| name | db-migrate |
| description | Drizzle schema change workflow for SpawnForge Neon DB. Use when modifying schema.ts, generating migrations, applying migrations to production, or debugging FK/cascade issues. |
| user-invocable | true |
| allowed-tools | Bash, Read, Glob, Grep, Edit |
| argument-hint | [action: generate|push|migrate|validate|status] |
| paths | web/src/lib/db/** |
Database Migration Workflow
Safe database schema changes for SpawnForge (Drizzle ORM + Neon Postgres).
Before ANY Schema Change
- Read the current schema:
web/src/lib/db/schema.ts
- Read lessons learned — FK constraint bugs have caused real incidents (PF-976, PF-974)
- Identify ALL tables that reference the table being modified
Actions
validate (default when no args)
Check schema for common issues:
cd web
grep -n "references.*=>" src/lib/db/schema.ts | grep -v "onDelete"
grep -n "user_id\|userId" src/lib/db/schema.ts | grep "references"
grep -n "DELETE FROM\|delete(" src/lib/auth/user-service.ts
echo "--- Tables with user_id FK ---"
grep -B5 "userId.*references.*users" src/lib/db/schema.ts | grep "pgTable"
echo "--- Tables deleted in deleteUserAccount ---"
grep "DELETE FROM\|\.delete(" src/lib/auth/user-service.ts | grep -oE "'[a-z_]+'" | sort -u
npx tsc --noEmit src/lib/db/schema.ts 2>&1 | head -20
generate
Generate a migration from schema changes:
cd web
npx tsc --noEmit
npx drizzle-kit generate
ls -t drizzle/*.sql | head -1 | xargs cat
push (dev only — direct schema push, no migration file)
cd web && npx drizzle-kit push
Use only for local development. Never in production.
migrate (production — applies migration files)
cd web && npx drizzle-kit migrate
status
cd web && npx drizzle-kit status
FK Cascade Checklist
When adding a new table with user_id or any FK to users.id:
- Add
DELETE FROM <table> WHERE user_id = ${userId} to deleteUserAccount() in web/src/lib/auth/user-service.ts
- Place the DELETE statement BEFORE the parent table's DELETE (dependency order)
- If the new table has its own FK children, delete those first
- Add the table to the schema test in
web/src/lib/db/__tests__/schema.test.ts
Common Pitfalls
- Missing FK in delete cascade: Adding a table with
userId.references(() => users.id) without updating deleteUserAccount() — user deletion fails silently
- Wrong delete order: Deleting a parent before its FK children causes constraint violations
- Non-nullable FK without onDelete: Postgres defaults to RESTRICT, blocking parent deletion
- Transaction atomicity: Multi-table mutations must use
sql.transaction([...statements]) — individual statements are not atomic together
Neon-Specific
- Use
neon-http driver (stateless HTTP), not WebSocket driver
- Transactions:
sql.transaction([stmt1, stmt2, ...]) — array of tagged template literals
- No connection pooling needed — each request is independent
- Schema lives in
web/src/lib/db/schema.ts, client in web/src/lib/db/client.ts