feat(dx): create-ssp bootstrap generator (WP-45)

Mechanises the new-ssp skill's manual fork-and-strip recipe into a runnable
script: strips the four business contexts and every wiring point that
references them (routes, tsconfig aliases, dependency-cruiser boundaries,
nav links, capability union, the debug-state panel, showcase snippet
tooling), renames BigRegister.* throughout including the backend
solution/projects, re-runs gen:api, and reuses gen:context (WP-44) to seed
the new portal's first context. Backend business rules and real branding
can't be generated from nothing, so those print an explicit checklist
instead of pretending to be automated.

Verified end-to-end against an isolated clone (not this working tree):
lint, dep:check, check:tokens, all frontend tests, ng build, dotnet
build/test on the renamed backend, and gen:api against it all pass clean
with zero remaining references to the stripped contexts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-28 16:43:17 +02:00
co-authored by Claude Sonnet 5
parent e4022fd31a
commit ad7ca31841
3 changed files with 593 additions and 18 deletions
+69 -18
View File
@@ -9,38 +9,89 @@ The template's value is the **enforced architecture** (layer fences, token gate,
a11y gate, API-drift gate) and the shared building blocks — not the BIG-register
business content. Keep the machinery, replace the domain.
## Run the script
Clone this repo, `npm ci`, then mechanise the mechanical parts (WP-45):
```bash
node scripts/create-ssp.mjs --name Kvk --context inschrijving
```
`--name` (PascalCase) replaces `BigRegister.*` everywhere; `--context` (lowercase Dutch
ubiquitous term) is passed straight to `gen:context` (`plop context`, WP-44) to seed the new
portal's first real context. Add `--dry-run` to preview file operations first, `--keep
<context>` to leave one business context in place temporarily as a worked example, and
`--skip-backend` if no .NET SDK is available yet (skips `gen:api`).
It strips the four business contexts and their wiring, renames the backend, re-runs
`gen:api`, and seeds the first context — then **prints a checklist** for what it deliberately
doesn't script: backend business rules and real branding can't be generated from nothing.
Work through that checklist, keeping the GREEN gate below passing at every step.
## Keep as-is
- `src/app/shared/` — kernel (`fp.ts`), application (`remote-data`, `store`,
`submit`), ui atoms/molecules, layout templates, upload subtree.
- Tooling: `eslint.config.mjs`, `scripts/check-tokens.sh`, `.github/workflows/ci.yml`,
`submit`), ui atoms/molecules, layout templates, upload subtree**except**
`shared/ui/debug-state/`, which the script deletes (see below).
- Tooling: `eslint.config.mjs`, `.dependency-cruiser.js` (edited by the script, not
hand-stripped — see below), `scripts/check-tokens.sh`, `.github/workflows/ci.yml`,
`nswag.json`, `.storybook/`, `proxy.conf.json`, `.npmrc` (`legacy-peer-deps`
and never `npm audit fix --force`, it downgrades Angular).
- `src/app/auth/` (fake auth shell) and `src/app/shared/infrastructure/scenario.interceptor.ts` (dev-only).
- `docs/reference/architecture/` ADRs 00010003 — the decisions still apply; amend, don't delete.
- `CLAUDE.md`, `docs/reference/architecture/ARCHITECTURE.md`, `docs/reference/fp-tea-atomic-design.md` — update names/examples as contexts change.
- `.claude/skills/` — these recipes are the point of the template.
- `src/app/beheer/` — its frontend is genuinely generic (data-driven off a `StamdataTable`/
`AuditEntry` shape, nothing BIG-specific). Its _backend_ Stamdata catalog is not — see below.
## Strip / replace
## Strip / replace — what the script does
- Business contexts `registratie/`, `herregistratie/`, `brief/`, and `showcase/`:
delete or keep one slice temporarily as the worked example while building the
first real context (**new-context** + **new-feature** skills). If deleted, update
the worked-example paths in these skills to the new flagship context.
- `app.routes.ts` routes and `tsconfig.json` aliases for removed contexts, plus
their eslint blocks in `eslint.config.mjs`.
- Business contexts `registratie/`, `herregistratie/`, `brief/`, `showcase/`: deleted (or one
kept temporarily via `--keep` as the worked example while building the first real context —
**new-context** + **new-feature** skills; if kept, update the worked-example paths in those
skills to the new flagship context once you drop it for real).
- `app.routes.ts` route blocks and `tsconfig.json` aliases for removed contexts, and their
`CONTEXT_ALLOWED` entry in **`.dependency-cruiser.js`** — boundary rules moved there in
WP-38 and are no longer in `eslint.config.mjs` (which only keeps `no-explicit-any` + a11y
template rules). Route stripping matches on the _import alias_ a route uses, not its own
path segment — `beheer/zaken` imports `@registratie/ui/admin-cases.page` and gets dropped
along with `registratie` even though its own path doesn't say so.
- `src/app/shared/ui/debug-state/` (the dev `⚙ state` panel): imports
`@registratie/application/big-profile.store` directly and is the one path
`.dependency-cruiser.js`'s `shared-no-features` rule exempts — there's no generic way to
re-target it at an arbitrary new context, so it's deleted alongside `registratie`, along
with its three wiring lines in `shell.component.ts` (import, `imports:` entry, template tag).
- The `dashboard` route is **not** deleted even though it currently imports
`@registratie/ui/dashboard.page` — too much else hardcodes `/dashboard` (login's post-auth
redirect, `authGuard`'s fallback, header nav/logo, breadcrumb trail, several stories/specs).
The script rewrites its `loadComponent` to point at the freshly scaffolded `--context` page
instead (a `TODO(create-ssp)` stopgap landing page, not a real overview).
- `scripts/gen-snippets.mjs` (showcase-only) + its `package.json` script entry + its CI/
`ci-local.sh` "showcase snippets drift" steps: deleted alongside `showcase/` — they run
unconditionally, so leaving them breaks `npm run ci` immediately once `showcase/` is gone.
- Backend: keep the skeleton (`Program.cs` minimal-API style, ProblemDetails 422,
`X-Correlation-Id` audit line, `/api/v1` versioning, `Contracts/`/`Domain/`/`Data/`
split, test project) — replace `Data/SeedData.cs`, `Domain/*` rules, and
`Contracts/*` DTOs with the new domain's. Rename the solution/projects from
`BigRegister.*` (also update `package.json` `gen:api` and `ci.yml` paths).
split, test project, and the generic `Stamdata/StamdataFile.cs`+`StamdataTable.cs`
reflection-driven `/stamdata` endpoint machinery, ADR-0004) — replace `Data/SeedData.cs`,
`Domain/*` rules, `Contracts/*` DTOs, and the three concrete Stamdata catalog entries
(`Beroep`/`Opleiding`/`Specialisme`/`ProfessionMapping` + their JSON) with the new
register's. The script renames the solution/projects from `BigRegister.*` (and updates
`package.json`'s `gen:api`, `ci.yml`'s paths, `docker-compose.yml`) — it does not rewrite
business content; that's the printed checklist.
- Regenerate the seam: `npm run gen:api` (commits `backend/swagger.json` +
`src/app/shared/infrastructure/api-client.ts`).
- Branding: `public/cibg-huisstijl/` + the token bridge in `src/styles.scss` — for a
different house style, swap the vendored CSS and re-point the `--rhc-*` bridge
(ADR-0003 pattern: bridge, don't rewrite tokens).
`src/app/shared/infrastructure/api-client.ts`) — only reflects a new shape once the backend
content above is actually rewritten.
- Branding: the script swaps `src/index.html`'s stylesheet `<link>` + `<title>` to a
placeholder path and creates an empty `public/<name>-huisstijl/` — it cannot generate a
real house style. Vendor your CSS there, then re-point the `--rhc-*` bridge in
`src/styles.scss` (ADR-0003 pattern: bridge, don't rewrite tokens), then `npm run check:tokens`.
- `docs/project/backlog/` WPs, PRDs, and memory-specific docs — new portal, new backlog
(keep `docs/project/backlog/README.md`'s WP process/template if you like the workflow).
`docs/reference/scaffolding.md` also names `BigRegister.Api` in prose — update by hand.
- `e2e/*.spec.ts` (`smoke.spec.ts`, `brief-v2.spec.ts`, `error-state.spec.ts`): full
BIG-register user-flow tests (BSN login → registration wizard → submission assertions).
Not touched by the script (they don't block `npm run ci` — the `e2e` job runs separately)
but are 100% stale business content; rewrite once you have real flows to test.
## Verify — the GREEN gate must pass at every step
@@ -51,5 +102,5 @@ cd backend && dotnet test && cd ..
npm run gen:api && git diff --exit-code backend/swagger.json src/app/shared/infrastructure/api-client.ts
```
Strip incrementally and keep this green — the fences are only worth having if they
never go red.
Or just `npm run ci` for the non-storybook subset. Strip incrementally and keep this green
— the fences are only worth having if they never go red.