Finishes S-12 · Behandel-portal — werkbak + beoordeling. The backend sub-slices (S-12a/b/c-1/c-2) were merged, but the slice's stated outcome — a behandel portal with medewerker login, a werkbak, and decide — had no frontend. This adds it.
libs/auth: MedewerkerAuthService + provideMedewerkerAuth (Keycloak medewerker realm), a roles/hasRole surface on the shared AuthService, and a realm-roles protocol mapper so the SPA can read behandelaar/teamlead from the token. The BFF remains the security boundary (ADR-0013).
apps/behandel: a new Nx Angular app mirroring self-service — medewerker OIDC login and a werkbak page listing registrations awaiting beoordeling (GET /behandel/werkbak) with per-row Goedkeuren/Afwijzen actions (POST /behandel/registrations/{id}/decide) that refresh the list. NL DS/Utrecht, standalone + signals.
e2e: the walking-skeleton happy path now approves through the real portal (behandelaar logs in, finds the row by reference, clicks Goedkeuren) instead of the temporary admin endpoint.
infra/docs: behandel service in compose (:8142, depends on Keycloak); added to the smoke WAIT_SVCS + CI log dump; frontend-decisions.md and demo-script.md updated.
Implementation makes the test pass; refactor commit if structure improved.
Conventional Commits referencing the issue (refs #13).
CI green — all Gitea Actions jobs.
docker compose up from a fresh clone reaches green health checks within 3 minutes. (behandel image + container verified locally; full stack gated in CI.)
Docs updated if behaviour, contracts, or operations changed.
ADR added — ADR-0013 (merged with the backend sub-slices) already covers the wiring; no new decision here.
Demo note in docs/demo-script.md.
Notes for reviewers
Verified locally: auth + behandel + all frontend projects pass lint & unit tests (incl. axe WCAG 2.1 AA); production build green; the behandel Docker image builds and serves with the correct baked medewerker config + SPA fallback.
The full compose-up smoke, e2e, and mutation are CI-gated (known local full-stack verify limits).
Follow-ups (not in scope): the WerkbakItem contract has no citizen name (werkbak shows the BSN) — adding one is a BFF+domain contract change; and the domain's temporary admin approve endpoint is now unused by the e2e and could be removed.
## What & why
Finishes **S-12 · Behandel-portal — werkbak + beoordeling**. The backend sub-slices (S-12a/b/c-1/c-2) were merged, but the slice's stated outcome — a behandel *portal* with medewerker login, a werkbak, and decide — had no frontend. This adds it.
- **`libs/auth`**: `MedewerkerAuthService` + `provideMedewerkerAuth` (Keycloak `medewerker` realm), a `roles`/`hasRole` surface on the shared `AuthService`, and a realm-roles protocol mapper so the SPA can read `behandelaar`/`teamlead` from the token. The BFF remains the security boundary (ADR-0013).
- **`apps/behandel`**: a new Nx Angular app mirroring self-service — medewerker OIDC login and a **werkbak** page listing registrations awaiting beoordeling (`GET /behandel/werkbak`) with per-row **Goedkeuren/Afwijzen** actions (`POST /behandel/registrations/{id}/decide`) that refresh the list. NL DS/Utrecht, standalone + signals.
- **e2e**: the walking-skeleton happy path now approves through the real portal (behandelaar logs in, finds the row by reference, clicks Goedkeuren) instead of the temporary admin endpoint.
- **infra/docs**: behandel service in compose (`:8142`, depends on Keycloak); added to the smoke `WAIT_SVCS` + CI log dump; `frontend-decisions.md` and `demo-script.md` updated.
Closes #13
## Definition of Done
- [x] Linked Gitea issue (above).
- [x] Failing test committed before the implementation.
- [x] Implementation makes the test pass; refactor commit if structure improved.
- [x] Conventional Commits referencing the issue (`refs #13`).
- [x] CI green — all Gitea Actions jobs.
- [x] `docker compose up` from a fresh clone reaches green health checks within 3 minutes. *(behandel image + container verified locally; full stack gated in CI.)*
- [x] Docs updated if behaviour, contracts, or operations changed.
- [x] ADR added — ADR-0013 (merged with the backend sub-slices) already covers the wiring; no new decision here.
- [x] Demo note in `docs/demo-script.md`.
## Notes for reviewers
- Verified locally: auth + behandel + all frontend projects pass lint & unit tests (incl. axe WCAG 2.1 AA); production build green; the behandel Docker image builds and serves with the correct baked `medewerker` config + SPA fallback.
- The full compose-up smoke, e2e, and mutation are CI-gated (known local full-stack verify limits).
- **Follow-ups (not in scope):** the `WerkbakItem` contract has no citizen name (werkbak shows the BSN) — adding one is a BFF+domain contract change; and the domain's temporary admin `approve` endpoint is now unused by the e2e and could be removed.
The behandel-portal authenticates staff against the Keycloak `medewerker` realm. Add
MedewerkerAuthService (reads nested realm_access.roles), provideMedewerkerAuth, a roles/hasRole
surface on the shared AuthService, and a realm-roles protocol mapper so the frontend can read
the behandelaar/teamlead roles from the token. Per ADR-0013 the BFF remains the security boundary.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drives the behandel-portal frontend: the werkbak lists registrations awaiting beoordeling, a
decision (goedkeuren/afwijzen) posts to the BFF and refreshes, an empty werkbak and a load
failure are surfaced, the page is WCAG 2.1 AA clean, and the medewerker token attaches to the
relative /behandel/ calls (and not to the anonymous openbaar register).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Scaffold apps/behandel (mirrors self-service): medewerker-realm OIDC login, the werkbak page
listing registrations awaiting beoordeling (GET /behandel/werkbak) with goedkeuren/afwijzen
actions (POST /behandel/registrations/{id}/decide) that refresh the list, plus Dockerfile and
same-origin nginx reverse proxy for /behandel/ (ADR-0013; S-12).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The walking-skeleton happy path now drives the real S-12 flow: after submit, a behandelaar logs
in to the behandel portal (medewerker realm), finds the registration in the werkbak by its
reference, and clicks Goedkeuren — replacing the temporary domain admin endpoint. Treat the
behandel origin as secure too, for its PKCE login.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the behandel service (:8142, nginx → BFF, depends on Keycloak for the medewerker realm) to
docker-compose, add it to the smoke's WAIT_SVCS and the CI failure-log dump.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The happy path clicked Goedkeuren and immediately navigated to the openbaar register, which
cancelled the in-flight POST /behandel/registrations/{id}/decide (nginx 499) — the decision
never reached the domain, so the registration stayed INGEDIEND and the final INGESCHREVEN
assertion failed. Wait for the decide response (204) before navigating away.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
not
merged commit 3abf8f7ccf into main2026-07-16 08:31:58 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What & why
Finishes S-12 · Behandel-portal — werkbak + beoordeling. The backend sub-slices (S-12a/b/c-1/c-2) were merged, but the slice's stated outcome — a behandel portal with medewerker login, a werkbak, and decide — had no frontend. This adds it.
libs/auth:MedewerkerAuthService+provideMedewerkerAuth(Keycloakmedewerkerrealm), aroles/hasRolesurface on the sharedAuthService, and a realm-roles protocol mapper so the SPA can readbehandelaar/teamleadfrom the token. The BFF remains the security boundary (ADR-0013).apps/behandel: a new Nx Angular app mirroring self-service — medewerker OIDC login and a werkbak page listing registrations awaiting beoordeling (GET /behandel/werkbak) with per-row Goedkeuren/Afwijzen actions (POST /behandel/registrations/{id}/decide) that refresh the list. NL DS/Utrecht, standalone + signals.:8142, depends on Keycloak); added to the smokeWAIT_SVCS+ CI log dump;frontend-decisions.mdanddemo-script.mdupdated.Closes #13
Definition of Done
refs #13).docker compose upfrom a fresh clone reaches green health checks within 3 minutes. (behandel image + container verified locally; full stack gated in CI.)docs/demo-script.md.Notes for reviewers
medewerkerconfig + SPA fallback.WerkbakItemcontract has no citizen name (werkbak shows the BSN) — adding one is a BFF+domain contract change; and the domain's temporary adminapproveendpoint is now unused by the e2e and could be removed.Scaffold apps/behandel (mirrors self-service): medewerker-realm OIDC login, the werkbak page listing registrations awaiting beoordeling (GET /behandel/werkbak) with goedkeuren/afwijzen actions (POST /behandel/registrations/{id}/decide) that refresh the list, plus Dockerfile and same-origin nginx reverse proxy for /behandel/ (ADR-0013; S-12). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>The happy path clicked Goedkeuren and immediately navigated to the openbaar register, which cancelled the in-flight POST /behandel/registrations/{id}/decide (nginx 499) — the decision never reached the domain, so the registration stayed INGEDIEND and the final INGESCHREVEN assertion failed. Wait for the decide response (204) before navigating away. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>