feat(acl): resolve the zaaktype by identificatie, not a pinned URL (S-27, closes #113) #118

Merged
not merged 5 commits from feat/113-acl-zaaktype-by-identificatie into main 2026-07-22 14:49:27 +00:00
Contributor

What & why

The ACL was handed a pinned zaaktype URL (Acl__Defaults__ZaaktypeUrl) + informatieobjecttype URL. OpenZaak assigns those UUIDs at creation, so every stack had to seed the catalogus and then capture + inject the resulting URLs out of band (CI's run-domain-check.sh; the local local-seedacl.env bootstrap from ADR-0020). Brittle, and a stale/placeholder URL failed opaquely (OpenZaak 400).

Now the ACL resolves them itself from OpenZaak's Catalogi API by stable business key:

  • config ZaaktypeIdentificatie (BIG-REGISTRATIE) / InformatieobjecttypeOmschrijving (Diploma);
  • a CachedZaaktypeCatalog resolves lazily on first use and caches (success only, so a pre-publish miss is retried — no startup ordering coupling);
  • a clear "No published … found" error replaces the opaque placeholder 400.

Design in ADR-0021 (proposed in #117).

Closes #113
Closes #117

Consequences (the payoff)

No stack captures/injects a server-assigned URL any more — docker-compose.yml/.local.yml, run-domain-check.sh and local-seed all drop it; the local acl.env shrinks to a single line.

One thing S-27 can't remove (confirmed empirically during this work): OpenZaak validates the zaaktype field on zaak-create with Django's URLValidator and rejects a single-label host (http://openzaak:8000/…zaaktype: bad-url). So the ACL's base URL must still point at a URL-valid host (a container IP); that base-URL injection from ADR-0020 stays (local acl.env now carries only it; CI keeps ACL_OPENZAAK_BASEURL). ADR-0021 records this.

Definition of Done

  • Linked issues (#113 slice, #117 adr-proposal).
  • TDD — resolver + gateway-lookup unit tests, updated AclService tests (50 unit tests green).
  • Implementation makes them pass; refactor of both compose stacks + verify scripts follows.
  • Conventional Commits referencing #113.
  • CI green — see below.
  • docker compose up reaches green health — verified: fresh make local + make verify-local green with no zaaktype-URL injection; acl.env is base-URL-only.
  • Docs — ADR-0021 + demo-script S-27 note.
  • ADR added (ADR-0021).
  • Demo note appended.

Verification done locally

  • 50 unit tests pass (resolver resolve/cache/retry-on-failure; gateway match/miss/blank-key; all AclService paths).
  • 6 ACL integration tests pass against a live seeded OpenZaak — incl. resolving the zaaktype + Diploma iot by business key, and a clear error for an unknown identificatie.
  • Fresh make local + make verify-local: full flow (submit → werkbak → openbaar) green; acl.env = Acl__OpenZaak__BaseUrl only.
  • make lint clean; ACL mutation ratchet run locally (see checks).

Notes for reviewers

  • IZaakGateway gains two resolve methods; AclService depends on the new IZaaktypeCatalog (singleton, so the cache persists).
  • Supersedes the pinned-URL mechanism; ADR-0021 documents that ADR-0020's seed-env/entrypoint shim are simplified (base-URL only), not deleted, because of the URLValidator constraint above.
## What & why The ACL was handed a **pinned zaaktype URL** (`Acl__Defaults__ZaaktypeUrl`) + informatieobjecttype URL. OpenZaak assigns those UUIDs at creation, so every stack had to seed the catalogus and then capture + inject the resulting URLs out of band (CI's `run-domain-check.sh`; the local `local-seed`→`acl.env` bootstrap from ADR-0020). Brittle, and a stale/placeholder URL failed opaquely (OpenZaak 400). Now **the ACL resolves them itself** from OpenZaak's Catalogi API by stable business key: - config `ZaaktypeIdentificatie` (`BIG-REGISTRATIE`) / `InformatieobjecttypeOmschrijving` (`Diploma`); - a `CachedZaaktypeCatalog` resolves **lazily on first use** and caches (success only, so a pre-publish miss is retried — no startup ordering coupling); - a clear "No published … found" error replaces the opaque placeholder 400. Design in **ADR-0021** (proposed in #117). Closes #113 Closes #117 ## Consequences (the payoff) No stack captures/injects a server-assigned URL any more — `docker-compose.yml`/`.local.yml`, `run-domain-check.sh` and `local-seed` all drop it; the local `acl.env` shrinks to a single line. **One thing S-27 can't remove** (confirmed empirically during this work): OpenZaak validates the `zaaktype` field on zaak-create with Django's URLValidator and **rejects a single-label host** (`http://openzaak:8000/…` → `zaaktype: bad-url`). So the ACL's **base URL** must still point at a URL-valid host (a container IP); that base-URL injection from ADR-0020 stays (local `acl.env` now carries only it; CI keeps `ACL_OPENZAAK_BASEURL`). ADR-0021 records this. ## Definition of Done - [x] Linked issues (#113 slice, #117 adr-proposal). - [x] TDD — resolver + gateway-lookup unit tests, updated `AclService` tests (50 unit tests green). - [x] Implementation makes them pass; refactor of both compose stacks + verify scripts follows. - [x] Conventional Commits referencing #113. - [ ] CI green — see below. - [x] `docker compose up` reaches green health — verified: fresh `make local` + `make verify-local` green with **no zaaktype-URL injection**; `acl.env` is base-URL-only. - [x] Docs — ADR-0021 + demo-script S-27 note. - [x] ADR added (ADR-0021). - [x] Demo note appended. ## Verification done locally - **50 unit tests** pass (resolver resolve/cache/retry-on-failure; gateway match/miss/blank-key; all `AclService` paths). - **6 ACL integration tests** pass against a live seeded OpenZaak — incl. resolving the zaaktype + Diploma iot by business key, and a clear error for an unknown identificatie. - **Fresh `make local` + `make verify-local`**: full flow (submit → werkbak → openbaar) green; `acl.env` = `Acl__OpenZaak__BaseUrl` only. - `make lint` clean; ACL mutation ratchet run locally (see checks). ## Notes for reviewers - `IZaakGateway` gains two resolve methods; `AclService` depends on the new `IZaaktypeCatalog` (singleton, so the cache persists). - Supersedes the pinned-URL mechanism; ADR-0021 documents that ADR-0020's `seed-env`/entrypoint shim are **simplified** (base-URL only), not deleted, because of the URLValidator constraint above.
not added 4 commits 2026-07-22 14:04:23 +00:00
The ACL now discovers its BIG zaaktype (by identificatie) and diploma
informatieobjecttype (by omschrijving) from OpenZaak's Catalogi API, instead of
being handed server-assigned URLs in config. A CachedZaaktypeCatalog resolves
lazily on first use and caches (success only, so a pre-publish miss is retried);
AclDefaults now carries ZaaktypeIdentificatie/InformatieobjecttypeOmschrijving.
Clear errors replace the opaque placeholder-URL 400. Unit tests cover the
resolver (resolve/cache/retry-on-failure) and the gateway lookups (match/miss).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Assert the gateway resolves the published BIG-REGISTRATIE zaaktype + Diploma
informatieobjecttype against a real seeded OpenZaak, and that an unknown
identificatie throws a clear error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The ACL now discovers those URLs itself (S-27), so no stack captures/injects them:
docker-compose.yml/.local.yml carry ZaaktypeIdentificatie/InformatieobjecttypeOmschrijving
instead of placeholder URLs, run-domain-check.sh + local-seed stop emitting the URLs, and
the local acl.env shrinks to the OpenZaak base URL. That base URL injection stays: OpenZaak
rejects a single-label host on zaak-create (confirmed), so the ACL is still pointed at the
container IP. ADR-0021 + demo-script note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test(acl): cover the resolve null/error paths to hold the mutation ratchet (refs #113)
CI / lint (pull_request) Successful in 1m20s
CI / build (pull_request) Failing after 54s
CI / unit (pull_request) Failing after 1m3s
CI / frontend (pull_request) Successful in 2m32s
CI / mutation (pull_request) Successful in 5m39s
CI / verify-stack (pull_request) Successful in 8m11s
2fe187cbdd
Kills the survivors the new resolution code introduced: null Results (no "results"
in the response) must throw "none found" not NRE; a non-success catalogi response
must surface an error naming the resource. ACL mutation score 93.89% (break 90%).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
not added 1 commit 2026-07-22 14:10:34 +00:00
fix(acceptance): implement the resolve API in the in-memory ZGW gateway (refs #113)
CI / frontend (pull_request) Successful in 2m35s
CI / lint (pull_request) Successful in 1m20s
CI / build (pull_request) Successful in 1m1s
CI / unit (pull_request) Successful in 1m10s
CI / mutation (pull_request) Successful in 5m50s
CI / verify-stack (pull_request) Successful in 8m17s
f363cb1663
The acceptance InMemoryZaakGateway now implements IZaakGateway's new
Resolve{Zaaktype,Informatieobjecttype}UrlAsync, and the "een zaak openen" step
configures the ACL by identificatie + points the fake's resolved zaaktype at the
scenario URL — the Release build (which compiles tests/acceptance) failed without
this. All 17 acceptance + 54 ACL unit tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
not merged commit 5de8c1e292 into main 2026-07-22 14:49:27 +00:00
Sign in to join this conversation.