Behandelportal: monorepo merge + WP-64..67 backoffice arc (OpenZaak write closes it out) #1

Merged
eho merged 8 commits from monorepo-behandelportal into main 2026-08-04 12:56:34 +00:00
8 Commits
Author SHA1 Message Date
ehoandClaude Sonnet 5 a2e301060e docs: record WP-66 commit hash
CI / changes (pull_request) Successful in 18s
CI / lint (pull_request) Successful in 1m9s
CI / frontend (pull_request) Successful in 3m28s
CI / backend (pull_request) Successful in 2m59s
CI / e2e (pull_request) Successful in 4m33s
CI / semgrep (pull_request) Successful in 1m23s
CI / api-client-drift (pull_request) Successful in 2m25s
CI / storybook-a11y (pull_request) Successful in 14m48s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 09:41:38 +02:00
ehoandClaude Sonnet 5 d996ca2463 feat(behandelportal): WP-66 wire the decision into OpenZaak
Extends IZaakSource with RecordBesluit, mirroring WP-50's CreateZaak write
pattern: OpenZaakZaakSource POSTs a new Statussen entry (highest-volgnummer
statustype, since the harness catalogus has no per-outcome besluittype),
carrying the besluit + toelichting in statustoelichting; LocalZaakSource
no-ops. The beoordeling endpoint calls it after the local decision commits,
flagging a failure via RecordZgwDivergence the same way submit's
create-zaak/document writes do — closing WP-60's "second write pair" gap.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 09:41:28 +02:00
ehoandClaude Sonnet 5 39409bdf76 ci: fix test-storybook config-dir + add missing behandelportal a11y coverage
CI / changes (pull_request) Successful in 17s
CI / lint (pull_request) Successful in 56s
CI / frontend (pull_request) Successful in 2m31s
CI / backend (pull_request) Successful in 1m57s
CI / e2e (pull_request) Successful in 3m32s
CI / semgrep (pull_request) Successful in 1m13s
CI / api-client-drift (pull_request) Successful in 2m2s
CI / storybook-a11y (pull_request) Successful in 11m42s
WP-67's monorepo split renamed .storybook to .storybook-ssp/
.storybook-behandelportal, but test-storybook still defaulted to the
(now nonexistent) plain .storybook dir -- it loads <config-dir>/main.js
for test-runner hooks even in --url mode, so every invocation failed
with "Could not load main.js in .storybook".

Also: test-storybook:ci only ever built+served+tested the ssp instance.
Since the split, behandelportal's stories (werkvoorraad, beoordeling,
besluit-form, ...) were never axe-tested in CI at all. Added the
:behandelportal siblings (mirroring the existing storybook/
build-storybook naming) and wired them into ci-local.sh's --full step
and the storybook-a11y GitHub Actions job.

Verified directly: ssp 62/180 stories green, behandelportal 45/112
green (including the new besluit-form story), full `ci-local.sh --full`
green end-to-end.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 10:24:49 +02:00
ehoandClaude Sonnet 5 6c6bef45f3 docs: fix stale WP-65 status in backlog README, closing the format:check gap
CI / changes (pull_request) Successful in 16s
CI / lint (pull_request) Successful in 54s
CI / frontend (pull_request) Successful in 2m27s
CI / storybook-a11y (pull_request) Failing after 3m16s
CI / backend (pull_request) Successful in 1m53s
CI / semgrep (pull_request) Successful in 1m7s
CI / e2e (pull_request) Successful in 2m45s
CI / api-client-drift (pull_request) Successful in 1m57s
WP-65's summary-table row still said "in progress (65a done)" from before
65b shipped, and that one oversized cell was forcing prettier to want to
re-pad the entire ~65-row table. Correcting it to "done" (its actual
status, per the WP-65 file's own outcome notes) removes the outlier —
npm run format:check is green again with zero other rows touched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 09:52:34 +02:00
ehoandClaude Sonnet 5 af8a011819 feat(behandelportal): WP-65b beoordeling besluit (decision write)
CI / changes (pull_request) Successful in 17s
CI / lint (pull_request) Failing after 56s
CI / frontend (pull_request) Successful in 2m36s
CI / storybook-a11y (pull_request) Failing after 3m19s
CI / backend (pull_request) Failing after 1m55s
CI / api-client-drift (pull_request) Canceled after 0s
CI / e2e (pull_request) Canceled after 40s
CI / semgrep (pull_request) Canceled after 24s
Adds POST /beoordeling/{id}/besluit: a Besluit enum (Goedkeuren/Afwijzen/
MeerInfoOpvragen) backed by new Aanvraag.BesluitStatus/BesluitToelichting
columns, gated by the same BeoordelingRules.CanDecide the read side's
canBesluiten flag already uses (409 on an illegal transition, 400 on a
missing required toelichting). Mappers.ToStatusDto gains the "a recorded
decision wins" branch. FE: besluit.machine.ts + besluit-form organism
(same form idiom as change-request-form), wired into the beoordeling page
behind the server's canBesluiten flag.

Completes WP-65 (65a + 65b) — verified end-to-end against a running
backend (werkvoorraad -> beoordeling -> besluit -> status reflected back).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 09:46:20 +02:00
ehoandClaude Sonnet 5 4133b30e5d feat(behandelportal): WP-65a beoordeling detail (read) + fix unreachable medewerker login
CI / changes (pull_request) Successful in 17s
CI / lint (pull_request) Failing after 54s
CI / frontend (pull_request) Successful in 2m38s
CI / storybook-a11y (pull_request) Failing after 3m28s
CI / backend (pull_request) Successful in 2m1s
CI / semgrep (pull_request) Successful in 1m9s
CI / e2e (pull_request) Successful in 2m55s
CI / api-client-drift (pull_request) Successful in 2m1s
New GET /beoordeling/{id} shows one aanvraag's status, linked documents, and a
canBesluiten decision flag, gated by the same CanBeoordelen capability as the
werkvoorraad list. Reads through IZaakSource.ListCases rather than a new seam
method (WP-66 needs one anyway for the real write); owner BSN is masked.

Fixes a real gap found while wiring this up: the behandelportal's login was still
WP-61's copied citizen/BSN DigiD flow, so nothing ever sent X-Medewerker and the
werkvoorraad screen (WP-64) always denied in a real browser. A dev-only
medewerkerInterceptor (mirrors the existing ?role= stand-in as ?rollen=) fixes that.

WP-65's own Risks note authorized splitting read from write across sessions given
its size; this is the read half. The decision-recording mutation is next (65b).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 09:01:09 +02:00
ehoandClaude Sonnet 5 fe69caee63 feat(behandelportal): WP-64 werkvoorraad (queue) screen
CI / changes (pull_request) Successful in 15s
CI / lint (pull_request) Successful in 57s
CI / frontend (pull_request) Successful in 2m36s
CI / storybook-a11y (pull_request) Failing after 3m14s
CI / backend (pull_request) Successful in 2m1s
CI / semgrep (pull_request) Successful in 1m10s
CI / e2e (pull_request) Successful in 3m3s
CI / api-client-drift (pull_request) Successful in 2m1s
New GET /werkvoorraad endpoint lists aanvragen still open (Ingediend/InBehandeling),
gated by the medewerker capability (CanBeoordelen) rather than the admin role — reuses
the existing ApplicationSummaryDto, no new DTO. GET /me now surfaces aanvraag:beoordelen
for a behandelaar so the FE can gate with the same AccessStore/capabilityGuard idiom
every other page uses.

FE: a behandeling domain type deliberately narrower than ssp's full AanvraagStatus
union (only the two open tags — illegal states unrepresentable), composed into a
werkvoorraad-list organism from existing shared/ui molecules. Replaces WP-61's
scaffold placeholder as the app's real landing page.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 22:02:35 +02:00
ehoandClaude Sonnet 5 e7156c5132 feat(WP-67): merge behandelportal into this repo as a monorepo
Restructures into apps/ssp + apps/behandelportal (two Angular projects)
plus libs/shared + libs/beheer (cross-app libraries), replacing WP-61's
separate sibling repo. That split had already produced real drift: a
hand-vendored copy of the backend's OpenAPI doc, a shared/ui+layout tree
forked and silently diverging (7 files), and beheer + the styles.scss
token bridge duplicated byte-for-byte across both repos.

- git mv the SSP's src/app/* into apps/ssp/; fold shared/, beheer/,
  environments/, the Storybook docs/*.mdx, and styles.scss into
  libs/shared + libs/beheer (all confirmed identical between the two
  repos before merging). auth stays deliberately duplicated per
  ADR-0002 (actor-specific, expected to diverge) - amended there.
- One generated API client (libs/shared), no more vendored swagger.json.
- .dependency-cruiser split into a base factory + one config per app,
  and Storybook into .storybook-ssp/.storybook-behandelportal - both
  forced by the @auth/* alias resolving to different directories per app.
- SiteHeaderComponent/ShellComponent gained HEADER_NAV_ITEMS/
  HEADER_ADMIN_LINKS/DEBUG_PANEL injection tokens so each app supplies
  its own nav/admin-links/dev-panel instead of one being hardcoded.
- CLAUDE.md, ARCHITECTURE.md, dependencies.md, and ADR-0002 updated;
  WP-67 backlog entry documents the full decision trail.

npm run ci green (lint, dep:check x2, 360 tests across ssp/
behandelportal/shared/beheer, both localized builds, backend tests,
snippet + api-client drift); both dev servers, both Storybook
instances, and docker compose verified working.

The old sibling repo (/home/eho/repos/behandelportal) is left
untouched, not deleted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 21:01:57 +02:00