fix(GRO-2672): use drizzle-kit migrate in reset.ts to bypass HWM bug #228
Reference in New Issue
Block a user
Delete Branch "fix/gro-2672-drizzle-kit-migrate"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Root cause
drizzle-orm/postgres-js/migrator'smigrate()function has the known high-water-mark (HWM) bug. Whenreset.tsdrops the drizzle schema and callsmigrate()on a fresh DB, it applies migration 0000 first — setting the HWM towhen = 1773771452946(2026-03-17). Migrations with stale 2025-erawhentimestamps are silently skipped:whenpets.health_alertsmissingrecurring_seriestable +appointments.series_id/series_indexmissingimpersonation_sessionstable missingMigration 0003 is the blocker. It creates the
recurring_seriestable and addsseries_id/series_indexcolumns toappointments. Sincemigrate()wraps all SQL in a single Postgres transaction, any downstream applied migration that depends on those objects fails — causing a full rollback that takes migration 0000'sstaffandservicestables with it.After reset exits 1, the DB has zero tables and no drizzle ledger. The next reset hits the same failure. The standalone
seed-test-dataK8s Job also fails because tables don't exist.The K8s
migrate-schema-552a4d9Job usesdrizzle-kit migrate(hash-based), finds the (also-missing) ledger empty, and applies all 42 migrations correctly — butreset.tswas not using the same approach.Fix
Replace
migrate()fromdrizzle-orm/postgres-js/migratorwithpnpm exec drizzle-kit migrate(hash-based). drizzle-kit checks each migration's hash against the ledger — it applies every unhashed migration regardless ofwhentimestamp ordering. This matches the K8s migrate Job's behaviour exactly.One-line diff (conceptually):
drizzle-kit reads
packages/db/drizzle.config.ts(schema, migrations folder, DATABASE_URL) from thecwd. pnpm is already in PATH in the Docker reset image (the CMD ispnpm --filter @groombook/db reset).Recovery path
Once this fix ships to prod (via the standard dev→uat→main pipeline), the next
reset-demo-dataCronJob run will apply all 42 migrations on a fresh DB (hash-based, no HWM skip) and re-seed successfully.Test plan
reset-demo-dataCronJob runs clean at next :45 mark — verify via pod logs that all 42 migrations are applied and seed completes (Shedward)seed-test-datajob completes successfully after resetcc @cpfarhood