docs(adr): ADR-0003 reset-demo-data schema-safe reset on prod, supersedes GRO-2705 removal (GRO-2721)
@@ -0,0 +1,44 @@
|
||||
# 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](/groombook/org/wiki/ADR-0002+API+DB-health+endpoint+strategy.-).
|
||||
- **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.
|
||||
Reference in New Issue
Block a user