Files
atomic-design-poc/docs/project/archive/backlog/WP-67-monorepo-behandelportal.md
ehoandClaude Opus 5 12f17d9d73 docs: archive the finished backlogs (RD-30)
Two backlog trees are complete: `docs/project/backlog/` (75 files, every
WP done) and `docs/project/refactor-backlog-setup/` (the arc before it).
Move both under `docs/project/archive/` with `git mv`, so history stays
intact through `git log --follow`. `SHOWCASE-ROADMAP.md` moves with them,
because it points at the now-archived backlog README.

Add `docs/project/archive/README.md`. It states that these trees are
historical and names the two directories that are still live.

Repoint every inbound reference named in RD-30's Files table: CLAUDE.md,
the root README, both backend READMEs, `LetterHtml.cs`, `a11y.mdx`, the
`document-feature` and `new-ssp` skills, and the readable-codebase PLAN,
README, and RD-19 ticket. Fix two upward-relative links inside the moved
WP files (WP-68, WP-69) that gained a directory level and would otherwise
break. Repoint `.prettierignore`'s two agent-prompt exclusions to their
new path, so prettier keeps leaving those files' exact wording alone.

Mark RD-30 done and check off its acceptance criteria; flip its README
row to done.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 23:00:38 +02:00

8.6 KiB
Raw Permalink Blame History

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 — its "Amendment (WP-67)" section records exactly what changed and why the underlying actor/bounded-context reasoning didn't.
  • 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/sharedlibs/shared/src; git mv src/app/beheerlibs/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

  • 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).
  • Both apps' dev servers run against the one shared backend (npm start / npm run start:behandelportal, ports 4200/4201, backend on 5000).
  • Both apps' production + localized builds succeed.
  • Both Storybook instances build (build-storybook[:behandelportal]).
  • npm run gen:api generates the one client into libs/shared with zero drift.
  • 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.