Safe zero-downtime database migrations using Expand/Contract.
Triggered whenever a database schema change is requested. Every breaking change must be split into two or three phases via Expand/Contract.
ARCHITECTURE_RULES.md.claude/feature-workspace/db-migration-[description].md
# DB Migration: [Description]
## Change Summary
[What is changing and why]
## Pattern
Expand/Contract (3 phases) | Single-phase safe
## Phase 1 — Expand
```sql
-- Forward
ALTER TABLE users ADD COLUMN locked_until TIMESTAMPTZ NULL;
-- Rollback
ALTER TABLE users DROP COLUMN IF EXISTS locked_until;
Deploy when: immediately
Verify: SELECT COUNT(*) FROM users WHERE locked_until IS NOT NULL; → expect 0
-- Application writes to both old and new columns
UPDATE users SET locked_until = lockout_expires_at WHERE lockout_expires_at IS NOT NULL;
Deploy when: Phase 1 is live and stable
Verify: SELECT COUNT(*) FROM users WHERE lockout_expires_at != locked_until; → expect 0
-- Forward
ALTER TABLE users DROP COLUMN lockout_expires_at;
Deploy when: Phase 2 backfill verified, no traffic using old column
Verify: \d users → lockout_expires_at column absent
## Guardrails
- `DROP COLUMN` or `DROP TABLE` NEVER appears in Phase 1 — only in Phase 3
- `NOT NULL` without `DEFAULT` NEVER appears in a single-phase migration
- `RENAME COLUMN` is NEVER used directly — always Expand/Contract instead
- Phase 3 requires explicit user confirmation: "confirm contract phase"
- Never write a migration that cannot be rolled back in Phase 1 or Phase 2
## Standalone Mode
Pure SQL generation. No external tools required.