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>
This commit is contained in:
@@ -21,7 +21,9 @@ Getting this wrong is expensive: split the code by role and every feature smears
|
||||
|
||||
Confirmed constraints (with the product owner):
|
||||
|
||||
- The backoffice is a **separate frontend application**, own audience, own deployment.
|
||||
- The backoffice is a **separate frontend application** (own audience, own deployable —
|
||||
see the [WP-67 amendment](#amendment-wp-67-2026-08-01-one-repo-not-two) below for where
|
||||
its source actually lives).
|
||||
- The groups **authenticate differently**: Zorgverlener via DigiD/BSN; Behandelaar via employee SSO.
|
||||
- Both act on the **same underlying aggregate** — the aanvraag/registration — but see different views.
|
||||
|
||||
@@ -43,9 +45,11 @@ Confirmed constraints (with the product owner):
|
||||
The same real-world thing is described in two different languages:
|
||||
|
||||
- **Zelfbediening (SSP)** — the Zorgverlener: _"ik vraag herregistratie aan"_ — eligibility, fill in
|
||||
my data, upload documents, submit. **This repo.**
|
||||
my data, upload documents, submit. **`apps/ssp` in this repo** (was "this repo" itself
|
||||
before WP-67 turned it into a monorepo).
|
||||
- **Behandeling (backoffice)** — the Behandelaar: _"ik beoordeel de aanvraag"_ — werkvoorraad,
|
||||
beoordeling, besluit, meer-info-opvragen, SLA, audit. **A sibling application**, not a folder here.
|
||||
beoordeling, besluit, meer-info-opvragen, SLA, audit. **`apps/behandelportal`** — a
|
||||
separate Angular _project_, not a separate _repo_ (see the amendment below).
|
||||
|
||||
Diverging verbs over the same noun is the textbook signal for **two bounded contexts**.
|
||||
|
||||
@@ -60,16 +64,16 @@ contract_ between the two contexts:
|
||||
Ingediend → In behandeling → (Meer info gevraagd ⇄) → Goedgekeurd / Afgewezen
|
||||
```
|
||||
|
||||
The Behandeling context **advances** this lifecycle; the SSP **reads** it. Today the SSP already holds
|
||||
the seed of it — `pendingHerregistratie` in `big-profile.store.ts:53` is the first, coarsest read of
|
||||
that status ("in behandeling"). As the backoffice appears, that single boolean grows into a real
|
||||
status the backend publishes.
|
||||
The Behandeling context **advances** this lifecycle; the SSP **reads** it. WP-63 published the
|
||||
full lifecycle enum backend-side (`AanvraagStatusTag`); the SSP's dashboard `pendingHerregistratie`
|
||||
signal (`big-profile.store.ts`) turned out to be a pure client-side optimistic flag, not a read of
|
||||
any backend field — WP-65 is where a behandelaar action first reaches `Ingediend`/`MeerInfoGevraagd`.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph FE["Frontend bounded contexts (separate apps)"]
|
||||
SSP["<b>Zelfbediening (SSP)</b><br/>Zorgverlener · DigiD/BSN<br/><i>this repo</i>"]
|
||||
BO["<b>Behandeling (backoffice)</b><br/>Behandelaar · employee SSO<br/><i>sibling app</i>"]
|
||||
subgraph FE["Frontend bounded contexts (two Angular projects, one repo — WP-67)"]
|
||||
SSP["<b>Zelfbediening (SSP)</b><br/>Zorgverlener · DigiD/BSN<br/><i>apps/ssp</i>"]
|
||||
BO["<b>Behandeling (backoffice)</b><br/>Behandelaar · employee SSO<br/><i>apps/behandelportal</i>"]
|
||||
end
|
||||
BE["<b>Backend domain</b><br/>aanvraag aggregate (system of record)<br/>status lifecycle · authorization"]
|
||||
SSP -- "reads aanvraag status<br/>(decision DTOs, ADR-0001)" --> BE
|
||||
@@ -115,14 +119,45 @@ not merely a new login.
|
||||
|
||||
## Consequences
|
||||
|
||||
- This repo **stays the pure SSP**. No backoffice code leaks in; no role-named folders appear.
|
||||
- The backoffice ships as a **separate app** against the same backend and the same OpenAPI contract.
|
||||
- `apps/ssp` **stays the pure SSP**. No backoffice code leaks in; no role-named folders appear.
|
||||
- The backoffice ships as a **separate Angular project** (`apps/behandelportal`, WP-67 —
|
||||
originally a separate repo, see the amendment below) against the same backend and the same
|
||||
OpenAPI contract.
|
||||
- The one concrete FE change when actor #2 lands is `Session → Principal` in the `auth` context; the
|
||||
`authGuard`/`SessionStore` seams already localise that (`auth.guard.ts`, `session.store.ts`).
|
||||
- The backend becomes the authority for the **aanvraag status lifecycle** and for **authorization**,
|
||||
publishing both as decision DTOs — a natural extension of ADR-0001, not a new pattern.
|
||||
- `pendingHerregistratie` is understood as a _temporary stand-in_ for a real, backend-owned status.
|
||||
|
||||
## Amendment (WP-67, 2026-08-01): one repo, not two
|
||||
|
||||
WP-61 initially built `apps/behandelportal` as a **separate sibling repo**
|
||||
(`/home/eho/repos/behandelportal`), taking this ADR's "separate frontend application" literally
|
||||
as "separate git repository." That produced real friction WP-67 then undid: a hand-vendored,
|
||||
manually-kept-in-sync copy of the backend's OpenAPI doc instead of a live-generated one, a
|
||||
`shared/ui`+`shared/layout` tree forked at WP-61 and already silently diverging by the time
|
||||
WP-67 checked (7 files), a `beheer` (admin/stamdata) context and `styles.scss` token bridge
|
||||
duplicated byte-for-byte across both repos, and a second CI/lint/CLAUDE.md to hand-maintain.
|
||||
|
||||
**The bounded-context reasoning above is unchanged** — it never depended on repo count. What
|
||||
changes is purely the _packaging_:
|
||||
|
||||
- Two Angular CLI projects in one workspace: `apps/ssp`, `apps/behandelportal` — each still
|
||||
its own deployable, its own `angular.json` build/serve/test targets, its own port.
|
||||
- `libs/shared` (design system + kernel + the one generated API client) and `libs/beheer`
|
||||
(admin/stamdata — genuinely identical for both apps, not actor-specific) are cross-app
|
||||
libraries. `auth` stays **duplicated**, not unified — per §3 above, it's expected to diverge
|
||||
(Zorgverlener DigiD/BSN vs. Behandelaar employee SSO), so unifying it now would be forcing
|
||||
today's accidental similarity into a shape that fights tomorrow's real difference.
|
||||
- One backend, one OpenAPI doc, one generated client — the vendored-swagger workaround is
|
||||
gone; `npm run gen:api` regenerates the live doc straight into `libs/shared`.
|
||||
- Each app still needs its **own** Storybook instance (`.storybook-ssp/`,
|
||||
`.storybook-behandelportal/`) — `@auth/*` (and other context aliases) resolve to different
|
||||
physical directories per app, so one merged tsconfig can't serve both at once. This is a
|
||||
real, structural constraint, not a leftover of the old two-repo split.
|
||||
- The old sibling repo was left untouched (not deleted) when this migration landed — a
|
||||
redundant clone, safe to archive once the monorepo version is verified in daily use.
|
||||
|
||||
## Out of scope here (next steps, not built)
|
||||
|
||||
- Building the Behandeling backoffice application.
|
||||
|
||||
Reference in New Issue
Block a user