Overview
Technology Stack
| Component | Technology | Purpose |
|---|---|---|
| Database | PostgreSQL 15 | Relational database |
| Hosting | Neon Serverless | Auto-scaling PostgreSQL |
| ORM | Drizzle ORM | Type-safe query builder |
| Migrations | Drizzle Kit | Schema migration tool |
| Admin UI | Drizzle Studio | Visual database browser |
Key Features
Type Safety- Schema defined in TypeScript (
lib/db/schema.ts) - Types automatically inferred for queries
- Compile-time type checking
db:pushfor instant local schema updatesdb:studiofor visual database browsing- Auto-generated migrations for production
- Single source of truth (schema.ts)
- Automatic type generation
- Zero runtime overhead
Database Structure
CharleOS has 47 tables organized into functional groups:Core Entities
Users, Clients, Tasks, Quotes, Projects
Scheduling
Subtasks, Blocks, Schedule, Capacity
Billing & Time
Time Entries, Plans, Metrics, Efficiency
Auxiliary
Help Desk, Leave, Notifications, Activity Log
Common Workflows
Local Development
1
Update Schema
Modify
lib/db/schema.ts to add/change tables or columns2
Push to Database
3
Verify Changes
Production Deployment
1
Generate Migration
drizzle/ directory2
Review Migration
Check the generated SQL in
drizzle/XXXX_name.sql to ensure it’s correct3
Commit & Deploy
Commit the migration file and schema changes. Migrations run automatically on deployment.
Available Commands
| Command | Purpose | When to Use |
|---|---|---|
npm run db:push | Push schema changes to database | Local development |
npm run db:generate | Generate migration file | Before deploying to production |
npm run db:studio | Open Drizzle Studio | Browse/edit data visually |
npm run db:seed | Seed development data | Fresh local setup |
npm run db:sync | Sync migrations to Neon | After adding migration files |
Querying the Database
CharleOS uses Drizzle ORM for all database queries. Here’s a quick example:Basic Query
Joins and Relations
Drizzle provides full TypeScript types for all queries. If you try to query a column that doesn’t exist, you’ll get a compile error.
Database Configuration
Connection
The database connection is configured via theDATABASE_URL environment variable:
- Uses DEV branch on Neon (safe to experiment)
- Configured in
.env.local
- Uses main branch on Neon
- Configured via Vercel environment variables
Connection Pooling
Drizzle uses@neondatabase/serverless with connection pooling:
- Efficient connection reuse
- Auto-scaling with Neon
- Fast query execution
Schema Organization
The schema is organized into logical sections inlib/db/schema.ts:
Type Safety
One of the biggest advantages of Drizzle is automatic type inference:Auto-Generated Types
Query Type Safety
Database Tools
Drizzle Studio
Visual database browser built into the development workflow:- Browse all tables
- Filter and search data
- Edit records directly
- View relationships
- Run custom queries
https://local.drizzle.studio (secure local HTTPS)
Neon Console
The Neon dashboard provides:- Database branching (dev/staging/prod)
- Query history and analytics
- Connection pooling stats
- Backups and point-in-time restore
Best Practices
Always Use the ORM
Always Use the ORM
Never write raw SQL queries. Use Drizzle’s query builder:
Use Transactions for Multi-Step Operations
Use Transactions for Multi-Step Operations
When multiple database operations must succeed or fail together:
Test Schema Changes Locally First
Test Schema Changes Locally First
Always test schema changes with
db:push locally before generating migrations:- Update schema in
lib/db/schema.ts - Run
npm run db:pushto test locally - Fix any issues
- Run
npm run db:generateto create migration - Commit and deploy
Keep Services Separate from Routes
Keep Services Separate from Routes
Database queries should live in
lib/services/, not in API routes:Common Patterns
Pagination
Filtering
Aggregation
Troubleshooting
Connection Issues
Error: “Connection refused” or “SSL required” Fix:- Check
DATABASE_URLin.env.local - Ensure Neon database is active (not auto-paused)
- Verify SSL mode is enabled:
?sslmode=require
Migration Conflicts
Error: “Migration X not found” or “Migration conflict” Fix:Type Errors
Error: “Property ‘xyz’ does not exist on type…” Fix:- Restart TypeScript server in your IDE
- Schema types are auto-generated - if you just changed the schema, wait a moment for TS to catch up
- Run
npm run type-checkto see all type errors