docs(infra): ADR-0020 + demo note for the local-stack self-seed (refs #110)
CI / lint (pull_request) Successful in 1m19s
CI / build (pull_request) Successful in 56s
CI / unit (pull_request) Successful in 1m6s
CI / frontend (pull_request) Successful in 2m31s
CI / mutation (pull_request) Successful in 6m0s
CI / verify-stack (pull_request) Failing after 10m33s
CI / lint (pull_request) Successful in 1m19s
CI / build (pull_request) Successful in 56s
CI / unit (pull_request) Successful in 1m6s
CI / frontend (pull_request) Successful in 2m31s
CI / mutation (pull_request) Successful in 6m0s
CI / verify-stack (pull_request) Failing after 10m33s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
|||||||
|
# ADR-0020: The local stack self-seeds the zaaktype, DMN, and NRC abonnement at bring-up
|
||||||
|
|
||||||
|
- **Status:** Accepted
|
||||||
|
- **Date:** 2026-07-22
|
||||||
|
- **Deciders:** Respellion engineering
|
||||||
|
- **Relates to:** S-B04 (#110). Local-stack twin of the seeding the verify-* scripts do for CI
|
||||||
|
(`infra/run-domain-check.sh`, `infra/verify-notification-driver.py`). Superseded in part by S-27
|
||||||
|
(#113), which would let the ACL resolve its zaaktype by identificatie and remove the URL injection.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
`infra/docker-compose.local.yml` is the host-browser-friendly stack (`make local`) — the one a
|
||||||
|
developer clicks through the portals with. It had drifted behind three slices, so a fresh bring-up
|
||||||
|
could not complete the flow:
|
||||||
|
|
||||||
|
1. The ACL pointed at a placeholder zaaktype (`…/00000000-…`), so zaak creation failed with OpenZaak
|
||||||
|
`400` and the registratie process stuck at `OpenZaakAanmaken` (S-05).
|
||||||
|
2. `flowable-init` deployed only `registratie.bpmn`, not `diploma-eligibility.dmn`, so completing
|
||||||
|
`WachtOpDocumenten` 404'd on the missing decision and never reached `Beoordelen` (S-10a/S-13).
|
||||||
|
3. No NRC abonnement was registered, so notifications reached NRC and went nowhere — the projection
|
||||||
|
and the openbaar register stayed empty (S-06).
|
||||||
|
|
||||||
|
The CI stack (`infra/docker-compose.yml`) does not hit this because its `verify-*` scripts seed the
|
||||||
|
zaaktype, deploy the DMN, and register the abonnement at *test* time. The local stack has no such
|
||||||
|
harness — a developer just runs `make local` and browses. The non-obvious wrinkle is (1): the
|
||||||
|
zaaktype **UUID is assigned by OpenZaak at creation**, so the ACL's zaaktype URL is not knowable when
|
||||||
|
the compose file is written and cannot be a static value.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
**Make the local stack self-seed at bring-up via one-shot init containers, and hand the ACL its
|
||||||
|
server-assigned zaaktype URL through a shared-volume env file it sources on startup.**
|
||||||
|
|
||||||
|
- **DMN (gap 2).** `flowable-init` now deploys `diploma-eligibility.dmn` to the DMN engine
|
||||||
|
(`/flowable-rest/dmn-api/dmn-repository/deployments`) as a separate deployment alongside the BPMN —
|
||||||
|
identical to the CI `flowable-init`. Idempotent.
|
||||||
|
- **Zaaktype + ACL wiring (gap 1).** A `local-seed` one-shot runs the existing
|
||||||
|
`infra/openzaak/seed_catalogus.py` (`OZ_PUBLISH=1`) against OpenZaak and writes the resulting
|
||||||
|
`Acl__Defaults__ZaaktypeUrl` / `…InformatieobjecttypeUrl` / `Acl__OpenZaak__BaseUrl` into
|
||||||
|
`seed-env:/out/acl.env`. The ACL mounts that volume read-only and overrides its entrypoint to
|
||||||
|
`sh -c 'set -a; . /seed/acl.env; set +a; exec dotnet Acl.Api.dll'`, so the real values override the
|
||||||
|
compose placeholders before the app reads config. The ACL `depends_on: local-seed
|
||||||
|
(service_completed_successfully)`.
|
||||||
|
- **Abonnement (gap 3).** A `nrc-subscribe` one-shot registers an abonnement on the `zaken` kanaal
|
||||||
|
pointing at the event-subscriber's `/notifications` callback (`infra/local/register-abonnement.py`).
|
||||||
|
It is a leaf — nothing depends on it — so it can wait for the event-subscriber without forming a
|
||||||
|
cycle with the ACL bootstrap.
|
||||||
|
- **Reach OpenZaak/NRC by container IP, not service name.** Both the seed's ZTC calls and the
|
||||||
|
abonnement's `callbackUrl` are validated by Django's URLValidator, which rejects a single-label host
|
||||||
|
like `openzaak` / `event-subscriber`. The scripts resolve the target's container IP at runtime (as
|
||||||
|
`infra/run-domain-check.sh` does), keeping the seeded URLs valid **and** host-consistent — the ACL's
|
||||||
|
base URL is set to the same OpenZaak IP that owns the zaaktype URL.
|
||||||
|
- **Acceptance.** `make verify-local` (`infra/run-local-flow-check.sh`) submits against a fresh stack
|
||||||
|
and asserts the zaak opens, the case reaches the werkbak after documents, and the reference appears
|
||||||
|
in the openbaar register — the red-to-green test for all three gaps.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
**Positive**
|
||||||
|
|
||||||
|
- A fresh `make local` completes the full demo (submit → werkbak → openbaar) with no manual seeding —
|
||||||
|
the slice's stated outcome.
|
||||||
|
- Reuses the proven CI mechanisms (`seed_catalogus.py`, the DMN deploy, the abonnement driver) rather
|
||||||
|
than inventing new ones; the only genuinely new piece is the entrypoint-sourced env file.
|
||||||
|
- No service code changes — the fix is entirely in `infra/` (compose + two small scripts), so the ACL
|
||||||
|
image and the CI stack are untouched.
|
||||||
|
|
||||||
|
**Negative / costs**
|
||||||
|
|
||||||
|
- The two compose files diverge further: the CI stack seeds at test time, the local stack at bring-up.
|
||||||
|
Mitigated by reusing the same underlying scripts and cross-referencing them.
|
||||||
|
- The ACL entrypoint override couples the local ACL to the seed-written file path (`/seed/acl.env`);
|
||||||
|
if the seed fails, the ACL fails to start (loud, healthcheck-visible — preferred over silently
|
||||||
|
running with a placeholder).
|
||||||
|
- Container-IP-based URLs are re-derived on each bring-up; a keep-volumes restart with a changed
|
||||||
|
OpenZaak IP relies on OpenZaak rebuilding hyperlinked URLs from the request host (it does) so the
|
||||||
|
idempotent re-seed reports current-IP URLs.
|
||||||
|
|
||||||
|
## Alternatives considered
|
||||||
|
|
||||||
|
- **ACL resolves its zaaktype by identificatie (`BIG-REGISTRATIE`) at startup.** The cleaner,
|
||||||
|
less-brittle design — no server-assigned URL to capture — and it would help the CI stack too. But it
|
||||||
|
changes a service's runtime behaviour and its config contract, needs new ACL tests + mutation
|
||||||
|
coverage, and still needs a seed step to *create* the zaaktype. Deliberately split out as its own
|
||||||
|
slice with its own ADR (S-27 / #113) rather than folded into this infra-only fix.
|
||||||
|
- **A documented `make local-seed` step run after `make local`.** Smallest change, but it fails the
|
||||||
|
slice's "no manual seeding" outcome — the local stack is exactly the one meant to just work in a
|
||||||
|
browser. Rejected.
|
||||||
|
- **Fixed zaaktype UUID via OpenZaak `setup_configuration`/fixtures.** OpenZaak assigns UUIDs on POST;
|
||||||
|
declaratively creating a fully *published* zaaktype (statustypen + resultaattypen validated against
|
||||||
|
the Selectielijst + roltypen + iot relations) is not something `setup_configuration` supports
|
||||||
|
cleanly in 1.28.2. Rejected as more fragile than reusing `seed_catalogus.py`.
|
||||||
@@ -5,6 +5,33 @@ copy-pasteable walkthrough against a local `make up` stack.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## S-B04 — `make local` completes the whole flow with no manual seeding (#110, ADR-0020)
|
||||||
|
|
||||||
|
**Outcome:** the host-browser stack (`make local`) now self-seeds at bring-up — it publishes the BIG
|
||||||
|
zaaktype and wires the ACL to it, deploys the `diploma-eligibility` DMN, and registers the NRC
|
||||||
|
abonnement — so a fresh bring-up runs submit → werkbak → openbaar without the manual seeding the
|
||||||
|
`verify-*` scripts do for CI. (Previously the process stuck at `OpenZaakAanmaken`, the werkbak stayed
|
||||||
|
empty, and the openbaar register showed nothing.)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Fresh bring-up (self-seeding init containers: local-seed, nrc-subscribe; DMN in flowable-init).
|
||||||
|
make local
|
||||||
|
|
||||||
|
# 2. Assert the whole flow works with no manual seeding — submit opens a zaak, documents route it to
|
||||||
|
# the werkbak, and the reference appears in the openbaar register:
|
||||||
|
make verify-local # → "OK — a fresh local stack completed the flow with no manual seeding ..."
|
||||||
|
|
||||||
|
# 3. Or by hand in the browser: log in at http://localhost:8140 (jan-burger / test123), submit +
|
||||||
|
# upload a PDF, then approve it in the werkbak at http://localhost:8142 (merel-behandelaar /
|
||||||
|
# test123); it shows as INGESCHREVEN in the openbaar register at http://localhost:8141.
|
||||||
|
```
|
||||||
|
|
||||||
|
> The zaaktype UUID is server-assigned, so `local-seed` writes the real URL into a shared volume as
|
||||||
|
> `acl.env` and the ACL sources it on startup (ADR-0020). The cleaner long-term fix — the ACL
|
||||||
|
> resolving its zaaktype by `identificatie` — is tracked separately as S-27 (#113).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## S-08d — Walking skeleton complete: browser → submit, end-to-end
|
## S-08d — Walking skeleton complete: browser → submit, end-to-end
|
||||||
|
|
||||||
**Outcome:** the self-service portal is served in the stack and the full front-of-house happy path
|
**Outcome:** the self-service portal is served in the stack and the full front-of-house happy path
|
||||||
|
|||||||
Reference in New Issue
Block a user