Files
atomic-design-poc/docs/project/readable-codebase/RD-03-overzicht-context.md
T
ehoandClaude Sonnet 5 b9fd411283 refactor: move the portal home into its own overzicht context (RD-03)
The dashboard page lived inside registratie, a context with no permitted
outbound edges. Two of its sections do cross-context navigation: action
links to herregistratie/intake/brief/concepts, and an admin links section
that imported ADMIN_LINKS directly from the app shell.

Move the page and these two navigation sections into a new overzicht
context. Declare overzicht: ['registratie'] as the one sanctioned edge, so
the four data sections that stay in registratie/ui/dashboard/ remain
reachable. The route stays at /dashboard: it is a user-visible URL and four
e2e specs assert it, so only the import path and class name change.

beheer-links.section.ts now injects HEADER_ADMIN_LINKS, the same token the
site header uses, instead of importing the app shell's nav config directly.

Used npm run gen:context and corrected its three known-wrong outputs: the
overzicht: [] edge, the scaffolded overzicht.page.ts (the real page is the
moved dashboard.page.ts), and the scaffolded path: 'overzicht' route.

Verified the boundary is enforced, not decorative: a temporary import of a
herregistratie file into overzicht.page.ts makes dep:check fail, as
expected, then reverted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 16:26:11 +02:00

8.9 KiB

RD-03 — Move the portal home into its own overzicht context

Status: done Source: PLAN.md Phase 0

Why

The dashboard is the portal home, but it lives inside registratie — a context that .dependency-cruiser.ssp.js declares as registratie: [], permitted to import no other context. Three concrete symptoms:

  • Its six sections span four concerns: registratie data (3), aanvragen (1), cross-context action links to /herregistratie /intake /brief /concepts (1), and admin links to /beheer/* (1).
  • The cross-context coupling is invisible to the linter, because wat-wilt-u-doen.section.ts links by route string. npm run dep:check passes and gives false assurance on exactly this file.
  • beheer-links.section.ts:6 imports ADMIN_LINKS from ../../../shell/nav.config — a context reaching into the app frame.

Splitting the dashboard into sections is what makes this fixable at all. That is the refactor's first real payoff.

Read first

  • apps/ssp/src/app/registratie/ui/dashboard.page.ts (42 lines, pure composition)
  • apps/ssp/src/app/registratie/ui/dashboard/ — the six sections
  • .dependency-cruiser.ssp.js — the CONTEXT_ALLOWED map (5 lines)
  • libs/shared/src/layout/site-header/nav-config.ts — the HEADER_ADMIN_LINKS token
  • libs/shared/src/layout/site-header/site-header.component.ts:99 — how to inject it
  • apps/ssp/src/app/app.config.ts:72 — where ADMIN_LINKS is already provided to the token
  • plopfile.mjs, the context generator
  • CLAUDE.md decision 1 (DDD contexts and layers)

Decisions (pre-made, don't relitigate)

  1. New context name: overzicht. Dutch, per CLAUDE.md ("domain contexts are Dutch"), and it matches the page's own title, "Mijn overzicht".

  2. Only the page and the two navigation sections move. These three:

    • dashboard.page.ts → overzicht/ui/overzicht.page.ts (class OverzichtPage, selector app-overzicht-page)
    • dashboard/wat-wilt-u-doen.section.ts → overzicht/ui/wat-wilt-u-doen.section.ts
    • dashboard/beheer-links.section.ts → overzicht/ui/beheer-links.section.ts
  3. The four data sections STAY in registratie/ui/dashboard/ — mijn-aanvragen, wat-moet-ik-regelen, mijn-registratie, specialismen. They render registratie data and belong beside BigProfileStore/AanvragenStore. Do not move them, and do not move their three story files.

  4. Declare overzicht: ['registratie'] in .dependency-cruiser.ssp.js — the second sanctioned cross-feature edge, mirroring herregistratie: ['registratie']. The generator inserts overzicht: []; you must change it.

  5. beheer-links.section.ts injects HEADER_ADMIN_LINKS, exactly as site-header.component.ts:99 does. Drop the shell/nav.config import entirely. app.config.ts:72 already provides ADMIN_LINKS to that token, and the AdminLink doc comment already says it is "Consumed by the site header's admin nav AND (per app) a dashboard's own Beheer section". The direct import was always the anomaly.

  6. KEEP the route at /dashboard. Four e2e specs assert it (e2e/smoke.spec.ts:18, e2e/brief-v2.spec.ts:33, e2e/error-state.spec.ts:16,18), and it is a user-visible URL. Only the loadComponent import path and the class name change. Add a one-line comment in app.routes.ts saying the path stays dashboard deliberately while the context is overzicht, so the mismatch reads as a decision and not an oversight.

  7. Use npm run gen:context, then correct three things. The generator gets the folders, the @overzicht/* tsconfig alias, and the dep-cruiser entry right. It gets three things wrong for this case:

    • it writes overzicht: [] → change to ['registratie'] (decision 4)
    • it scaffolds a new overzicht.page.ts from a template → delete it, the real page is the moved dashboard.page.ts
    • it adds a new path: 'overzicht' route → delete that block, and instead repoint the existing dashboard route (decision 6)
  8. Delete the empty layer folders the generator creates. overzicht has no domain/, application/, infrastructure/ or contracts/ — it is composition only. Remove those four .gitkeep directories rather than keeping scaffolding for work that does not exist.

  9. The page keeps its 8 imports. CLAUDE.md has no import-count rule; one import per rendered section is exactly right. Do not introduce an OVERZICHT_SECTIONS const to get the number down — that trades a self-documenting array for an indirection, and this repo deliberately has no barrels.

Files

Move (use git mv so the rename is visible in review):

From To
apps/ssp/src/app/registratie/ui/dashboard.page.ts apps/ssp/src/app/overzicht/ui/overzicht.page.ts
apps/ssp/src/app/registratie/ui/dashboard/wat-wilt-u-doen.section.ts apps/ssp/src/app/overzicht/ui/wat-wilt-u-doen.section.ts
apps/ssp/src/app/registratie/ui/dashboard/beheer-links.section.ts apps/ssp/src/app/overzicht/ui/beheer-links.section.ts

Edit: apps/ssp/tsconfig.json (alias), .dependency-cruiser.ssp.js (edge), apps/ssp/src/app/app.routes.ts (import path + class + comment), apps/ssp/src/app/overzicht/ui/beheer-links.section.ts (token), apps/ssp/src/app/overzicht/ui/overzicht.page.ts (class, selector, section import paths).

Steps

  1. Run npm run gen:context and answer overzicht.
  2. Delete the generated overzicht/ui/overzicht.page.ts and the four empty layer folders.
  3. Delete the generated path: 'overzicht' route block from app.routes.ts.
  4. Change the generated overzicht: [] to overzicht: ['registratie'].
  5. git mv the three files per the table above.
  6. Rename the page's class to OverzichtPage and its selector to app-overzicht-page; fix its six section import paths (four now via @registratie/ui/dashboard/…, two local).
  7. Repoint the existing dashboard route to @overzicht/ui/overzicht.page / OverzichtPage and add the comment from decision 6.
  8. Rewrite beheer-links.section.ts to inject HEADER_ADMIN_LINKS per decision 5.
  9. Update this ticket's Status: to done and the README's RD-03 row to done.
  10. Commit all of it together.

Acceptance criteria

npm run dep:check     # exits 0 — proves overzicht: ['registratie'] is accepted
npm run ci            # exits 0

Then prove the boundary is real, not decorative:

# Add a temporary import of a herregistratie file to overzicht/ui/overzicht.page.ts.
# `npm run dep:check` MUST fail (overzicht may reach registratie only). Then revert.

And prove the section still renders for an admin:

grep -n "HEADER_ADMIN_LINKS" apps/ssp/src/app/overzicht/ui/beheer-links.section.ts   # present
grep -rn "shell/nav.config" apps/ssp/src/app/overzicht/                              # no match

Verification

npm run ci. No story or .mdx file moves in this ticket — the three section stories stay in registratie — so --full is not strictly required. Run it once anyway, because this is a structural move and Storybook globs the app's stories by path.

Manual check, since e2e is not in the local GREEN one-liner: npm start, open http://localhost:4200/dashboard, confirm all six sections render, then ?role=admin and confirm the Beheer section appears (and is absent without it).

Out of scope

  • Renaming the route to /overzicht. It needs a redirect and touches four e2e specs. Recorded in PLAN.md as deliberately out of scope.
  • Moving the four data sections (decision 3).
  • Story titles — that is RD-04.
  • Turning wat-wilt-u-doen's action list into a token beside NAV_ITEMS. PLAN.md Phase 0 step 6 lists it as a "consider"; leave it for now, since route strings on a landing page are legitimate once the page lives in a context whose job is cross-context linking.

Risks

  • The generator's three wrong outputs (decision 7). If you skip the corrections, dep:check still passes with the boundary silently missing — the exact failure mode plopfile.mjs's own comment warns about for create-frontend.mjs.
  • messages.xlf / messages.en.xlf carry <context context-type="sourcefile"> paths that these moves make stale. Nothing checks them and $localize ids are the identity, so ng build --localize stays green. Do not hand-edit the xlf files to chase paths.
  • Do not change any $localize id. Every id in the three moved files stays byte identical; only the file's location changes. A changed id needs a new English <target> or the localize gate fails.
  • git mv, not delete-and-create, or the review loses the rename and the diff looks like 300 new lines.