Skip to main content
CharleOS uses PostgreSQL (hosted on Neon) with Drizzle ORM for type-safe database access. All schema is defined in code, and migrations are generated automatically.

Overview

Technology Stack

Key Features

Type Safety
  • Schema defined in TypeScript (lib/db/schema.ts)
  • Types automatically inferred for queries
  • Compile-time type checking
Developer Experience
  • db:push for instant local schema updates
  • db:studio for visual database browsing
  • Auto-generated migrations for production
Architecture
  • 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
See the Schema page for detailed table documentation.

Common Workflows

Local Development

1

Update Schema

Modify lib/db/schema.ts to add/change tables or columns
2

Push to Database

Instantly applies changes to your local dev database
3

Verify Changes

Open Drizzle Studio to browse your updated schema

Production Deployment

1

Generate Migration

Creates SQL migration file in drizzle/ directory
2

Review Migration

Check the generated SQL in drizzle/XXXX_name.sql to ensure it’s correct
3

Commit & Deploy

Commit the migration file and schema changes. Migrations run automatically on deployment.

Available Commands

Local vs Production:
  • Use db:push for local dev (fast, no migration files)
  • Use db:generate for production (creates migration files for deployment)

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 the DATABASE_URL environment variable:
Local development:
  • Uses DEV branch on Neon (safe to experiment)
  • Configured in .env.local
Production:
  • Uses main branch on Neon
  • Configured via Vercel environment variables

Connection Pooling

Drizzle uses @neondatabase/serverless with connection pooling:
Benefits:
  • Efficient connection reuse
  • Auto-scaling with Neon
  • Fast query execution

Schema Organization

The schema is organized into logical sections in lib/db/schema.ts:
This organization makes it easy to find and understand related tables.

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:
Features:
  • Browse all tables
  • Filter and search data
  • Edit records directly
  • View relationships
  • Run custom queries
Access: Opens at 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
Access: console.neon.tech

Best Practices

Never write raw SQL queries. Use Drizzle’s query builder:
When multiple database operations must succeed or fail together:
Always test schema changes with db:push locally before generating migrations:
  1. Update schema in lib/db/schema.ts
  2. Run npm run db:push to test locally
  3. Fix any issues
  4. Run npm run db:generate to create migration
  5. Commit and deploy
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:
  1. Check DATABASE_URL in .env.local
  2. Ensure Neon database is active (not auto-paused)
  3. 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-check to see all type errors

Schema

Complete database schema reference

Drizzle ORM

Query builder syntax and patterns

Migrations

Managing schema changes over time

Project Structure

Where database code lives