rebranding
This commit is contained in:
113
tasks/kordant-unified-restructure/10-db-connection-migrations.md
Normal file
113
tasks/kordant-unified-restructure/10-db-connection-migrations.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# 10. Database — PostgreSQL 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, postgres]
|
||||
|
||||
objective:
|
||||
- Set up the database connection layer, migration tooling, and seed data for the unified monolith. Replace the current SQLite setup in `web/` with PostgreSQL, matching the production database used by the legacy `packages/db`.
|
||||
|
||||
deliverables:
|
||||
- `web/src/server/db/index.ts` — Database connection module:
|
||||
- Creates PostgreSQL connection pool using `pg` or `@neondatabase/serverless`
|
||||
- Exports `db` instance initialized with Drizzle ORM
|
||||
- Handles connection string from environment variables
|
||||
- Graceful shutdown hook to close pool
|
||||
- `web/drizzle.config.ts` — Drizzle Kit configuration:
|
||||
- Points to `src/server/db/schema.ts`
|
||||
- Specifies PostgreSQL dialect
|
||||
- Reads database URL from env
|
||||
- `web/src/server/db/migrate.ts` — Migration runner script:
|
||||
- Programmatically runs pending migrations on startup
|
||||
- Can be called from `entry-server.tsx` or 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_URL` in `.env` and `.env.example`
|
||||
- Connection pooling settings (max connections, timeout)
|
||||
|
||||
steps:
|
||||
1. Install dependencies in `web/`:
|
||||
- `drizzle-orm`, `drizzle-kit`
|
||||
- `pg` (for local/dev) or `@neondatabase/serverless` (for serverless deploy)
|
||||
- `@types/pg` if using `pg`
|
||||
2. Create `web/src/server/db/index.ts`:
|
||||
```ts
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import { Pool } from 'pg';
|
||||
import * as schema from './schema';
|
||||
|
||||
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
||||
export const db = drizzle(pool, { schema });
|
||||
```
|
||||
3. Update `web/drizzle.config.ts`:
|
||||
```ts
|
||||
import { defineConfig } from 'drizzle-kit';
|
||||
export default defineConfig({
|
||||
schema: './src/server/db/schema.ts',
|
||||
out: './drizzle',
|
||||
dialect: 'postgresql',
|
||||
dbCredentials: { url: process.env.DATABASE_URL! },
|
||||
});
|
||||
```
|
||||
4. Create `web/src/server/db/migrate.ts`:
|
||||
- Import `migrate` from `drizzle-orm/node-postgres/migrator`
|
||||
- Run migrations from `./drizzle` folder
|
||||
- Log success or error
|
||||
5. 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
|
||||
6. Add `db:migrate`, `db:generate`, `db:push`, `db:seed` scripts to `web/package.json`.
|
||||
7. Create `.env.example` in `web/` with `DATABASE_URL=postgresql://...`
|
||||
8. Test locally:
|
||||
- Start PostgreSQL (Docker or local install)
|
||||
- Run `pnpm db:generate` to create migration SQL
|
||||
- Run `pnpm db:push` to apply schema
|
||||
- Run `pnpm db:seed` to populate data
|
||||
- Verify tables exist with correct data using `psql` or a GUI tool
|
||||
9. Update `web/src/server/db/schema.ts` from task 09 if any adjustments are needed based on migration output.
|
||||
|
||||
steps:
|
||||
- Integration: `pnpm db:generate` produces valid SQL
|
||||
- Integration: `pnpm db:push` creates all tables in local PostgreSQL
|
||||
- Integration: `pnpm db:seed` populates tables without errors
|
||||
- Integration: Application can query seeded data via `db.select()`
|
||||
|
||||
acceptance_criteria:
|
||||
- [ ] `web/src/server/db/index.ts` exports a working Drizzle `db` instance
|
||||
- [ ] `drizzle.config.ts` is correctly configured for PostgreSQL
|
||||
- [ ] `pnpm db:generate` creates migration files in `web/drizzle/`
|
||||
- [ ] `pnpm db:push` applies schema to a PostgreSQL database successfully
|
||||
- [ ] `pnpm db:seed` populates 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` — check `drizzle/` folder for SQL files
|
||||
- `cd web && pnpm db:push` — verify tables created via `psql -d kordant -c "\dt"`
|
||||
- `cd web && pnpm db:seed` — verify data exists via `psql -d kordant -c "SELECT COUNT(*) FROM users;"`
|
||||
- Create a temporary test route that queries `db.select().from(users)` and renders results
|
||||
|
||||
notes:
|
||||
- The legacy project used Prisma + PostgreSQL in production. We are keeping PostgreSQL but switching to Drizzle ORM.
|
||||
- For local development, Docker Compose with PostgreSQL is recommended:
|
||||
```yaml
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_USER: kordant
|
||||
POSTGRES_PASSWORD: kordant
|
||||
POSTGRES_DB: kordant
|
||||
ports:
|
||||
- "5432:5432"
|
||||
```
|
||||
- If deploying to Vercel/Netlify serverless, use `@neondatabase/serverless` instead of `pg`.
|
||||
- Migration files should be committed to git so all environments run the same migrations.
|
||||
- The seed script should be idempotent. Use `ON CONFLICT DO NOTHING` or check existence before inserting.
|
||||
Reference in New Issue
Block a user