feat(arch): WP-38 — dependency graph + declarative boundaries (dependency-cruiser)
CI / frontend (push) Successful in 2m11s
CI / storybook-a11y (push) Successful in 5m46s
CI / backend (push) Successful in 1m29s
CI / e2e (push) Successful in 2m55s
CI / semgrep (push) Successful in 1m1s
CI / api-client-drift (push) Successful in 2m5s

Adopt dependency-cruiser as the single declarative source for bounded-context +
atomic-layer boundaries, replacing the per-context no-restricted-imports blocks that
had to be hand-copied (and had left herregistratie uncovered). `.dependency-cruiser.js`
encodes context direction (everyone→shared, herregistratie→registratie, showcase→*),
domain-purity, contracts-import-nothing, ui↛infrastructure, ApiClient confinement, and
no-circular. `npm run dep:check` enforces (wired into ci-local.sh + the frontend CI job);
`npm run dep:graph` emits a committed mermaid context×layer graph. ESLint slimmed to
no-explicit-any + template a11y. Docs + new-context skill updated to the single source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-23 13:51:04 +02:00
co-authored by Claude Opus 4.8
parent fe9e3121c7
commit 7d2a36ff22
12 changed files with 641 additions and 248 deletions
+12 -14
View File
@@ -1,6 +1,6 @@
---
name: new-context
description: Scaffold a new DDD bounded context (folders, path alias, eslint boundary rules, lazy route). Use when adding a new business capability that doesn't belong in an existing context.
description: Scaffold a new DDD bounded context (folders, path alias, boundary rules, lazy route). Use when adding a new business capability that doesn't belong in an existing context.
---
# New bounded context
@@ -18,16 +18,14 @@ shared/reusable code is English. The context name is the ubiquitous language ter
only once it gets a wire seam). Empty layers can wait; don't scaffold placeholders.
2. **Path alias** — add `"@<ctx>/*": ["src/app/<ctx>/*"]` to `tsconfig.json` `paths`.
Aliases are direction statements; always import cross-context via the alias.
3. **eslint boundaries** (`eslint.config.mjs`) — dependencies point inward and
toward `shared` only. Copy the existing per-context block (the `brief` block is
the minimal leaf-context example) and:
- add a block for `src/app/<ctx>/**/*.ts` banning imports from every context it
may **not** depend on;
- add `@<ctx>/*` to the ban lists of `shared/**` and every context that must not
depend on the new one (grep the config for `@brief/*` to find all lists);
- the generic blocks (`domain/**` framework-free, `contracts/**` import-nothing,
ApiClient confinement, `ui/**` never imports `infrastructure`) match by glob
and cover the new context automatically.
3. **Boundaries** (`.dependency-cruiser.js`, WP-38 — the single declarative source;
dependencies point inward and toward `shared` only). Add ONE `contextRule(...)` entry
for the new context listing the contexts it may **not** import (copy the `brief` leaf
example), and add the new context to the forbidden list of any context that must not
depend on it. The layer rules (`domain/` framework-free, `contracts/` import-nothing,
ApiClient confinement, `ui ↛ infrastructure`) match by glob and cover it automatically.
Verify with `npm run dep:check`; regenerate the graph with `npm run dep:graph`. (Boundaries
are no longer in `eslint.config.mjs` — that now holds only `no-explicit-any` + template a11y.)
4. **Route** — lazy child under the persistent shell in `app.routes.ts`:
```ts
@@ -40,12 +38,12 @@ shared/reusable code is English. The context name is the ubiquitous language ter
## Worked example
`src/app/brief/` — an independent leaf context (depends only on shared): see its
folder layout and its eslint block in `eslint.config.mjs`.
folder layout and its `contextRule` entry in `.dependency-cruiser.js`.
## Verify
```bash
npm run lint && npm run build
npm run dep:check && npm run lint && npm run build
# prove the fence works: add a forbidden import (e.g. new ctx → @herregistratie/*),
# confirm lint fails, remove it.
# confirm `npm run dep:check` fails, remove it.
```