5.2 KiB
5.2 KiB
10. Database — Turso (SQLite) Connection, Migrations, and Seed Data
meta: id: kordant-unified-restructure-10 feature: kordant-unified-restructure priority: P0 depends_on: [kordant-unified-restructure-09] tags: [backend, database, drizzle, turso, sqlite]
objective:
- Set up the database connection layer, migration tooling, and seed data for the unified monolith. Configure Turso (libsql/SQLite) as the database backend, matching the production database used by the legacy
packages/db.
deliverables:
web/src/server/db/index.ts— Database connection module:- Creates Turso (libsql) client using
@libsql/client - Exports
dbinstance initialized with Drizzle ORM - Handles connection URL and auth token from environment variables
- Graceful shutdown hook to close client
- Creates Turso (libsql) client using
web/drizzle.config.ts— Drizzle Kit configuration:- Points to
src/server/db/schema/index.ts - Specifies
tursodialect - Reads database URL and auth token from env
- Points to
web/src/server/db/migrate.ts— Migration runner script:- Programmatically runs pending migrations on startup
- Can be called from
entry-server.tsxor a standalone script
web/src/server/db/seed.ts— Seed script:- Creates sample users, subscriptions, watchlist items, alerts, blog posts
- Idempotent: can be run multiple times without duplicates
- Useful for development and demo environments
- Environment configuration:
DATABASE_URLandDATABASE_AUTH_TOKENin.envand.env.example
steps:
- Install dependencies in
web/:drizzle-orm,drizzle-kit@libsql/client(Turso/libsql client)
- Create
web/src/server/db/index.ts:import { createClient } from '@libsql/client'; import { drizzle } from 'drizzle-orm/libsql'; import * as schema from './schema'; const client = createClient({ url: process.env.DATABASE_URL, authToken: process.env.DATABASE_AUTH_TOKEN, }); export const db = drizzle(client, { schema }); - Update
web/drizzle.config.ts:import { defineConfig } from 'drizzle-kit'; export default defineConfig({ schema: './src/server/db/schema/index.ts', out: './drizzle', dialect: 'turso', dbCredentials: { url: process.env.DATABASE_URL!, authToken: process.env.DATABASE_AUTH_TOKEN, }, }); - Create
web/src/server/db/migrate.ts:- Import
migratefromdrizzle-orm/libsql/migrator - Run migrations from
./drizzlefolder - Log success or error
- Import
- Create
web/src/server/db/seed.ts:- Use
db.insert()to populate tables - Create: 2-3 users, 1 family group, 2 subscriptions (basic + premium), 3-5 watchlist items, 2-3 exposures, 5-10 alerts, 3 blog posts, 2 property watchlist items, 1 removal request
- Use deterministic IDs or check for existing data before inserting
- Use
- Add
db:migrate,db:generate,db:push,db:seedscripts toweb/package.json. - Create
.env.exampleinweb/withDATABASE_URL=libsql://...andDATABASE_AUTH_TOKEN - Test locally:
- Create a Turso database (or use local SQLite with
libsql://./dev.db) - Run
pnpm db:generateto create migration SQL - Run
pnpm db:pushto apply schema - Run
pnpm db:seedto populate data - Verify tables exist with correct data using
turso db shellor a SQLite GUI tool
- Create a Turso database (or use local SQLite with
- Update
web/src/server/db/schema.tsfrom task 09 if any adjustments are needed based on migration output.
steps:
- Integration:
pnpm db:generateproduces valid SQL - Integration:
pnpm db:pushcreates all tables in local Turso/SQLite - Integration:
pnpm db:seedpopulates tables without errors - Integration: Application can query seeded data via
db.select()
acceptance_criteria:
web/src/server/db/index.tsexports a working Drizzledbinstance with Turso clientdrizzle.config.tsis correctly configured for Turso (dialect: 'turso')pnpm db:generatecreates migration files inweb/drizzle/pnpm db:pushapplies schema to a Turso database successfullypnpm db:seedpopulates all relevant tables with sample data- The app can perform
db.select().from(users)and return seeded users - Environment variables are documented in
.env.example
validation:
cd web && pnpm db:generate— checkdrizzle/folder for SQL filescd web && pnpm db:push— verify tables created viaturso db shell <database> "SELECT name FROM sqlite_master WHERE type='table';"cd web && pnpm db:seed— verify data exists viaturso db shell <database> "SELECT COUNT(*) FROM users;"- Create a temporary test route that queries
db.select().from(users)and renders results
notes:
- We are using Turso (libsql/SQLite) as the database backend with Drizzle ORM.
- For local development, you can use a local SQLite file (
libsql://./dev.db) or create a Turso database. - Turso provides edge-distributed SQLite with fast read replicas — no connection pooling needed.
- Migration files should be committed to git so all environments run the same migrations.
- The seed script should be idempotent. Use
INSERT OR IGNOREor check existence before inserting. - SQLite doesn't support
DROP COLUMNorALTER TABLEextensively — plan schema changes carefully or use Turso's rewrap for migrations.