Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.8 KiB
Demo script
A running log of demoable outcomes, one section per slice. Each entry is a short,
copy-pasteable walkthrough against a local make up stack.
S-08c — Self-service submit form (NL Design System + DigiD)
Outcome: a zorgprofessional logs in via mock DigiD and submits a BIG registration through the self-service portal (NL Design System styling); the page confirms with the reference returned by the BFF. The bsn comes from the DigiD token, so it's a confirm-and-submit flow (no bsn field).
# 1. Bring the backend + Keycloak up (BFF on :8080, Keycloak on :8180).
make up
# 2. Serve the portal (dev server); it redirects to Keycloak for DigiD login.
pnpm nx serve self-service # → http://localhost:4200
# 3. In the browser: log in as the mock DigiD user jan-burger / test123, then submit.
# The page shows the returned registration reference.
First real UI. The full login → submit → success happy path is automated in S-08d (Playwright, against the compose-served app). Component tests + an axe WCAG 2.1 AA check on the submit page run headless in the
frontendCI lane. Seedocs/frontend-decisions.md.
S-08a — Nx workspace + self-service portal skeleton
Outcome: the frontend foundation — an Nx (pnpm) monorepo with the self-service Angular app
(standalone + signals), lint/test/build green in a CI Node lane. The login + submit form follow in
S-08c.
# From a fresh clone (Node 24 + pnpm 11):
pnpm install # native builds are pre-approved in pnpm-workspace.yaml
pnpm nx test self-service # Vitest component test
pnpm nx build self-service # production build
pnpm nx serve self-service # → http://localhost:4200 (placeholder page)
# Or the CI-equivalent one-shot:
make frontend # install + nx lint/test/build
Nx manages only
apps/+libs/; the .NET services stay ondotnet/the Makefile. NL Design System and the real form arrive in S-08c (#67); seedocs/frontend-decisions.md.
S-07 — BFF: the portals' single backend
Outcome: the BFF validates Keycloak digid tokens on the self-service submit (forwarding the
bsn to the domain) and serves the openbaar register anonymously with only public-safe fields — the
front door the portals (S-08/S-09) will talk to.
The path: portal → BFF POST /self-service/registrations (token-gated) → domain; and
BFF GET /openbaar/register (anonymous) → projection-api. See ADR-0010.
# 1. Bring the full stack up.
make up
# 2. Drive the BFF end-to-end (401 without a token, 202 with a real digid token, anonymous openbaar).
make verify-bff # → "OK — BFF: 401 without token, 202 with a digid token, anonymous ..."
# 3. Try it by hand (BFF on host port 8080).
# a) A digid access token for the mock user jan-burger (bsn 123456782):
tok=$(curl -s -X POST http://localhost:8180/realms/digid/protocol/openid-connect/token \
-d grant_type=password -d client_id=big-portal -d username=jan-burger -d password=test123 \
| python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")
# b) Submit — without the token it is 401; with it, 202:
curl -s -o /dev/null -w "no token -> %{http_code}\n" -X POST http://localhost:8080/self-service/registrations
curl -s -o /dev/null -w "with token-> %{http_code}\n" -X POST http://localhost:8080/self-service/registrations \
-H "Authorization: Bearer $tok"
# c) The openbaar register is anonymous and exposes only id + status (never the bsn):
curl -fsS http://localhost:8080/openbaar/register | jq
The self-service token is validated against Keycloak's
digidrealm; the openbaar lookup needs no token (S-09). The generated contract lives atservices/bff/openapi.json— S-08's client is built from it.
S-05 — BIG Domain Service: submit a registration
Outcome: submitting a registration starts a Flowable process; the external-task worker opens a zaak via the ACL and records it on the aggregate — the upstream half of the skeleton that produces the zaak S-06 then projects.
The path: domain POST /registrations → Flowable registratie process → OpenZaakAanmaken
worker → ACL → OpenZaak; GET /registrations/{id} shows the opened zaak (ADR-0009).
# 1. Bring the full stack up (seeds config, builds our services, waits for health).
make up
# 2. Drive the full path end-to-end. This also seeds a published BIG zaaktype and points the
# ACL at it (the zaak's zaaktype URL is server-assigned, so it isn't known at bring-up).
make verify-domain # → "OK — the domain opened a zaak and recorded it on the registration"
# 3. Submit one yourself (domain on host port 8130). Returns 202 + a Location to read back.
loc=$(curl -fsS -D - -o /dev/null -X POST http://localhost:8130/registrations \
-H 'Content-Type: application/json' -d '{"bsn":"123456782"}' | sed -n 's/\r$//; s/^[Ll]ocation: //p')
# 4. The worker opens the zaak off the request path (eventual consistency, ADR-0009); poll
# until zaakUrl is filled. (Step 2 must have run first, so the ACL knows the zaaktype.)
curl -fsS "http://localhost:8130$loc" | jq
# → { "registrationId": "...", "status": "Ingediend", "zaakUrl": "http://.../zaken/api/v1/zaken/<uuid>" }
Registration state is in-memory for this slice (ADR-0009); the rebuildable read model is the projection (S-06), fed by the very zaak this flow opens.
S-06 — Event Subscriber + read projection
Outcome: a zaak created in OpenZaak flows through NRC to the Event Subscriber, which projects it into a rebuildable read projection the projection-api serves.
The path: OpenZaak → (notification) NRC → (abonnement callback) Event Subscriber →
register_projection → projection-api GET /register.
# 1. Bring the full stack up (seeds config, builds our services, waits for health).
make up
# 2. Register the Event Subscriber's abonnement and create a zaak, then read it back.
# (The verify-projection check does exactly this end-to-end and asserts the result.)
make verify-projection # → "OK — projection-api serves zaak <uuid> with status INGEDIEND"
# 3. Observe the projection directly via the read API (host port 8120).
curl -fsS http://localhost:8120/register | jq
# → [ { "id": "<zaak-uuid>", "status": "INGEDIEND", "bsn": null, "naamPlaceholder": null } ]
# 4. Idempotency + rebuild: replays don't duplicate; a rebuild repopulates from the
# notification log (no OpenZaak access needed — ADR-0008).
curl -fsS -X POST http://localhost:8110/admin/rebuild # Event Subscriber, host port 8110
curl -fsS http://localhost:8120/register | jq 'length' # → unchanged
bsn/naam_placeholderare deferred (ADR-0008) — the notification doesn't carry them and the subscriber may not read OpenZaak directly (§8.1). They surface in a later slice.