Development Guide¶
This guide provides detailed information for developers working on this project.
Prerequisites¶
- Node.js 20.x or higher
- npm 9.x or higher
- Git 2.x or higher
- Google Cloud Platform account with Vertex AI API enabled
Initial Setup¶
1. Clone and Install¶
2. Environment Configuration¶
Copy the example environment file:
Fill in the required values:
NextAuth Configuration¶
Generate a secret:
Set in .env.local:
User Credentials¶
Set the authorized user email:
Generate a password hash:
Copy the hash and set:
Google Cloud Vertex AI¶
- Create a Google Cloud project
- Enable Vertex AI API
- Set up application default credentials or service account
GOOGLE_PROJECT_ID=your-project-id
GOOGLE_LOCATION=us-central1
GOOGLE_VERTEX_AI_MODEL_ID=gemini-1.5-flash-002
Rate Limiting (In-Memory)¶
The application now uses in-memory rate limiting via rate-limiter-flexible. No additional configuration is needed!
- Rate Limit: 5 requests per 10 seconds per IP address
- Persistence: Rate limits reset when the server restarts
- Scaling: For production with multiple servers, consider migrating to Upstash Redis or another distributed store
No environment variables needed for rate limiting! 🎉
3. Google Cloud Authentication¶
For local development, authenticate with Google Cloud:
Or use a service account:
4. Gemini CLI Integration¶
The Gemini CLI provides a powerful command-line interface for interacting with Google's Gemini models directly from your terminal. This is useful for quick testing, prototyping prompts, and debugging AI responses.
Installation¶
Install the Gemini CLI globally via npm:
Or use it directly with npx (no installation required):
Setup and Authentication¶
The Gemini CLI uses the same authentication as your application. Ensure you're authenticated with Google Cloud:
# Application Default Credentials (recommended for development)
gcloud auth application-default login
# Verify authentication
gcloud auth application-default print-access-token
Set required environment variables:
Basic Usage¶
Test a simple prompt:
Use a specific model:
Multi-line prompts with stdin:
Save output to file:
Model Management¶
List available models:
Get model details:
Compare models:
# Test the same prompt on different models
for model in gemini-1.5-flash gemini-1.5-pro gemini-2.5-flash; do
echo "=== $model ==="
gemini --model $model "Summarize the concept of machine learning"
echo
done
Multimodal Queries (Text + Images)¶
Analyze an image:
Multiple images:
gemini \
--image screenshot1.png \
--image screenshot2.png \
"Compare these two screenshots and highlight the differences"
Image from URL:
Advanced Options¶
Set temperature (0.0 - 2.0):
Limit output tokens:
JSON output format:
Verbose mode (see API details):
Integration with This Workspace¶
Test chat prompts before implementing:
# Test a system prompt
gemini --system-instruction "You are a helpful coding assistant" \
"How do I use React hooks?"
# Test message formatting
gemini "User: How do I deploy to Cloud Run?
Assistant: I'll help you with that. First, ensure you have..."
Validate image inputs:
# Test image upload flow
gemini --image public/test-image.jpg \
"Describe this image in detail" \
--max-tokens 200
Prototype new features:
# Test code generation
gemini "Generate a TypeScript interface for a chat message with role, content, and timestamp fields"
# Test function calling
gemini --function-declarations functions.json \
"What's the weather in New York?"
Troubleshooting¶
Issue: Error: Could not load the default credentials
Solution:
# Re-authenticate
gcloud auth application-default login
# Or set explicit service account
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
Issue: Error: Permission denied
Solution:
# Enable Vertex AI API
gcloud services enable aiplatform.googleapis.com
# Verify IAM permissions
gcloud projects get-iam-policy $GOOGLE_PROJECT_ID \
--flatten="bindings[].members" \
--filter="bindings.members:user:$(gcloud config get-value account)"
Issue: Error: Model not found
Solution:
# List available models in your region
gemini models list --location us-central1
# Use exact model name from the list
gemini --model gemini-2.5-flash-001 "Your prompt here"
Issue: Error: Quota exceeded
Solution:
# Check quota usage
gcloud alpha services api-keys lookup-key \
--display-name "Vertex AI API" \
--location global
# Request quota increase in Cloud Console:
# https://console.cloud.google.com/iam-admin/quotas
Issue: Rate limit exceeded
Solution:
# Add delay between requests
for prompt in "prompt1" "prompt2" "prompt3"; do
gemini "$prompt"
sleep 2 # Wait 2 seconds between calls
done
Useful Aliases¶
Add these to your ~/.bashrc or ~/.zshrc:
# Quick Gemini access
alias gai='gemini --model gemini-2.5-flash'
# Gemini with verbose output
alias gaiv='gemini --model gemini-2.5-flash --verbose'
# Analyze images
alias gimg='gemini --model gemini-2.5-flash --image'
# Code review helper
alias greview='gemini --model gemini-1.5-pro --system-instruction "You are a code reviewer focusing on best practices and security"'
Usage with aliases:
gai "Quick question about React hooks"
gimg screenshot.png "What's wrong with this UI?"
greview < src/components/chat.tsx
Tips for Effective Prompting¶
- Be specific: Instead of "Explain React", use "Explain React hooks with 3 examples"
- Provide context: "As a Next.js 15 developer, how do I..."
- Request format: "List 5 bullet points..." or "Provide a JSON object..."
- Set constraints: "In 100 words or less..." or "Using only TypeScript..."
- Iterate: Test prompts in CLI before adding to application code
Documentation¶
Development Workflow¶
Running the Development Server¶
The application will be available at http://localhost:3000.
Code Quality Checks¶
# Run ESLint
npm run lint
# Fix ESLint errors automatically
npm run lint:fix
# Check formatting
npm run format:check
# Format code
npm run format
# Type checking
npm run type-check
Pre-commit Hooks¶
The project uses Husky for pre-commit hooks that automatically:
- Run ESLint with auto-fix
- Format code with Prettier
- Only for staged files
This ensures code quality before committing.
Architecture Principles¶
This project follows SOLID principles and Clean Code practices:
Single Responsibility Principle (SRP)¶
- Each module has one reason to change
- Components are focused and composable
- Services handle specific domains (e.g., ChatService for AI interactions)
Open/Closed Principle (OCP)¶
- Code is open for extension, closed for modification
- Use composition over inheritance
- Leverage TypeScript interfaces for contracts
Liskov Substitution Principle (LSP)¶
- Subtypes are substitutable for base types
- Error classes extend base AppError consistently
Interface Segregation Principle (ISP)¶
- Small, focused interfaces
- Components receive only props they need
Dependency Inversion Principle (DIP)¶
- Depend on abstractions, not concretions
- Services injected where needed
- Environment configuration centralized
Clean Code Practices¶
- Meaningful names: Variables, functions, and classes have descriptive names
- Small functions: Each function does one thing well
- Comments: Code is self-documenting; comments explain "why" not "what"
- Error handling: Proper error boundaries and user-friendly messages
- DRY: Don't Repeat Yourself - shared logic is extracted
- KISS: Keep It Simple, Stupid - avoid over-engineering
Common Tasks¶
Adding a New UI Component¶
Use shadcn/ui CLI:
Example:
Creating a New API Endpoint¶
- Create file in
src/app/api/<endpoint>/route.ts - Export named functions for HTTP methods (GET, POST, etc.)
- Add validation with Zod
- Add error handling
- Update API documentation in
docs/API.md
Example:
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
const schema = z.object({
// your validation schema
});
export async function POST(req: NextRequest) {
try {
const body = await req.json();
const parsed = schema.safeParse(body);
if (!parsed.success) {
return NextResponse.json({ error: "Invalid request" }, { status: 400 });
}
// Your logic here
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}
Adding a New Service¶
- Create file in
src/lib/services/<service-name>.ts - Export a class with clear methods
- Add JSDoc comments
- Handle errors with custom error classes
- Add logging for debugging
Example:
import { logger } from "@/lib/logger";
import { AppError } from "@/lib/errors";
export class MyService {
constructor() {
// Initialize
}
/**
* Does something useful
* @param input - The input parameter
* @returns The result
* @throws {AppError} When something goes wrong
*/
async doSomething(input: string): Promise<string> {
try {
// Your logic
return "result";
} catch (error) {
logger.error("Error in doSomething", { error, input });
throw new AppError("Failed to do something", 500);
}
}
}
Debugging¶
VS Code Launch Configuration¶
Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev"
},
{
"name": "Next.js: debug client-side",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000"
}
]
}
Logging¶
Use the logger utility for consistent logging:
import { logger } from "@/lib/logger";
logger.info("Something happened", { context: "value" });
logger.warn("Warning message", { context: "value" });
logger.error("Error occurred", { error, context: "value" });
logger.debug("Debug info", { context: "value" }); // Only in development
Troubleshooting¶
Build Errors¶
# Clear Next.js cache
rm -rf .next
# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install
# Type check
npm run type-check
Authentication Issues¶
- Verify environment variables are set correctly
- Regenerate NEXTAUTH_SECRET
- Check password hash matches
- Clear browser cookies
Vertex AI Errors¶
- Verify Google Cloud credentials
- Check project ID and location
- Ensure Vertex AI API is enabled
- Check API quotas
Rate Limiting Issues¶
In-Memory Rate Limiting: The app now uses rate-limiter-flexible with in-memory storage.
- Rate limits reset on server restart (expected behavior)
- Adjust limits in
src/middleware.ts(RATE_LIMIT_REQUESTS and RATE_LIMIT_WINDOW_SECONDS) - For production, consider upgrading to a distributed store (Redis, etc.)
- Check middleware logs for rate limit violations
Git Workflow¶
Commit Messages¶
Follow conventional commits:
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
Examples:
feat(chat): add image upload support
fix(auth): resolve login redirect issue
docs(api): update chat endpoint documentation
Branch Strategy¶
main: Production-ready codefeature/*: New featuresfix/*: Bug fixesdocs/*: Documentation updates
Performance Optimization¶
Bundle Analysis¶
Analyze bundle size:
Check the build output for bundle sizes.
Image Optimization¶
- Use Next.js Image component
- Use modern formats (WebP, AVIF)
- Provide appropriate sizes
Caching¶
- Static assets are cached automatically
- API responses include appropriate cache headers
- Redis used for rate limiting (in-memory caching)
Deployment¶
Vercel (Recommended)¶
- Push code to GitHub
- Import project in Vercel
- Set environment variables
- Deploy
Manual Deployment¶
Environment variables must be set on the server.
Contributing¶
See CONTRIBUTING.md for contribution guidelines.
Support¶
For issues and questions:
- Check existing documentation
- Review closed issues on GitHub
- Open a new issue with detailed information