Skip to main content
DelightBridge uses Neon as its serverless PostgreSQL database and Drizzle ORM for schema management and queries.

Prerequisites

  • Node.js 20+ and pnpm installed
  • DelightBridge repository cloned locally
  • Neon account (free tier available)

Step 1: Create Neon Database

1

Sign up for Neon

Go to neon.tech and create an account (GitHub login available).
2

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) for us-east-2)
Click Create Project.
3

Copy connection string

After project creation, Neon displays your connection string. Copy the Pooled connection string.It should look like:
postgresql://user:[email protected]/delightbridge?sslmode=require
Ensure the connection string ends with ?sslmode=require - this is required for Neon.
4

Add to environment variables

Create or update .env.local in your DelightBridge project root:
DATABASE_URL=postgresql://user:[email protected]/delightbridge?sslmode=require

Step 2: Push Database Schema

DelightBridge uses Drizzle Kit to push schema changes directly to your database without migrations.

Install dependencies

pnpm install

Push schema to Neon

pnpm db:push
This command:
  1. Reads schema definitions from src/lib/db/schema.ts
  2. Connects to your Neon database using DATABASE_URL
  3. Creates all required tables and indexes
Expected output:
✓ Pushing changes...
Done!

Verify tables created

You can verify tables were created using Neon’s SQL Editor or Drizzle Studio:
pnpm db:studio
This opens a local web interface at 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.
ColumnTypeDescription
idtextPrimary key
nametextService display name (e.g., “Noji Support”)
emailtextGmail address
colortextBrand color (hex)
signaturetextHTML email signature
documenttextReference documentation for AI (Markdown)
access_tokentextOAuth access token
refresh_tokentextOAuth refresh token
last_history_idtextGmail API history ID for incremental sync
created_attimestampCreation timestamp

categories

Service-specific email categories for automatic labeling.
ColumnTypeDescription
idtextPrimary key
account_idtextForeign key to gmail_accounts
nametextCategory name
colortextBadge background color
text_colortextBadge text color

email_threads

Email conversation threads from Gmail.
ColumnTypeDescription
idtextPrimary key
account_idtextForeign key to gmail_accounts
gmail_thread_idtextGmail thread ID
subjecttextEmail subject
customer_emailtextCustomer email address
customer_nametextCustomer display name
category_idtextForeign key to categories
statusenuminbox, sent, or archived
detected_languagetextDetected language code
is_readbooleanRead status
last_message_attimestampTimestamp of most recent message
created_attimestampCreation timestamp

emails

Individual messages within threads.
ColumnTypeDescription
idtextPrimary key
thread_idtextForeign key to email_threads
gmail_message_idtextGmail message ID
from_emailtextSender email
from_nametextSender display name
to_emailtextRecipient email
bodytextHTML message body
directionenuminbound or outbound
sent_attimestampMessage timestamp
created_attimestampCreation timestamp

drafts

AI-generated draft responses for threads.
ColumnTypeDescription
idtextPrimary key
thread_idtextForeign key to email_threads (unique)
subjecttextDraft subject line
contenttextHTML draft content
translationtextKorean translation
statusenumpending, ready, sent, or skipped
sent_attimestampSent timestamp (null if not sent)
updated_attimestampLast update timestamp

User & Permission Tables

users

Authenticated users who can access DelightBridge.
ColumnTypeDescription
idtextPrimary key
google_idtextGoogle account ID (unique)
emailtextUser email (unique)
nametextDisplay name
picturetextProfile picture URL
permissionenumview, edit, send, or admin
created_attimestampCreation timestamp

workspace_members

Allowlist of emails permitted to access DelightBridge.
ColumnTypeDescription
emailtextPrimary key
permissionenumDefault permission level
created_attimestampCreation 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

pnpm db:seed
What it does:
  1. Inserts sample services from src/lib/mock-data.ts
  2. Creates categories for each service
  3. Adds sample email threads and messages
  4. Generates initial drafts
Expected output:
Seeding database...
✓ Inserted 3 services
✓ Inserted 15 threads, 45 messages
Seed complete.
The seed script uses mock data. In production, you should connect real Gmail accounts instead of seeding.

Verify seeded data

Run Drizzle Studio to browse seeded data:
pnpm db:studio
Navigate to the 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.
pnpm db:push
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.
pnpm db:studio
Opens https://local.drizzle.studio in your browser.

pnpm db:seed

Seeds database with sample data from scripts/seed.ts.
pnpm db:seed

Configuration File

Drizzle configuration is defined in drizzle.config.ts:
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  schema: './src/lib/db/schema.ts',
  out: './drizzle',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});
  • schema: Path to schema definitions
  • out: Directory for generated migration files (not used with db:push)
  • dialect: Database type (postgresql)
  • dbCredentials.url: Connection string from environment

Production Setup

Use separate databases for development and production

Create two Neon projects:
  1. Development - for local testing
  2. Production - for live deployment
Set different 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:
  1. Export data using pg_dump:
pg_dump $DATABASE_URL > backup.sql
  1. Restore using psql:
psql $DATABASE_URL < backup.sql

Troubleshooting

”connection refused” error

Verify:
  • DATABASE_URL is 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 has CREATE 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:
pnpm db:push
Then run seed again:
pnpm db:seed

Schema changes not reflected

After modifying src/lib/db/schema.ts, always run:
pnpm db:push
Drizzle Kit will detect changes and update your database.

Build docs developers (and LLMs) love