A privacy-focused AI chatbot running entirely on your local machine with Ollama models, PostgreSQL, and Redis.
Features · Tech Stack · Running Locally · Configuration
- 100% Local & Private - All AI processing happens on your machine via Ollama
- Modern UI - Built with Next.js 15, React 19, and shadcn/ui components
- Real-time Chat - Streaming responses with the AI SDK
- Code Artifacts - Generate and edit code with syntax highlighting
- Document Editing - Create and modify documents with rich text editing
- Chat History - Persistent conversations stored in PostgreSQL
- Authentication - Secure user sessions with Auth.js
- Credit System - Usage-based credit management with subscription plans
- File Uploads - Local file storage for images and attachments
- Resumable Streams - Continue interrupted conversations with Redis
- Frontend: Next.js 15 (App Router), React 19, TailwindCSS, shadcn/ui
- AI: Ollama (Qwen 2.5 14B models), AI SDK
- Database: PostgreSQL (Docker), Drizzle ORM
- Cache: Redis (Docker)
- Auth: Auth.js (NextAuth v5)
- Code Quality: Ultracite (Biome), TypeScript
This application uses local Ollama models:
- qwen2.5:14b - Main chat model for conversations and reasoning
- qwen2.5-coder:14b - Specialized model for code generation and artifacts
You can easily swap these models by editing lib/ai/providers.ts to use any Ollama model you have installed.
- Docker Desktop - Download here
- Ollama - Download here
- Node.js 18+ and pnpm
- Clone the repository:
git clone <your-repo-url>
cd chatbotnext- Start Docker services:
docker compose up -dThis starts PostgreSQL and Redis containers.
- Install Ollama models:
ollama pull qwen2.5:14b
ollama pull qwen2.5-coder:14bVerify models are installed:
ollama list- Install dependencies:
pnpm install- Run database migrations:
pnpm db:migrate- Start the development server:
pnpm devThe app will be available at http://localhost:3000
Stop Docker containers:
docker compose downTo remove all data:
docker compose down -vEnvironment variables in .env.local:
# Session encryption (change in production)
AUTH_SECRET=your-secret-key-here
# Ollama API endpoint
OLLAMA_BASE_URL=http://localhost:11434
# PostgreSQL connection
POSTGRES_URL=postgresql://chatbot:chatbot_dev_password@localhost:5432/chatbot
# Redis connection
REDIS_URL=redis://localhost:6379pnpm dev- Start development server with Turbopnpm build- Build for productionpnpm start- Start production serverpnpm lint- Check code with Ultracitepnpm format- Format code with Ultracitepnpm db:migrate- Run database migrationspnpm db:studio- Open Drizzle Studio (database GUI)pnpm db:seed- Seed subscription planspnpm test- Run Playwright tests
The application includes a comprehensive credit-based usage system that tracks and manages user consumption.
Credits are consumed based on the length of AI-generated responses:
Credit Calculation Formula: credits = (character_count / 20) rounded to 2 decimal places
Example:
- A 100-character response costs 5.00 credits
- A 500-character response costs 25.00 credits
- A 1000-character response costs 50.00 credits
- Initial Credits: 200 credits upon first visit
- Persistence: Credits persist during browser session
- Limitations: Cannot purchase additional credits (must register)
- Exhaustion: Redirected to login page when credits run out
- Welcome Bonus: 1000 credits upon registration
- One-time: Bonus is only granted once per account
- Immediate: Credits available immediately after registration
- Monthly Allowance: 200 credits automatically added each month
- Automatic: No action required, processed by cron job
- Additive: Monthly credits add to existing balance
- Purchase: Can buy additional credits via subscription plans
Three subscription tiers are available for purchasing credits:
| Plan | Credits | Price | Best For |
|---|---|---|---|
| Starter | 500 | $5.00 | Light usage, occasional conversations |
| Pro | 2000 | $15.00 | Regular usage, daily conversations |
| Premium | 5000 | $30.00 | Heavy usage, extensive conversations |
Note: This is a mock payment system for demonstration purposes.
- Navigation Bar: Current balance displayed in the header
- Account Profile: Detailed balance and transaction history at
/profile - Real-time Updates: Balance updates immediately after each message
- Each AI response shows the exact credits consumed
- Credit meter updates in real-time during conversations
- Low balance warning appears when credits drop below 50
- Navigate to
/payments(authenticated users only) - Select a subscription plan
- Confirm purchase in the modal
- Credits are added immediately to your account
View complete credit history in your account profile:
- Credit deductions (message generation)
- Credit additions (purchases, bonuses, monthly allowances)
- Timestamps and descriptions for all transactions
- Current balance after each transaction
GET /api/credits/balance
- Returns current credit balance
- Authentication: Optional (returns guest balance if unauthenticated)
- Response:
{ balance: number, lastMonthlyAllocation: string | null }
POST /api/credits/deduct
- Deducts credits after message generation
- Authentication: Required
- Body:
{ amount: number, description: string, metadata?: object } - Response:
{ success: boolean, newBalance: number, transaction: CreditTransaction }
GET /api/credits/transactions
- Returns credit transaction history
- Authentication: Required
- Query params:
limit(default: 50),offset(default: 0) - Response:
{ transactions: CreditTransaction[], total: number }
GET /api/payments/plans
- Returns available subscription plans
- Authentication: Not required
- Response:
{ plans: SubscriptionPlan[] }
POST /api/payments/purchase
- Processes a plan purchase (mock payment)
- Authentication: Required
- Body:
{ planId: string } - Response:
{ success: boolean, purchase: UserPurchase, newBalance: number }
GET /api/payments/history
- Returns purchase history
- Authentication: Required
- Query params:
limit(default: 50),offset(default: 0) - Response:
{ purchases: UserPurchase[], total: number }
GET /api/user/profile
- Returns user profile with credit information
- Authentication: Required
- Response:
{ user: User, creditBalance: CreditBalance, activePlan: SubscriptionPlan | null }
The credit system uses the following tables:
Stores user credit balances and allocation tracking:
userId(UUID, primary key)balance(Decimal, 2 decimal places)lastMonthlyAllocation(Timestamp, nullable)isNewUser(Boolean)createdAt,updatedAt(Timestamps)
Records all credit operations:
id(UUID, primary key)userId(UUID, foreign key)type(Enum: deduction, purchase, bonus, monthly_allowance)amount(Decimal, 2 decimal places)balanceAfter(Decimal, 2 decimal places)description(Text)metadata(JSONB, optional)createdAt(Timestamp)
Defines available credit packages:
id(UUID, primary key)name(String)credits(Decimal, 2 decimal places)price(Decimal, 2 decimal places)description(Text)isActive(Boolean)displayOrder(Integer)createdAt(Timestamp)
Tracks user purchases:
id(UUID, primary key)userId(UUID, foreign key)planId(UUID, foreign key)creditsAdded(Decimal, 2 decimal places)amountPaid(Decimal, 2 decimal places)status(Enum: completed, pending, failed)createdAt(Timestamp)
Manages guest user sessions:
sessionId(String, primary key)balance(Decimal, 2 decimal places)createdAt(Timestamp)expiresAt(Timestamp)
- Schedule: Daily at midnight UTC
- Function: Checks all authenticated users for monthly allocation eligibility
- Process: Adds 200 credits to users who haven't received allocation in current month
- Configuration: See
lib/cron/monthly-allocation.ts - Deployment: Configure via Vercel Cron or similar service
- Row-level locking: Prevents race conditions during concurrent credit operations
- Database transactions: Ensures atomic credit operations
- Authentication enforcement: All credit endpoints require valid sessions
- Input validation: Zod schemas validate all API requests
- Rate limiting: Prevents abuse of API endpoints
- Audit logging: All credit operations are logged for monitoring
- Database indexes: Optimized queries on userId and createdAt fields
- Redis caching: Subscription plans cached with 24-hour TTL
- Balance caching: User balances cached with 60-second TTL
- Connection pooling: Efficient database connection management
- Pagination: Transaction and purchase history support pagination
Check if Ollama is running:
curl http://localhost:11434/api/tagsCheck PostgreSQL logs:
docker compose logs postgresCheck Redis logs:
docker compose logs redisMIT