Overview
The @cap/database package provides a shared database layer for Cap using Drizzle ORM and MySQL. It includes schema definitions, migrations, authentication, and email templates.
Installation
The database package is included in the monorepo:
Package Name: @cap/database
Location: packages/database/
Type: Private monorepo package
Exports
import db from "@cap/database" ;
import { authOptions } from "@cap/database/auth/auth-options" ;
import { getServerSession } from "@cap/database/auth/session" ;
import { users , videos , comments } from "@cap/database/schema" ;
import { encrypt , decrypt } from "@cap/database/crypto" ;
import { nanoIdLength } from "@cap/database/helpers" ;
import { runMigrations } from "@cap/database/migrate" ;
Database Schema
Core Tables
Users
interface User {
id: string;
name: string | null;
lastName: string | null;
email: string;
emailVerified: Date | null;
image: string | null;
stripeCustomerId: string | null;
stripeSubscriptionId: string | null;
stripeSubscriptionStatus: string | null;
preferences: {
notifications: {
pauseComments: boolean;
pauseReplies: boolean;
pauseViews: boolean;
pauseReactions: boolean;
};
} | null;
activeOrganizationId: string | null;
}
Videos
interface Video {
id : string ;
ownerId : string ;
name : string ;
createdAt : Date ;
totalComments : number ;
totalReactions : number ;
public : boolean ;
source : "local" | "s3" ;
transcriptionStatus : "PROCESSING" | "COMPLETE" | "ERROR" | null ;
metadata : VideoMetadata ;
}
interface Comment {
id : string ;
content : string ;
videoId : string ;
authorId : string ;
parentId : string | null ;
type : "text" | "textEmbed" ;
createdAt : Date ;
}
Organizations
interface Organisation {
id : string ;
name : string ;
createdAt : Date ;
ownerId : string ;
customDomain : string | null ;
stripeCustomerId : string | null ;
}
Folders
interface Folder {
id : string ;
name : string ;
ownerId : string ;
spaceId : string | null ;
createdAt : Date ;
}
S3 Configuration
interface S3Bucket {
id : string ;
name : string ;
ownerId : string ;
region : string ;
accessKeyId : string ;
secretAccessKey : string ;
endpoint : string | null ;
createdAt : Date ;
}
Database Scripts
Generate Migrations
Create new migration files from schema changes:
Push Schema Changes
Apply schema changes to the database:
Always run db:generate before db:push to create migration files.
Open Drizzle Studio
Visual database browser:
Access at https://local.drizzle.studio
Check Migrations
Verify migration files:
pnpm --filter @cap/database db:check
Drop Migrations
Remove migration files:
pnpm --filter @cap/database db:drop
Database Connection
The database connection is configured via environment variables:
DATABASE_URL = "mysql://user:password@localhost:3306/cap"
For local development with Docker:
DATABASE_URL = "mysql://root:password@localhost:3307/cap"
Database Client
The package exports a configured Drizzle instance:
import { drizzle } from "drizzle-orm/mysql2";
import mysql from "mysql2/promise";
const connection = mysql.createPool({
uri: process.env.DATABASE_URL,
});
const db = drizzle(connection);
export default db;
Crypto Utilities
The package includes encryption utilities for sensitive data:
import { encrypt, decrypt } from "@cap/database/crypto";
const encrypted = encrypt("sensitive-data");
const decrypted = decrypt(encrypted);
Authentication
NextAuth.js configuration:
import { authOptions } from "@cap/database/auth/auth-options" ;
import { getServerSession } from "next-auth" ;
const session = await getServerSession ( authOptions );
Auth Providers
Email Magic Links (primary)
Google OAuth (optional)
GitHub OAuth (optional)
Email Templates
React Email templates are included:
import { MagicLinkEmail } from "@cap/database/emails/MagicLink" ;
import { WelcomeEmail } from "@cap/database/emails/Welcome" ;
Emails are styled with Tailwind CSS via @react-email/tailwind.
Type Definitions
interface VideoMetadata {
customCreatedAt?: string;
sourceName?: string;
aiTitle?: string;
summary?: string;
chapters?: { title: string; start: number }[];
aiGenerationStatus?: "QUEUED" | "PROCESSING" | "COMPLETE" | "ERROR" | "SKIPPED";
enhancedAudioStatus?: "PROCESSING" | "COMPLETE" | "ERROR" | "SKIPPED";
}
Migrations
Migrations are stored in packages/database/migrations/.
Migration Flow
Modify schema in schema.ts
Run pnpm db:generate to create migration
Review generated SQL in migrations/
Run pnpm db:push to apply
Commit migration files to git
Run Migrations Programmatically
import { runMigrations } from "@cap/database/migrate" ;
await runMigrations ();
Database Support
Cap is designed to work with MySQL only . MariaDB or other compatible databases might partially work but are not officially supported.
Dependencies
Core Dependencies
{
"drizzle-orm": "0.44.6",
"mysql2": "^3.15.2",
"@effect/sql-mysql2": "^0.47.0",
"next-auth": "^4.24.5",
"zod": "^3"
}
Dev Dependencies
{
"drizzle-kit" : "0.31.0" ,
"typescript" : "^5.8.3"
}
Effect SQL Integration
The database supports Effect.ts SQL queries:
import { Effect } from "effect" ;
import { MySql } from "@effect/sql-mysql2" ;
const query = Effect . gen ( function* () {
const sql = yield * MySql . MySql ;
const result = yield * sql `SELECT * FROM users WHERE id = ${ userId } ` ;
return result ;
});
Observability
The package includes OpenTelemetry instrumentation via @kubiks/otel-drizzle.
Best Practices
Always run db:generate before db:push
Review generated migrations before applying
Test migrations on a development database first
Commit migration files to version control
Use encryptedText type for sensitive fields
Store S3 credentials encrypted
Never log decrypted values
Use environment variables for keys
Next Steps
UI Components Learn about UI component packages
Development Setup Set up your development environment