Files
atomic-design-poc/docs/project/backlog/WP-67-monorepo-behandelportal.md
T
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

138 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WP-67 — Merge behandelportal into this repo as a monorepo
Status: done
Phase: 11 — Behandelportal
## Why
WP-61 bootstrapped `behandelportal` as a **separate sibling repo**, per ADR-0002's original
"separate frontend application" reading taken literally as "separate git repository." That
produced real, measured friction: a hand-vendored, manually-kept-in-sync copy of the
backend's OpenAPI doc instead of a live-generated one; `shared/ui`+`shared/layout` forked at
WP-61 and already silently diverging by the time this WP checked (7 files differed); a
`beheer` (admin/stamdata) context and the `styles.scss` token bridge duplicated byte-for-byte
across both repos; a second CI/lint/CLAUDE.md to hand-maintain. The user asked to collapse
this into one repo so the two apps share one CI, one shared UI library, and one generated API
client — the standard monorepo payoff, now that a second real frontend exists.
## Read first
- [ADR-0002](../reference/architecture/0002-user-groups-and-bounded-contexts.md) — its
"Amendment (WP-67)" section records exactly what changed and why the underlying
actor/bounded-context reasoning didn't.
- [dependencies.md](../reference/architecture/dependencies.md) — the per-app
dependency-cruiser split this WP introduced.
- `behandelportal-bootstrap` memory (prior sessions) for WP-61/62's own decisions.
## Decisions (made during this WP, not pre-made — see the plan file for the questions asked)
- **Unify** `libs/shared` into one library both apps import (not two copies) — the user's
explicit call, given the two trees had already started diverging.
- Restructure into **`apps/ssp/` + `apps/behandelportal/`** (not an Angular-CLI `projects/`
addition next to an untouched `src/app/`) — the user's call, accepting the larger diff.
- **Leave** the old sibling repo (`/home/eho/repos/behandelportal`) untouched — no deletion.
- Bring the content in as a **fresh commit**, no git-history import — that repo is itself a
fork of this repo's own pre-WP-61 history, so a subtree merge would fight to reconcile two
copies of the same ancestor commits for one commit's worth of real new content.
- **Course corrections found during execution** (squarely within "unify shared," not
separately asked): `libs/beheer` (admin/stamdata — already identical in both apps, not
actor-specific) and `libs/shared/styles.scss` (the token bridge, also byte-identical) were
folded in alongside `libs/shared/ui`. `auth` was deliberately **not** unified — ADR-0002
models it as actor-specific (different `Principal` variants), so today's accidental
similarity is expected to diverge, not something to force together.
- **Two Storybook instances, not one** (`.storybook-ssp/`, `.storybook-behandelportal/**`) —
a structural necessity, not a simplification choice: both apps' `auth` (and other) context
aliases share the name `@auth/*` but resolve to different physical directories, so no
single tsconfig can compile both apps' stories in one pass.
- Each app's own `shell/nav.config.ts` supplies its primary nav + admin links to the shared
`SiteHeaderComponent` via two new injection tokens (`HEADER_NAV_ITEMS`,
`HEADER_ADMIN_LINKS`) rather than the component hardcoding one app's routes — the same
"shared component takes copy as an input, the domain caller supplies it" idiom CLAUDE.md
already used for `shared/ui` copy, extended to injection tokens for this DI-shaped case.
The dev-only "state" panel (`DebugStateComponent`) moved out of `libs/shared` into
`apps/ssp` entirely (it's coupled to `BigProfileStore`, an ssp-only store) and is now hosted
by the shared `ShellComponent` via a `DEBUG_PANEL` injection token — no provider, no panel.
## Files
Nearly the whole repo, mechanically (`git mv`), plus:
- `angular.json` — rewritten for 4 projects: `ssp`, `behandelportal` (real apps),
`shared`, `beheer` (library projects whose only real purpose is giving `ng test` a
`buildTarget` to satisfy — see `libs/*/src/test-entry.ts`'s comment).
- `tsconfig.json` (root, no more `paths` — see its comment) + a new `tsconfig.json` per
app/library declaring that project's own full alias map.
- `.dependency-cruiser.base.js` (rule factory) + `.dependency-cruiser.ssp.js` +
`.dependency-cruiser.behandelportal.js` (replacing the single `.dependency-cruiser.js`).
- `eslint.config.mjs`, `package.json` scripts, `docker-compose.yml`, `.github/workflows/ci.yml`,
`scripts/ci-local.sh`, `scripts/check-tokens.sh`, `scripts/gen-snippets.mjs`,
`scripts/serve-i18n.mjs`, `scripts/dep-graph.sh`, `plopfile.mjs`, `nswag.json` — all
re-pointed at the new paths / made per-app aware.
- `CLAUDE.md`, `ARCHITECTURE.md`, `dependencies.md`, ADR-0002 — updated for the new layout.
## Steps
1. Branch, then `git mv` the SSP's `src/app/*` (minus `shared/`) → `apps/ssp/src/app/`, plus
`main.ts`/`index.html`/`locale/`/`proxy.conf.json`/`tsconfig.app.json`/`tsconfig.spec.json`.
2. `git mv src/app/shared` → `libs/shared/src`; `git mv src/app/beheer` → `libs/beheer/src`;
fold in `environments/` and the Storybook `docs/*.mdx` (both found byte-identical between
the two repos — same treatment as `shared/ui`).
3. Copy (not `git mv` — a different repo) behandelportal's `auth`/`behandeling` +
`main.ts`/`index.html`/`locale/` into `apps/behandelportal/src/`.
4. Rewrite `angular.json` for the two real projects + two library test-only projects; fix
every relative import that broke (`environments/environment` → `@shared/environments/environment`;
MDX docs' `../app/shared/...` → `../src/...`).
5. Split `.dependency-cruiser.js` into a base factory + one config per app; broaden
`eslint.config.mjs`'s `files` glob.
6. Rewrite `package.json` scripts, `docker-compose.yml` (added a `web-behandelportal`
service), `.github/workflows/ci.yml` + `scripts/ci-local.sh` (both apps built/tested,
path filters widened), the four `scripts/*.mjs`/`*.sh` helpers, `plopfile.mjs`'s three
generators (value-object/form-machine paths now resolve `shared`/`beheer` to `libs/`, the
`context` generator's tsconfig/dep-cruiser/routes edits re-anchored on the ssp config).
7. Split `.storybook/` into `.storybook-ssp/` + `.storybook-behandelportal/` (forced by the
`@auth/*` alias collision); moved the CIBG token bridge (`styles.scss`) and the generated
`documentation.json` to avoid two more collisions.
8. Add `HEADER_NAV_ITEMS`/`HEADER_ADMIN_LINKS`/`DEBUG_PANEL` injection tokens to
`SiteHeaderComponent`/`ShellComponent`; give each app its own `shell/nav.config.ts` and
(ssp only) `shell/debug-state/`.
9. Update `CLAUDE.md`, `ARCHITECTURE.md`, `dependencies.md`, and amend ADR-0002.
## Acceptance criteria
- [x] `npm run ci` green (lint, dep:check ×2, format:check, check:tokens, test:coverage ×4
projects, `ng build --localize` ×2, npm audit, backend test, snippets drift,
api-client drift).
- [x] Both apps' dev servers run against the one shared backend
(`npm start` / `npm run start:behandelportal`, ports 4200/4201, backend on 5000).
- [x] Both apps' production + localized builds succeed.
- [x] Both Storybook instances build (`build-storybook[:behandelportal]`).
- [x] `npm run gen:api` generates the one client into `libs/shared` with zero drift.
- [x] `docker compose up` serves both apps + the shared backend.
## Verification
`npm run ci`; `npx ng build ssp --localize && npx ng build behandelportal --localize`;
`npx ng run ssp:build-storybook && npx ng run behandelportal:build-storybook`; manual:
`npm start` on :4200 and `npm run start:behandelportal` on :4201 against
`dotnet run --project backend/src/BigRegister.Api`, log in on both.
## Out of scope
- Deleting or archiving the old sibling repo (`/home/eho/repos/behandelportal`) — left
untouched per the user's explicit choice.
- `scripts/create-frontend.mjs` / the `new-ssp` skill (bootstrapping a _third_ portal as a
fresh standalone repo) — whether future portals should also join this monorepo is a
separate decision.
- Extending the `storybook-a11y` CI job to behandelportal's own Storybook instance — it
still only covers ssp's, unchanged from before this WP.
- Reconciling `auth` between the two apps — left duplicated, deliberately (see Decisions).
## Risks
The `libs/shared`/`libs/beheer` "library" Angular projects exist solely to give the
unit-test builder a `buildTarget` to resolve (`@angular/build:unit-test` always requires
one, even for a project that's only ever tested) — `test-entry.ts` + `tsconfig.app.json` in
each are a `ponytail:`-flagged workaround, not a real buildable/publishable library. If
either library ever needs to actually build (e.g. an ng-packagr distributable), replace this
with a real library target then.