document-chat-system
CLAUDE.md149 starsChanged 27 days agoMITView on GitHub
Document Chat System is a production-ready Next.js 15 application that combines intelligent document management with AI-powered conversations. It's a multi-tenant SaaS platform supporting multiple AI providers (OpenRouter, OpenAI, Anthropic), background job processing with Inngest, and vector search via Pinecone/pgvector.
- Reads credentials
- Deletes or force-pushes
- Installs packages
We split this CLAUDE.md into the rules it gives an agent
60 rules. About 0 are common, 38 are distinctive, and 22 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈38
Distinctive · estimate
This author's own choices. Worth a look.
22
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 7
Document Chat System is a production-ready Next.js 15 application that combines intelligent document management with AI-powered …
- Very specific: line 154
Every database query MUST filter by organizationId
- Very specific: line 166
All providers implement the same interface from src/lib/ai/interfaces/base-adapter.ts.
- Distinctive: line 221
When creating new Inngest functions, follow this pattern:
- Distinctive: line 247
When adding new models, update the model registry first.
- Very specific: line 264
Use the shared test utilities in src/lib/ai/__tests__/shared/
- Distinctive: line 266
Test error handling and edge cases
- Very specific: line 272
Create adapter in src/lib/ai/providers/my-provider-adapter.ts
- Very specific: line 274
Add provider to factory in providers/factory.ts
- Distinctive: line 275
Update model registry with new models
- Very specific: line 276
Add provider key to .env.example
- Very specific: line 280
Create function file in src/lib/inngest/functions/
- Distinctive: line 283
Add event trigger in appropriate API route
- Very specific: line 284
Test locally with npx inngest-cli dev
- Distinctive: line 285
Verify function appears in Inngest dashboard after deploy
- Very specific: line 288
Create route in src/app/api/v1/[endpoint]/route.ts
- Very specific: line 290
Check authentication with auth() from Clerk
- Distinctive: line 292
Add error handling with custom error classes
- Distinctive: line 293
Document endpoint in API docs
- Very specific: line 297
Run npm run db:push for development
- Very specific: line 298
Run npm run db:migrate to create migration
- Distinctive: line 299
Update TypeScript types if needed
- Distinctive: line 300
Update seed script if adding required fields
- Very specific: line 301
Test with fresh database: npm run dev:reset
- Distinctive: line 306
After deploying to production:
- Distinctive: line 309
Verify all 7 functions appear (process-document-basic, vectorize-document, etc.)
- Distinctive: line 310
Test by uploading a document and checking Inngest Dashboard → Runs
- Distinctive: line 315
Use the automated Vercel deployment script:
- Very specific: line 322
Always use migrations in production (not db:push):
- Distinctive: line 339
Check Inngest Dashboard for failed jobs
- Very specific: line 340
Verify INNGEST_EVENT_KEY and INNGEST_SIGNING_KEY are set
- Distinctive: line 342
Check application logs for errors
- Distinctive: line 343
Verify Supabase storage permissions
- Distinctive: line 346
Check provider API keys are valid
- Distinctive: line 347
Verify provider has available credits
- Distinctive: line 348
Check circuit breaker status in logs
- Distinctive: line 353
Verify Pinecone index exists with correct dimensions (1536 for OpenAI)
- Very specific: line 354
Check namespace format: org_{organizationId}
- Distinctive: line 357
Check vector search timeout settings
- Distinctive: line 376
Use TypeScript strict mode (already configured)
- Very specific: line 377
Follow ESLint rules: npm run lint
- Very specific: line 378
Use @/ imports for absolute paths (configured in tsconfig.json)
- Distinctive: line 379
Prefer async/await over promises
- Distinctive: line 380
Use Zod for runtime validation
- Distinctive: line 381
Add JSDoc comments for complex functions
- Very specific: line 382
Keep API routes thin, logic in src/lib/
- Distinctive: line 398
Wait for explicit user approval
- Distinctive: line 401
Exception: Only commit/push without asking if the user explicitly instructs you to do so
- Distinctive: line 409
When creating git commits:
- Very specific: line 417
Read applicable CLAUDE.md, gemini.md/GEMINI.md, and codex.md/CODEX.md guidance before drafting each commit
- Distinctive: line 419
Follow conventional commit format when appropriate
- Distinctive: line 421
Use a concise subject and a detailed, professional body that helps the next developer understand the change
- Distinctive: line 440
NEVER commit API keys or secrets
- Distinctive: line 441
ALWAYS validate input with Zod schemas
- Distinctive: line 442
ALWAYS filter by organizationId in multi-tenant queries
- Very specific: line 443
Use Clerk's auth() for authentication, not custom JWT
- Distinctive: line 447
Use Redis caching for expensive operations
- Distinctive: line 450
Use streaming for AI responses
- Distinctive: line 456
Use circuit breakers for external API calls
- Distinctive: line 470
Every database query must include organizationId:
≈ “Common” is an estimate: at least 1 in 5 of the 25,680 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Document Chat System is a production-ready Next.js 15 application that combines intelligent document management with AI-powered conversations. It's a multi-tenant SaaS platform supporting multiple AI providers (OpenRouter, OpenAI, Anthropic), background job processing with Inngest, and vector search via Pinecone/pgvector.
Development Commands
Essential Commands
# Development
npm run dev # Start dev server (localhost:3000)
npm run build # Production build (runs prisma generate first)
npm run start # Start production server
npm run lint # Run ESLint
npm run type-check # TypeScript type checking
# Database (Prisma)
npm run db:generate # Generate Prisma client
npm run db:push # Push schema changes to database
npm run db:migrate # Create and run migration
npm run db:studio # Open Prisma Studio GUI
npm run db:seed # Seed database with initial data
npm run db:reset # ⚠️ Reset database (deletes all data)
# Combined Development
npm run dev:setup # npm install + prisma generate + db push
npm run dev:reset # db reset + db seed + dev serverRunning Tests
npm test # Run Jest tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage reportBackground Jobs (Inngest)
npx inngest-cli dev # Start Inngest dev server at localhost:8288Architecture Overview
Technology Stack
- Frontend: Next.js 15 (App Router), React 19, TypeScript 5, Tailwind CSS, shadcn/ui, Zustand
- Backend: Next.js API Routes, Prisma ORM, PostgreSQL 14+
- AI: OpenRouter (100+ models), OpenAI, Anthropic via Vercel AI SDK
- Auth: Clerk (multi-tenant with organizations)
- Storage: Supabase (files) + PostgreSQL (metadata)
- Background Jobs: Inngest (document processing pipeline)
- Vector Search: Pinecone or pgvector
- Cache: Upstash Redis (optional)
- Billing: Stripe (optional)
Directory Structure Deep Dive
src/
├── app/ # Next.js 15 App Router
│ ├── api/ # API routes
│ │ ├── inngest/ # Inngest webhook endpoint
│ │ └── v1/ # Versioned REST APIs
│ ├── [page-routes]/ # Page routes (dashboard, chat, documents, etc.)
│ ├── layout.tsx # Root layout with providers
│ └── middleware.ts # Auth, CORS, rate limiting
│
├── lib/ # Core business logic
│ ├── ai/ # AI service layer (CRITICAL)
│ │ ├── providers/ # AI provider adapters
│ │ │ ├── openai-adapter.ts
│ │ │ ├── anthropic-adapter.ts
│ │ │ ├── smart-openrouter-adapter.ts # Main OpenRouter implementation
│ │ │ └── factory.ts # Provider factory pattern
│ │ ├── services/ # AI processing services
│ │ │ ├── embedding-service.ts # Generate embeddings
│ │ │ ├── vector-search.ts # Semantic search
│ │ │ ├── document-chunker.ts # Split documents into chunks
│ │ │ ├── hybrid-search.ts # Combine vector + keyword search
│ │ │ └── document-*-analyzer.ts # Document analysis services
│ │ ├── routing/ # Intelligent request routing
│ │ ├── monitoring/ # Metrics, cost tracking, alerts
│ │ ├── config/ # AI configuration, feature flags, model registry
│ │ ├── prompts/ # Prompt templates and library
│ │ └── ai-service-manager.ts # Main AI orchestration layer
│ │
│ ├── inngest/ # Background job processing
│ │ ├── client.ts # Inngest client configuration
│ │ └── functions/ # Job definitions
│ │ ├── process-document-basic.ts # Text extraction + sections
│ │ ├── process-document-full.ts # Complete analysis
│ │ ├── vectorize-document.ts # Generate embeddings
│ │ ├── analyze-document.ts # AI-powered analysis
│ │ └── batch-process-documents.ts # Batch processing
│ │
│ ├── documents/ # Document management logic
│ ├── file-processing/ # File type handlers (PDF, DOCX, images, etc.)
│ ├── auth/ # Clerk authentication utilities
│ ├── storage/ # Supabase file storage
│ ├── db/ # Prisma utilities and helpers
│ ├── cache/ # Redis caching layer
│ ├── errors/ # Custom error classes and handling
│ ├── audit/ # Audit logging system
│ └── validation/ # Zod schemas for input validation
│
├── components/ # React components
│ ├── ui/ # shadcn/ui primitives
│ ├── documents/ # Document management UI
│ ├── chat/ # AI chat interface
│ ├── billing/ # Stripe billing UI
│ └── layout/ # App layout components
│
├── stores/ # Zustand state management
├── hooks/ # Custom React hooks
├── contexts/ # React Context providers
└── types/ # TypeScript type definitionsData Flow Patterns
Document Upload & Processing Flow
1. User uploads file → API Route (/api/v1/documents/upload)
2. File stored in Supabase Storage
3. Document record created in PostgreSQL (status: PENDING)
4. Inngest event triggered: "document/process-basic.requested"
5. Background job processes document:
a. Extract text (process-document-basic)
b. Chunk content (document-chunker)
c. Generate embeddings (vectorize-document)
d. Store vectors in Pinecone/pgvector
e. Analyze content (analyze-document)
6. Update document status to COMPLETED
7. UI polls for updates or receives real-time notificationAI Chat Flow
1. User sends message → /api/v1/ai/chat
2. Retrieve relevant document chunks via vector search
3. Build context from chunks + chat history
4. Route request through ai-service-manager
5. ai-service-manager selects provider (OpenRouter/OpenAI/Anthropic)
6. Stream response tokens back to client
7. Save message to database with citations
8. Track metrics (cost, latency, tokens)Key Architectural Patterns
Multi-Tenant Isolation
- Every database query MUST filter by
organizationId - Clerk provides organization context via
auth() - Row-level security enforced at API layer
- Separate Pinecone namespaces per organization
AI Provider Abstraction
The system uses a provider adapter pattern in src/lib/ai/providers/:
factory.ts- Creates appropriate provider based on configsmart-openrouter-adapter.ts- Main OpenRouter implementation with smart routingopenai-adapter.ts- Direct OpenAI integrationanthropic-adapter.ts- Direct Anthropic integration
All providers implement the same interface from src/lib/ai/interfaces/base-adapter.ts.
Background Job Processing (Inngest)
Critical: Document processing happens asynchronously!
- Events defined in
src/lib/inngest/functions/ - Jobs are retryable with exponential backoff
- Concurrency limits prevent resource exhaustion
- Status tracked in
document.processingJSONB field
Caching Strategy
Three-tier caching:
- Redis (Upstash) - Distributed cache for API responses
- Memory Cache - In-process cache for frequently accessed data
- Browser Cache - Client-side caching via React Query
Error Handling
Centralized error system in src/lib/errors/:
- Custom error classes with proper inheritance
- Circuit breaker pattern for external services
- Automatic retry logic with exponential backoff
- Structured error logging for debugging
Critical Implementation Details
Environment Variables
Required for development:
DATABASE_URL- PostgreSQL connection stringNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY+CLERK_SECRET_KEY- AuthNEXT_PUBLIC_SUPABASE_URL+NEXT_PUBLIC_SUPABASE_ANON_KEY- StorageINNGEST_EVENT_KEY+INNGEST_SIGNING_KEY- Background jobs- At least one AI provider key (OPENROUTER_API_KEY recommended)
Important configuration:
OPENROUTER_SMART_ROUTING=true- Enable intelligent model routingOPENROUTER_COST_OPTIMIZATION="balanced"- Cost vs quality tradeoffAI_ENABLE_FALLBACK=true- Automatic provider fallbackAI_ENABLE_CIRCUIT_BREAKER=true- Circuit breaker protection
Database Schema (Prisma)
Located in prisma/schema.prisma:
- Organization - Multi-tenant root entity
- User - Maps to Clerk users via
clerkId - Document - Uploaded files with processing metadata
- Folder - Hierarchical organization
- Subscription - Stripe billing integration
- AIMetric - AI usage tracking
- AuditLog - Complete audit trail
After schema changes:
npm run db:push # Push to dev database
npm run db:migrate # Create migration for productionInngest Function Naming
When creating new Inngest functions, follow this pattern:
export const myFunction = inngest.createFunction(
{
id: "my-function", // Must match function name in dashboard
name: "My Function", // Human-readable display name
retries: 3, // Number of automatic retries
concurrency: { limit: 5 }, // Max concurrent executions
},
{ event: "my-domain/my-event.requested" }, // Event trigger
async ({ event, step }) => {
// Use step.run() for retry boundaries
const result = await step.run("step-name", async () => {
// Your logic here
});
}
);AI Provider Configuration
The AI layer in src/lib/ai/ is highly configurable:
- Model Registry (
config/model-registry.ts) - Centralized model definitions - Feature Flags (
config/feature-flags.ts) - Enable/disable features - Routing (
routing/request-router.ts) - Route requests to appropriate provider - Monitoring (
monitoring/) - Track costs, latency, errors
When adding new models, update the model registry first.
Vector Search Implementation
Two implementations available:
- Pinecone (
src/lib/ai/services/vector-search.ts)- Production-ready, managed service
- Separate namespaces per organization
- Index name configured via
PINECONE_INDEX_NAME
- pgvector (
src/lib/ai/services/pgvector-search.ts)- Uses PostgreSQL extension
- Good for development or single-tenant
- Enable with
ENABLE_PGVECTOR_FALLBACK=true
Testing Strategy
When writing tests:
- Unit tests in
src/lib/**/__tests__/ - Use the shared test utilities in
src/lib/ai/__tests__/shared/ - Mock external services (OpenRouter, Pinecone, etc.)
- Test error handling and edge cases
- Validate AI provider contracts with
contract-tests.ts
Common Development Tasks
Adding a New AI Provider
- Create adapter in
src/lib/ai/providers/my-provider-adapter.ts - Implement
BaseAIServiceAdapterinterface - Add provider to factory in
providers/factory.ts - Update model registry with new models
- Add provider key to
.env.example - Write contract tests
Adding a New Inngest Function
- Create function file in
src/lib/inngest/functions/ - Define event schema and handler
- Export from
src/lib/inngest/index.ts - Add event trigger in appropriate API route
- Test locally with
npx inngest-cli dev - Verify function appears in Inngest dashboard after deploy
Adding a New API Endpoint
- Create route in
src/app/api/v1/[endpoint]/route.ts - Validate input with Zod schema from
src/lib/validation/ - Check authentication with
auth()from Clerk - Filter by
organizationIdfor multi-tenant isolation - Add error handling with custom error classes
- Document endpoint in API docs
Modifying Database Schema
- Edit
prisma/schema.prisma - Run
npm run db:pushfor development - Run
npm run db:migrateto create migration - Update TypeScript types if needed
- Update seed script if adding required fields
- Test with fresh database:
npm run dev:reset
Production Deployment Notes
Inngest Configuration (CRITICAL)
After deploying to production:
- Go to Inngest Dashboard → Apps → Sync
- Enter your production URL:
https://your-domain.com/api/inngest - Verify all 7 functions appear (process-document-basic, vectorize-document, etc.)
- Test by uploading a document and checking Inngest Dashboard → Runs
Without this step, document processing will fail silently!
Environment Variables in Production
Use the automated Vercel deployment script:
./scripts/setup-vercel.sh --all # Sync all env vars to Vercel
vercel --prod # Deploy to productionDatabase Migrations
Always use migrations in production (not db:push):
npm run db:migrate # Create migration
vercel --prod # Deploy with new schemaMonitoring Production
Key dashboards to monitor:
- Inngest Dashboard (app.inngest.com) - Background job status
- Clerk Dashboard - Authentication metrics
- Supabase Dashboard - Database and storage usage
- Vercel Analytics - Performance and errors
- Stripe Dashboard - Billing (if enabled)
Troubleshooting
Documents Not Processing
- Check Inngest Dashboard for failed jobs
- Verify
INNGEST_EVENT_KEYandINNGEST_SIGNING_KEYare set - Confirm functions are synced in Inngest Dashboard
- Check application logs for errors
- Verify Supabase storage permissions
AI Responses Failing
- Check provider API keys are valid
- Verify provider has available credits
- Check circuit breaker status in logs
- Try fallback provider if enabled
- Review AI metrics in database
Vector Search Not Working
- Verify Pinecone index exists with correct dimensions (1536 for OpenAI)
- Check namespace format:
org_{organizationId} - Confirm embeddings were generated (check
document.processing.embeddingGenerated) - Try pgvector fallback if enabled
- Check vector search timeout settings
Build Failures
# Clean build
rm -rf .next node_modules package-lock.json
npm install
npx prisma generate
npm run buildType Errors
npm run type-check # Identify type errors
npx prisma generate # Regenerate Prisma typesCode Style Guidelines
- Use TypeScript strict mode (already configured)
- Follow ESLint rules:
npm run lint - Use
@/imports for absolute paths (configured in tsconfig.json) - Prefer async/await over promises
- Use Zod for runtime validation
- Add JSDoc comments for complex functions
- Keep API routes thin, logic in
src/lib/
Git Commit Guidelines
CRITICAL: This is a PUBLIC open-source repository - ALWAYS ask before committing/pushing
Before Committing or Pushing:
- ALWAYS ask the user for permission before:
- Creating any git commits
- Pushing any commits to GitHub
- Making any changes to the git repository
- When asking for permission:
- Clearly list what files will be committed
- Explain what changes were made
- Wait for explicit user approval
- Example: "I've made the following changes: [list changes]. Should I commit and push these to GitHub?"
- Exception: Only commit/push without asking if the user explicitly instructs you to do so
- Example user request: "commit these changes and push to github"
- Example user request: "push this to the repo"
Commit Message Guidelines:
IMPORTANT: Do NOT add Claude Code or Anthropic attribution to git commits
When creating git commits:
- Never include:
- "🤖 Generated with Claude Code"
- "Co-Authored-By: Claude noreply@anthropic.com"
- Any other Claude Code or Anthropic attribution
- Commit messages should:
- Read applicable
CLAUDE.md,gemini.md/GEMINI.md, andcodex.md/CODEX.mdguidance before drafting each commit - Be clear and descriptive
- Follow conventional commit format when appropriate
- Focus on what changed and why
- Use a concise subject and a detailed, professional body that helps the next developer understand the change
- Explain the problem, resulting behavior, significant implementation choices, and validation results
- Record known limitations, migration/configuration requirements, and follow-up work when relevant; distinguish passing checks from unresolved failures
- Read applicable
- Example of correct commit message:
Update Document Chat System branding and features - Remove unused sections from landing page - Add Vercel deployment automation - Fix mobile responsiveness issues - Update copyright year to 2025
This project is an open-source repository and commits should reflect the human developer's work without AI tool attribution in the commit history.
Important Constraints
Security
- NEVER commit API keys or secrets
- ALWAYS validate input with Zod schemas
- ALWAYS filter by organizationId in multi-tenant queries
- Use Clerk's
auth()for authentication, not custom JWT - Sanitize user input before rendering (use DOMPurify)
Performance
- Use Redis caching for expensive operations
- Implement pagination for large result sets (use
DEFAULT_PAGE_SIZE=25) - Optimize database queries with proper indexes
- Use streaming for AI responses
- Lazy load heavy components
AI Usage
- Track costs in
AIMetrictable - Respect usage limits from pricing plans
- Use circuit breakers for external API calls
- Implement rate limiting per organization
- Cache embeddings to avoid regeneration
Project-Specific Patterns
BYOK (Bring Your Own Key) Architecture
Users can provide their own AI API keys via Settings page:
- Keys encrypted with AES-256 before localStorage
- Keys sent to backend on each AI request
- Backend validates and uses user's key instead of system key
- Provides cost transparency and privacy
Multi-Tenant Data Access Pattern
Every database query must include organizationId:
const documents = await prisma.document.findMany({
where: {
organizationId: auth().orgId, // Always filter by org
userId: auth().userId, // Additional user filter if needed
},
});Document Processing State Machine
Documents progress through states:
- PENDING → PROCESSING → COMPLETED
- PENDING → PROCESSING → FAILED
- Track in
document.statusanddocument.processingJSONB
Error Recovery Strategy
- Circuit Breaker - Prevent cascading failures
- Automatic Retry - Exponential backoff with jitter
- Fallback Provider - Switch to backup AI provider
- Graceful Degradation - Return cached or partial results
Resources
- Main README: Comprehensive setup and deployment guide
- Prisma Schema:
prisma/schema.prisma- Complete database structure - AI Architecture:
src/lib/ai/README.md- AI routing and providers - Error Handling:
src/lib/errors/README.md- Error system documentation - File Processing:
src/lib/file-processing/README.md- File type handlers
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

