# WP-64 — Behandelportal: werkvoorraad (queue) screen Status: done Phase: 11 — Behandelportal ## Why First real screen in the new app — a read-only list of aanvragen needing treatment (the "werkvoorraad"), gated by the medewerker identity from WP-62 and backed by the real status DTO from WP-63. This is the smallest useful vertical slice of actual case-treatment functionality — usable and demoable on its own, even before any decision can be recorded (WP-65). ## Read first - WP-61/62/63 outcomes - `bff-endpoint` skill (screen-shaped decision DTO recipe) - `src/app/registratie/ui/admin-cases.page.ts` (the existing cross-owner list, for what to avoid repeating — that page is audit/delete, this one is a queue) ## Decisions (pre-made, don't relitigate) - New BFF-lite endpoint (decision-enriched DTO) shaped for a werkvoorraad screen — not a reuse of the existing `/admin/cases` endpoint, which is audit-shaped, not queue-shaped (per CLAUDE.md's per-screen endpoint discipline). - Gated by the `canBeoordelen`-style capability from WP-62, not a new ad hoc role check. - Domain first, then infrastructure, application, UI — per the house `new-feature` recipe. ## Files New backend endpoint + DTO in `BigRegister.Api`; new `behandeling` context in the behandelportal app (domain/infrastructure/application/ui per the house layering). ## Steps 1. Backend: new screen-shaped endpoint returning aanvragen needing treatment (status = `InBehandeling`/`Ingediend`), gated by WP-62's capability. 2. FE: scaffold the `behandeling` context (domain → infrastructure → application → ui), following `new-feature`. 3. UI: a list page (queue), composed from the shared `shared/ui` kernel — no new atoms unless nothing existing fits. 4. Storybook story for the new list component/page, a11y-checked. ## Acceptance criteria - [x] Werkvoorraad screen lists aanvragen needing treatment for an authenticated medewerker. - [x] `npm run ci` green in the behandelportal app; Storybook story present. - [x] Endpoint follows BFF-lite discipline (decision-enriched, not raw passthrough). ## Outcome `GET /werkvoorraad` reuses the existing `ApplicationSummaryDto`/`IZaakSource.ListCases` — no new DTO — filtered server-side to `Status.Tag is "Ingediend" or "InBehandeling"`. Gated by a new `Werkvoorraad` local-function twin of `CasesAdmin`, but checking `Authz.CanBeoordelen(ctx.Caller())` (the CallerIdentity directly) rather than a role-only `Principal` — a zorgverlener with `X-Role=admin` is still denied (covered by a test). One course correction beyond the pre-made decisions: `GET /me` didn't expose any capability a medewerker could hold (`RoleCapabilities` only switches on `PrincipalRole`, which every `MedewerkerCaller` also carries but doesn't determine `CanBeoordelen`). Added one line — `if (Authz.CanBeoordelen(ctx.Caller())) caps.Add("aanvraag:beoordelen")` — and a matching `Capability` union member in `libs/shared`, so the FE page can use the same deny-by-default `AccessStore`/`capabilityGuard` idiom every other gated page uses (avoids a wasted 403 GET and a denial flash), instead of inventing a second gating mechanism. FE: the queue item's domain type (`behandeling/domain/werkvoorraad-item.ts`) is deliberately **narrower** than the SSP's full `AanvraagStatus` union — only `Ingediend`/`InBehandeling` — so a case the backend's filter let through with any other tag is a parse error, not a silently-rendered row. Composed entirely from existing `libs/shared/ui` molecules (`ApplicationListComponent` + `ApplicationLinkComponent`, the same ones ssp's dashboard uses) via one new organism, `WerkvoorraadListComponent` — no new atom. The stopgap `behandeling.page.ts`/`BehandelingPage` (WP-61's scaffold placeholder, its own TODO said to replace it) is gone; `/dashboard` now loads `WerkvoorraadPage` directly, and the redundant `/behandeling` route (same placeholder, two paths) was dropped. ## Verification `npm run ci` in the behandelportal app; `cd backend && dotnet test`; manual: log in as a stub medewerker, see the queue populated from seeded aanvragen. ## Out of scope Viewing a single zaak's detail (WP-65); recording any decision (WP-65). ## Risks None major — this is a read-only composition slice once WP-61-63 exist. Depends on: WP-61, WP-62, WP-63.