Two backlog trees are complete: `docs/project/backlog/` (75 files, every WP done) and `docs/project/refactor-backlog-setup/` (the arc before it). Move both under `docs/project/archive/` with `git mv`, so history stays intact through `git log --follow`. `SHOWCASE-ROADMAP.md` moves with them, because it points at the now-archived backlog README. Add `docs/project/archive/README.md`. It states that these trees are historical and names the two directories that are still live. Repoint every inbound reference named in RD-30's Files table: CLAUDE.md, the root README, both backend READMEs, `LetterHtml.cs`, `a11y.mdx`, the `document-feature` and `new-ssp` skills, and the readable-codebase PLAN, README, and RD-19 ticket. Fix two upward-relative links inside the moved WP files (WP-68, WP-69) that gained a directory level and would otherwise break. Repoint `.prettierignore`'s two agent-prompt exclusions to their new path, so prettier keeps leaving those files' exact wording alone. Mark RD-30 done and check off its acceptance criteria; flip its README row to done. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
106 lines
5.5 KiB
Markdown
106 lines
5.5 KiB
Markdown
# WP-56 — Idempotent catalogus provisioning
|
||
|
||
Status: done
|
||
Phase: 10 — OpenZaak production hardening
|
||
|
||
## Why
|
||
|
||
`backend/openzaak/bootstrap-catalogus.sh` seeds catalogus/zaaktype/statustype/roltype/zaak
|
||
via hand-rolled curl+JWT and is explicitly **not idempotent** (fails on `domein`+`rsin`
|
||
uniqueness on rerun) — fine for a one-shot WP-54 harness, wrong for an environment that
|
||
needs to be rebuildable. OpenZaak already ships a documented, scripted alternative — the
|
||
`setup_configuration` mechanism (already used in the harness for the JWTSecret/Applicatie,
|
||
see `setup_configuration/data.yaml`) — this WP extends that same mechanism to the catalogus
|
||
content too.
|
||
|
||
## Read first
|
||
|
||
- `backend/openzaak/bootstrap-catalogus.sh`
|
||
- `backend/openzaak/setup_configuration/data.yaml`
|
||
- `backend/openzaak/docker-compose.openzaak.yml` (`web-init` service)
|
||
- OpenZaak's own `setup_configuration` / `openzaak_config_cli` docs (upstream)
|
||
|
||
## Decisions (pre-made, don't relitigate)
|
||
|
||
- Move catalogus/zaaktype/statustype/roltype provisioning into `setup_configuration`,
|
||
run by the existing `web-init` one-shot service, instead of the separate curl script.
|
||
- Keep `bootstrap-catalogus.sh` only for whatever content `setup_configuration` genuinely
|
||
can't express (e.g. a demo zaak instance) — confirm what's left at kickoff.
|
||
- Provisioning must be safe to run against an already-provisioned instance — either
|
||
genuinely idempotent, or the compose is structured to only run it once per fresh
|
||
volume (document which, don't leave it ambiguous).
|
||
|
||
## Files
|
||
|
||
- `backend/openzaak/setup_configuration/data.yaml`
|
||
- `backend/openzaak/bootstrap-catalogus.sh` (trim to whatever remains)
|
||
- `backend/openzaak/docker-compose.openzaak.yml`
|
||
- `backend/openzaak/README.md`
|
||
|
||
## Steps
|
||
|
||
1. Express the catalogus/zaaktype/statustype/roltype definitions currently created by
|
||
curl as `setup_configuration` YAML.
|
||
2. Wire it into the `web-init` command alongside the existing JWTSecret/Applicatie config.
|
||
3. Trim `bootstrap-catalogus.sh` to only what setup_configuration can't cover, if anything.
|
||
4. Test: tear down + `docker compose up` twice in a row (fresh volume, then existing
|
||
volume); confirm no failure on rerun.
|
||
5. Update the README describing the provisioning flow.
|
||
|
||
## Acceptance criteria
|
||
|
||
- [x] ~~Catalogus/zaaktype/statustype/roltype provisioning is declarative
|
||
(`setup_configuration`), not imperative curl.~~ Not achievable — see Deviation below;
|
||
replaced by: provisioning is safe to rerun against an already-seeded instance.
|
||
- [x] Running the compose stack up twice in a row doesn't error (verified: `bootstrap-catalogus.sh`
|
||
run 3× in a row against the same instance, all reused/no duplicates/no errors).
|
||
- [x] WP-54's `OpenZaakIntegrationTests` still pass unchanged (same content, different
|
||
provisioning mechanism).
|
||
|
||
## Deviation from the original plan
|
||
|
||
Confirmed by reading the `django_setup_configuration` steps actually installed inside the
|
||
`openzaak/open-zaak:1.29.1` image (`/app/src/openzaak/config/setup_configuration/steps/` +
|
||
every third-party `contrib/setup_configuration/` package): the ONLY app-registered
|
||
configuration steps are sites/credentials/applicaties (already used by `data.yaml`) and
|
||
Selectielijst API config. There is no step for catalogus/zaaktype/statustype/roltype/zaak
|
||
content anywhere in this OpenZaak version — the WP's core premise ("move provisioning into
|
||
setup_configuration") is not achievable. This was explicitly anticipated by the WP's own Risks
|
||
section ("if a piece genuinely can't be expressed declaratively, keep it in a clearly-labeled
|
||
idempotent script rather than forcing a bad fit") and Decisions block ("either genuinely
|
||
idempotent, or the compose is structured to only run it once... document which").
|
||
|
||
Chose **genuinely idempotent**: `bootstrap-catalogus.sh` now looks up every resource by its
|
||
natural key before creating it (catalogus by `domein`+`rsin`, zaaktype by `catalogus`+
|
||
`identificatie`, statustype by `zaaktype`+`volgnummer` (no server-side volgnummer filter, so
|
||
listed by zaaktype and matched client-side), resultaattype by existence-only (publish just
|
||
needs ≥1), roltype by `zaaktype`+`omschrijvingGeneriek`, zaaktype-publish by checking `concept`
|
||
on the zaaktype detail first, zaak by `identificatie`, status/rol by existence-under-the-zaak).
|
||
Real gotcha hit and fixed: OpenZaak's query-parameter names are camelCase
|
||
(`omschrijvingGeneriek`), not the Django model's snake_case (`omschrijving_generiek`) the
|
||
filter is registered under internally — the snake_case form 400s with "Onbekende query
|
||
parameters" (unknown query parameter). Verified for real: fresh instance → full run (all
|
||
"created") → `dotnet test --filter Category=Integration` green → reran the script twice more
|
||
against the same live instance (all "exists", identical URLs each time, no duplicates) →
|
||
integration test still green.
|
||
|
||
Not attempted: moving anything into `setup_configuration/data.yaml` (nothing there to move,
|
||
per the finding above).
|
||
|
||
## Verification
|
||
|
||
`docker compose -f backend/openzaak/docker-compose.openzaak.yml up` twice in a row (fresh
|
||
volume, then existing volume); `cd backend && dotnet test --filter Category=Integration`
|
||
against the harness.
|
||
|
||
## Out of scope
|
||
|
||
Secrets/TLS (WP-55, unrelated but sequenced first in the table only by number), client
|
||
scopes (WP-57), notifications (WP-58).
|
||
|
||
## Risks
|
||
|
||
OpenZaak's `setup_configuration` coverage for zaaktype/besluittype content may be
|
||
incomplete upstream — if a piece genuinely can't be expressed declaratively, keep it in a
|
||
clearly-labeled idempotent script rather than forcing a bad fit.
|