fix(db): make services seed idempotent across resets (GRO-2064, GRO-2033 close-out)
The seed Job `seed-test-data-b5943fb` failed three times on prod with
`duplicate key value violates unique constraint "services_pkey"` after
migrations 0039/0040 landed. Two interlocking bugs in
`packages/db/src/seed.ts` (and the parallel `apps/api/src/db/seed.ts`
tree — both kept in sync per the GRO-2052/2013/2014 lesson):
1. The reset `TRUNCATE` excluded `services`, so a prior
`seedKnownUsers` run that wrote `id=b0000001-…-004, name="Nail Trim"`
survived every reset. The next full `seed()` then tried to insert
`id=b0000001-…-004, name="Full Groom — Large"` and PostgreSQL
raised `services_pkey` (id collision) — the name-targeted
`ON CONFLICT` couldn't fire because the conflict was on a different
column.
2. The `demoSvcs` (used by `seedKnownUsers`) had `id=…-004, name="Nail Trim"`
while `servicesDef` (used by the full `seed()`) has `id=…-004,
name="Full Groom — Large"`. `Nail Trim` was supposed to be
`id=…-005` in the demo subset.
Fix:
* `TRUNCATE services, …` so each reset rebuilds the catalogue from
`servicesDef` (CASCADE handles appointments/invoices FKs).
* Key both services upserts on `schema.services.id` (not `name`) so
deterministic ids always win — defense-in-depth if a future change
drops `services` from the TRUNCATE list again.
* Reconcile the id↔name map: `demoSvcs[3]` is now
`id=…-005, name="Nail Trim"` to match `servicesDef[4]`.
* Update `UAT_PLAYBOOK.md §4.5.1` with regression coverage
(TC-SEED-1..4).
Required for the GRO-2033 close-out: infra PR #605 must repoint to the
new image tag (NOT 2a6242d) and `apps/overlays/prod/reset-cronjob.yaml`
must stay suspended until a one-shot seed Job runs 1/1 against prod.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -192,6 +192,33 @@ Expected: one row, `role = 'groomer'`. If zero rows return, the request hit the
|
||||
| TC-API-5.4 | Update service | PATCH /api/services/{id} with updated fields | 200 OK, service updated |
|
||||
| TC-API-5.5 | Delete service | DELETE /api/services/{id} | 200 OK, service deleted |
|
||||
|
||||
#### 4.5.1 Seed/Reset idempotency (GRO-2064)
|
||||
|
||||
Services seeding is now keyed on the deterministic `services.id` (not `name`) and
|
||||
the reset path now `TRUNCATE`s `services` alongside the other dynamic tables.
|
||||
This means:
|
||||
|
||||
- Running the seed Job twice in a row (no reset in between) converges to the
|
||||
same catalogue — no `services_pkey` collision.
|
||||
- A `pnpm reset` followed by `pnpm seed` (or a CronJob reset fire) leaves the
|
||||
catalogue exactly matching `servicesDef` (10 rows, ids `b0000001-…-001` …
|
||||
`…-00a`), regardless of any stale rows that were present beforehand.
|
||||
- Mixed `seedKnownUsers` + full `seed()` invocations are safe — the
|
||||
`demoSvcs` subset (Bath & Brush, Full Groom Small/Medium, Nail Trim) is
|
||||
keyed on ids `…-001`, `…-002`, `…-003`, `…-005` and the upsert target
|
||||
is `services.id`, so the same-id / different-name collision that broke
|
||||
GRO-2033 (id `…-004` = "Nail Trim" vs servicesDef `…-004` =
|
||||
"Full Groom — Large") cannot recur.
|
||||
|
||||
**UAT regression** (verify after a new image is rolled out):
|
||||
|
||||
| # | Scenario | Steps | Expected |
|
||||
|---|----------|-------|----------|
|
||||
| TC-SEED-1 | Reset → seed converges | `kubectl -n groombook exec deploy/api -- pnpm reset && pnpm seed` | Seed completes 1/1, `services` count = 10, all ids match `servicesDef` |
|
||||
| TC-SEED-2 | Idempotent re-seed | Re-run `pnpm seed` without reset | Seed completes 1/1, no `services_pkey` errors, `services` count still 10 |
|
||||
| TC-SEED-3 | Catalogue matches servicesDef | `psql -c "SELECT id, name FROM services ORDER BY id"` | Rows `…-001`…`…-00a` with names "Bath & Brush"…"Sanitary Trim" exactly as in `servicesDef` |
|
||||
| TC-SEED-4 | Demo subset coexists | Run `seedKnownUsers` then full `seed` | No collision, demo subset (4 services) ends up with the same rows the full seed would write |
|
||||
|
||||
### 4.6 Staff Management
|
||||
|
||||
| # | Scenario | Steps | Expected |
|
||||
|
||||
Reference in New Issue
Block a user