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>
169 lines
8.9 KiB
Markdown
169 lines
8.9 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
npm run dep:check # exits 0 — proves overzicht: ['registratie'] is accepted
|
|
npm run ci # exits 0
|
|
```
|
|
|
|
Then prove the boundary is real, not decorative:
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
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.
|