Prerequisites
- Node.js 20+ and pnpm installed
- DelightBridge repository cloned locally
- Neon account (free tier available)
Step 1: Create Neon Database
Sign up for Neon
Go to neon.tech and create an account (GitHub login available).
Create a new project
Click New Project and configure:
- Project name:
delightbridge(or your preferred name) - Database name:
delightbridge - Region: Choose closest to your Vercel deployment region (e.g.,
US East (Ohio)forus-east-2)
Copy connection string
After project creation, Neon displays your connection string. Copy the Pooled connection string.It should look like:
Ensure the connection string ends with
?sslmode=require - this is required for Neon.Step 2: Push Database Schema
DelightBridge uses Drizzle Kit to push schema changes directly to your database without migrations.Install dependencies
Push schema to Neon
- Reads schema definitions from
src/lib/db/schema.ts - Connects to your Neon database using
DATABASE_URL - Creates all required tables and indexes
Verify tables created
You can verify tables were created using Neon’s SQL Editor or Drizzle Studio:https://local.drizzle.studio where you can browse your database.
Database Schema Overview
DelightBridge creates the following tables:Core Tables
gmail_accounts
Stores Gmail service accounts that DelightBridge manages.
| Column | Type | Description |
|---|---|---|
id | text | Primary key |
name | text | Service display name (e.g., “Noji Support”) |
email | text | Gmail address |
color | text | Brand color (hex) |
signature | text | HTML email signature |
document | text | Reference documentation for AI (Markdown) |
access_token | text | OAuth access token |
refresh_token | text | OAuth refresh token |
last_history_id | text | Gmail API history ID for incremental sync |
created_at | timestamp | Creation timestamp |
categories
Service-specific email categories for automatic labeling.
| Column | Type | Description |
|---|---|---|
id | text | Primary key |
account_id | text | Foreign key to gmail_accounts |
name | text | Category name |
color | text | Badge background color |
text_color | text | Badge text color |
email_threads
Email conversation threads from Gmail.
| Column | Type | Description |
|---|---|---|
id | text | Primary key |
account_id | text | Foreign key to gmail_accounts |
gmail_thread_id | text | Gmail thread ID |
subject | text | Email subject |
customer_email | text | Customer email address |
customer_name | text | Customer display name |
category_id | text | Foreign key to categories |
status | enum | inbox, sent, or archived |
detected_language | text | Detected language code |
is_read | boolean | Read status |
last_message_at | timestamp | Timestamp of most recent message |
created_at | timestamp | Creation timestamp |
emails
Individual messages within threads.
| Column | Type | Description |
|---|---|---|
id | text | Primary key |
thread_id | text | Foreign key to email_threads |
gmail_message_id | text | Gmail message ID |
from_email | text | Sender email |
from_name | text | Sender display name |
to_email | text | Recipient email |
body | text | HTML message body |
direction | enum | inbound or outbound |
sent_at | timestamp | Message timestamp |
created_at | timestamp | Creation timestamp |
drafts
AI-generated draft responses for threads.
| Column | Type | Description |
|---|---|---|
id | text | Primary key |
thread_id | text | Foreign key to email_threads (unique) |
subject | text | Draft subject line |
content | text | HTML draft content |
translation | text | Korean translation |
status | enum | pending, ready, sent, or skipped |
sent_at | timestamp | Sent timestamp (null if not sent) |
updated_at | timestamp | Last update timestamp |
User & Permission Tables
users
Authenticated users who can access DelightBridge.
| Column | Type | Description |
|---|---|---|
id | text | Primary key |
google_id | text | Google account ID (unique) |
email | text | User email (unique) |
name | text | Display name |
picture | text | Profile picture URL |
permission | enum | view, edit, send, or admin |
created_at | timestamp | Creation timestamp |
workspace_members
Allowlist of emails permitted to access DelightBridge.
| Column | Type | Description |
|---|---|---|
email | text | Primary key |
permission | enum | Default permission level |
created_at | timestamp | Creation timestamp |
Step 3: Seed Initial Data (Optional)
DelightBridge includes a seed script that populates your database with sample services, categories, and email threads for testing.Run seed script
- Inserts sample services from
src/lib/mock-data.ts - Creates categories for each service
- Adds sample email threads and messages
- Generates initial drafts
Verify seeded data
Run Drizzle Studio to browse seeded data:gmail_accounts table to see sample services like “Noji”, “AnkiPro”, and “MemoCard”.
Database Management Commands
DelightBridge provides these database commands:pnpm db:push
Pushes schema changes to database without migrations. Use this during development.
This command reads configuration from
drizzle.config.ts and requires DATABASE_URL in .env.local.pnpm db:studio
Launches Drizzle Studio - a visual database browser.
https://local.drizzle.studio in your browser.
pnpm db:seed
Seeds database with sample data from scripts/seed.ts.
Configuration File
Drizzle configuration is defined indrizzle.config.ts:
schema: Path to schema definitionsout: Directory for generated migration files (not used withdb:push)dialect: Database type (postgresql)dbCredentials.url: Connection string from environment
Production Setup
Use separate databases for development and production
Create two Neon projects:- Development - for local testing
- Production - for live deployment
DATABASE_URL values:
.env.local→ Development database- Vercel environment variables → Production database
Backup and restore
Neon provides automated backups on paid plans. For free tier:- Export data using
pg_dump:
- Restore using
psql:
Troubleshooting
”connection refused” error
Verify:DATABASE_URLis set correctly in.env.local- Connection string includes
?sslmode=require - Neon project is active (not paused)
“permission denied” on table creation
Ensure your Neon user hasCREATE permissions. The default user should have full permissions.
Seed script fails with “duplicate key”
The seed script is idempotent but may fail if data already exists. Drop and recreate tables:Schema changes not reflected
After modifyingsrc/lib/db/schema.ts, always run: