1
ADR-0003 reset-demo-data on prod — schema-safe reset
The Dogfather edited this page 2026-08-16 13:07:30 +00:00

ADR-0003 — reset-demo-data on prod: schema-safe reset (supersedes GRO-2705 removal)

  • Status: Accepted (2026-08-16)
  • Context tickets: GRO-2721 (this), GRO-2720 (CEO correction), GRO-2705 / infra PR #735 (superseded), GRO-2678 (original outage). Related: ADR-0002.
  • Decider: CTO (Dogfather).

Context

demo.groombook.dev is a demo site; it relies on the reset-demo-data CronJob to periodically restore demo state. That CronJob runs the git.farh.net/groombook/reset image, whose entrypoint is pnpm --filter @groombook/db reset:

node ./scripts/wait-for-db.mjs && tsx src/reset.ts && drizzle-kit migrate && tsx src/seed.ts

packages/db/src/reset.ts was written local-dev-only and is destructive: DROP TABLE ... CASCADE (all public tables), DROP TYPE (all enums), DROP TABLE drizzle.__drizzle_migrations, and DROP SCHEMA IF EXISTS drizzle CASCADE. In GRO-2678 it dropped the PROD schema; the following drizzle-kit migrate no-op'd (journal-driven, GRO-2672 class bug) → empty DB → outage.

GRO-2705 (PR #735) removed the CronJob from the prod overlay entirely. That was a correct interim safety measure but the wrong permanent fix — it left the demo site with no reset path.

Decision

Re-add reset-demo-data to prod, but only after making the reset path schema-safe:

  • reset.ts resets data only via TRUNCATE ... RESTART IDENTITY CASCADE of public tables, then reseeds.
  • It issues no DROP TABLE / DROP TYPE / DROP SCHEMA / DROP DATABASE in any schema. The drizzle schema + migrations table are left intact, so drizzle-kit migrate stays a no-op on an already-migrated DB and the schema is never torn down — even if a later step fails.
  • Production guard (NODE_ENV=production && ALLOW_RESET!=true → exit) retained.

Sequencing (hard dependency)

Re-adding the CronJob against the current/:latest destructive image would reproduce GRO-2678. Therefore:

  1. GRO-2722 (api) — make packages/db/src/reset.ts schema-safe. Full SDLC; UAT must actually run the uat reset CronJob and prove the schema survives. Ships a new reset:<CalVer>-<sha> image.
  2. GRO-2723 (infra) — re-add reset-cronjob.yaml + kustomization entry to apps/overlays/prod, image pinned to GRO-2722's tag (never :latest). Blocked by GRO-2722.

Prod DB creds for the CronJob: secret groombook-postgres-credentials, key uri.

Consequences

  • Demo site regains automated reset with no schema-drop blast radius.
  • Reset image path is no longer "local-dev-only"; the destructive full-drop behavior, if still wanted for local dev, moves to a separate db:nuke script.
  • Overlay pins the reset image to CalVer (per DevOps no-:latest, no-image-automation policy); future reset changes require a new pin.

Guardrail

Any job/script that runs against the prod groombook schema must be additive or truncate-only. DROP SCHEMA / DROP TABLE / DROP DATABASE against prod is prohibited outside an explicit, board-approved, backup-gated migration.