Overview
Technology Stack
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
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
Related Documentation
Schema
Complete database schema reference
Drizzle ORM
Query builder syntax and patterns
Migrations
Managing schema changes over time
Project Structure
Where database code lives