Leafra is a Next.js application that provides a Retrieval-Augmented Generation (RAG) system for PDF documents. Users can upload PDFs, ask questions about them, and receive AI-powered responses based on the document content.
- π PDF Upload and Processing
- π€ AI-Powered Chat Interface
- π Vector Search using Pinecone
- π Authentication (Email/Password + OAuth)
- π Real-time Chat Streaming
- ποΈ PostgreSQL Database
- β‘ Background Job Processing with BullMQ
- Framework: Next.js 15 (App Router)
- Database: PostgreSQL with Drizzle ORM
- Vector Database: Pinecone
- AI/ML: TogetherAI (Embeddings & Chat)
- Queue: BullMQ with Redis (Upstash)
- File Upload: UploadThing
- Authentication: Better-auth
- UI: React, Tailwind CSS, shadcn/ui
- Authentication Flow: User signs up/in β Better-auth β Session management
- Chat Creation: User creates chat β Stored in DB β Chat page loads
- PDF Upload: UploadThing β BullMQ queue β Worker processes β Pinecone embeddings
- Chat Flow: User message β API route β Save to DB β Query Pinecone β Stream AI response β Save response
- Node.js 18+ or Bun
- PostgreSQL database
- Pinecone account
- TogetherAI account
- Upstash Redis account (optional but recommended)
- UploadThing account
- Clone the repository:
git clone <repository-url>
cd leafra- Install dependencies:
npm install
# or
bun install- Set up environment variables:
Create a
.env.localfile in the root directory with the following variables:
# Database
DATABASE_URL=postgresql://username:password@host:port/database
# Pinecone
PINECONE_API_KEY=your-pinecone-api-key
# TogetherAI
TOGETHER_AI_API_KEY=your-together-ai-api-key
TOGETHER_AI_MODEL=your-model-name
# Redis (Upstash) - Optional
UPSTASH_REDIS_REST_URL=https://your-redis-instance.upstash.io
UPSTASH_REDIS_REST_TOKEN=your-redis-token
# OAuth Providers (Optional)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
DISCORD_CLIENT_ID=your-discord-client-id
DISCORD_CLIENT_SECRET=your-discord-client-secret
# Next.js
NEXT_PUBLIC_BASE_URL=http://localhost:3000
NODE_ENV=development- Set up the database:
# Run migrations
npm run db:push
# or with drizzle-kit
npx drizzle-kit push- Start the development server:
npm run dev
# or
bun dev- Start the worker (in a separate terminal):
# Compile worker
tsc --watch ./lib/worker.ts
# Run worker (in another terminal)
bunx nodemon ./lib/worker.js
# or
bun run ./lib/worker.jsOpen http://localhost:3000 in your browser.
leafra/
βββ app/ # Next.js App Router
β βββ api/ # API routes
β β βββ auth/ # Authentication endpoints
β β βββ chat/ # Chat API
β β βββ messages/ # Messages API
β β βββ uploadthing/ # File upload
β βββ actions/ # Server actions
β βββ chat/ # Chat pages
β βββ dashboard/ # Dashboard page
β βββ layout.tsx # Root layout
βββ components/ # React components
β βββ custom/ # Custom components
β βββ ui/ # shadcn/ui components
β βββ shared/ # Shared components
βββ lib/ # Utility libraries
β βββ auth.ts # Authentication config
β βββ db.ts # Database connection
β βββ db/
β β βββ schema.ts # Database schema
β βββ env.ts # Environment validation
β βββ logger.ts # Logging utility
β βββ api-response.ts # API response helpers
β βββ integrations/ # Third-party integrations
β β βββ pinecone.ts # Pinecone client
β β βββ redis.ts # Redis client
β βββ worker.ts # Background worker
βββ types/ # TypeScript types
βββ middleware.ts # Next.js middleware
All API routes (except /api/auth/*) require authentication via session cookie.
Send a message to the chat and get an AI response.
Request Body:
{
"messages": [
{
"role": "user",
"content": "What is this document about?"
}
],
"chatId": "uuid-string"
}Response: Streaming text response
Get all messages for a chat.
Query Parameters:
chatId(required): UUID of the chat
Response:
[
{
"id": 1,
"chatId": "uuid",
"content": "Message content",
"role": "user",
"createdAt": "2024-01-01T00:00:00Z"
}
]npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLintnpm run typecheck- Run TypeScript type checkingnpm run dev:worker- Watch and run worker
- TypeScript for type safety
- ESLint for code linting
- Zod for runtime validation
- Structured logging
- Standardized error responses
Ensure all required environment variables are set in your production environment. See the .env.example file for reference.
Run database migrations before deploying:
npx drizzle-kit pushThe worker process must be running separately in production. Consider using:
- PM2
- Docker containers
- Cloud functions
- Kubernetes jobs
- Vercel - For Next.js hosting
- Railway - For PostgreSQL and worker
- Upstash - For Redis
- Pinecone - For vector database
- All API routes are authenticated
- Environment variables are validated at startup
- Input validation using Zod
- SQL injection protection via Drizzle ORM
- Session-based authentication
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linting
- Submit a pull request
[Add your license here]
For issues and questions, please open an issue on GitHub.