fix(scaffolding): rename create-ssp to create-frontend, fix 2 bugs it surfaced

Renamed scripts/create-ssp.mjs -> create-frontend.mjs (+ its WP-45 doc, npm
script, and every prose/command reference) since "ssp" reads as an acronym
where "create-frontend" says what it does.

Also fixes two real bugs found while running it for real during WP-61:
scripts/ci-local.sh was missing from RENAME_CONTENT_FILES (any --name'd
clone that keeps a backend would break `npm run ci`, still hardcoding
BigRegister.slnx), and plopfile.mjs's `gen:context` insertion into
.dependency-cruiser.js anchored on the `showcase: null,` line, which
create-ssp/create-frontend has already stripped by the time gen:context
runs in the same invocation — silently leaving a freshly scaffolded
context with no CONTEXT_ALLOWED fence entry at all. Re-anchored on the
`const CONTEXT_ALLOWED = {` line instead, which never moves.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-31 23:26:28 +02:00
co-authored by Claude Sonnet 5
parent ba24784586
commit 920ce138cb
7 changed files with 21 additions and 17 deletions
+2 -2
View File
@@ -14,7 +14,7 @@ business content. Keep the machinery, replace the domain.
Clone this repo, `npm ci`, then mechanise the mechanical parts (WP-45): Clone this repo, `npm ci`, then mechanise the mechanical parts (WP-45):
```bash ```bash
node scripts/create-ssp.mjs --name Kvk --context inschrijving node scripts/create-frontend.mjs --name Kvk --context inschrijving
``` ```
`--name` (PascalCase) replaces `BigRegister.*` everywhere; `--context` (lowercase Dutch `--name` (PascalCase) replaces `BigRegister.*` everywhere; `--context` (lowercase Dutch
@@ -65,7 +65,7 @@ Work through that checklist, keeping the GREEN gate below passing at every step.
`@registratie/ui/dashboard.page` — too much else hardcodes `/dashboard` (login's post-auth `@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). 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 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). instead (a `TODO(create-frontend)` stopgap landing page, not a real overview).
- `scripts/gen-snippets.mjs` (showcase-only) + its `package.json` script entry + its CI/ - `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 `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. unconditionally, so leaving them breaks `npm run ci` immediately once `showcase/` is gone.
+2 -2
View File
@@ -95,7 +95,7 @@ for its existing violations, so every WP ends green.
| [WP-42](WP-42-privacy-security-showcase.md) | Privacy & security showcase page (mask + no-PII log) | 8 · platform/DX/showcase | done | | [WP-42](WP-42-privacy-security-showcase.md) | Privacy & security showcase page (mask + no-PII log) | 8 · platform/DX/showcase | done |
| [WP-43](WP-43-scaffold-generators.md) | Runnable generators: value-object / form-machine (plop; ui-component/bff = skills) | 8 · platform/DX/showcase | done | | [WP-43](WP-43-scaffold-generators.md) | Runnable generators: value-object / form-machine (plop; ui-component/bff = skills) | 8 · platform/DX/showcase | done |
| [WP-44](WP-44-context-generator.md) | Runnable generator: `gen:context` | 8 · platform/DX/showcase | done | | [WP-44](WP-44-context-generator.md) | Runnable generator: `gen:context` | 8 · platform/DX/showcase | done |
| [WP-45](WP-45-create-ssp-generator.md) | `create-ssp` bootstrap generator (mechanise new-ssp) | 8 · platform/DX/showcase | done | | [WP-45](WP-45-create-frontend-generator.md) | `create-frontend` bootstrap generator (mechanise new-ssp) | 8 · platform/DX/showcase | done |
| [WP-46](WP-46-vitest-coverage.md) | Vitest coverage (report + report-only thresholds) | 8 · platform/DX/showcase | done | | [WP-46](WP-46-vitest-coverage.md) | Vitest coverage (report + report-only thresholds) | 8 · platform/DX/showcase | done |
| [WP-47](WP-47-feature-flags.md) | Runtime feature flags (catalog-in-code, admin toggle, FE+backend) | 8 · platform/DX/showcase | done | | [WP-47](WP-47-feature-flags.md) | Runtime feature flags (catalog-in-code, admin toggle, FE+backend) | 8 · platform/DX/showcase | done |
| [WP-48](WP-48-stamdata-deletion-protection.md) | Stamdata deletion protection (CI referential gate + editor expire/warn) | 8 · platform/DX/showcase | done | | [WP-48](WP-48-stamdata-deletion-protection.md) | Stamdata deletion protection (CI referential gate + editor expire/warn) | 8 · platform/DX/showcase | done |
@@ -135,7 +135,7 @@ Phase 8 (platform/DX/showcase, WP-37..46): goal is BOTH a teaching showcase AND
starter template. Priority: WP-37 (P0 quick fix) → WP-46 + WP-38 + WP-39 (P1, parallel) → starter template. Priority: WP-37 (P0 quick fix) → WP-46 + WP-38 + WP-39 (P1, parallel) →
WP-40 (P2) → WP-43 (P3) → WP-41 → WP-42 → WP-44 → WP-45 (P4). Ordering constraints: WP-40 (P2) → WP-43 (P3) → WP-41 → WP-42 → WP-44 → WP-45 (P4). Ordering constraints:
41 needs 40's PII kernel; 42 needs 40+41; 44 (`gen:context`) needs 38 (declarative boundaries 41 needs 40's PII kernel; 42 needs 40+41; 44 (`gen:context`) needs 38 (declarative boundaries
make the generator simple) + 43; 45 (`create-ssp`) needs 43+44. 37/38/39/40/43/46 are otherwise make the generator simple) + 43; 45 (`create-frontend`) needs 43+44. 37/38/39/40/43/46 are otherwise
independent. Two open tool forks, decided as step 1 of their WP: 38 dependency-cruiser vs Sheriff; independent. Two open tool forks, decided as step 1 of their WP: 38 dependency-cruiser vs Sheriff;
43 plop vs Angular schematics. 43 plop vs Angular schematics.
Phase 9 (OpenZaak/ZGW integration, WP-49..52) is strictly ordered 49 → 50 → 51 → 52: 49 lands Phase 9 (OpenZaak/ZGW integration, WP-49..52) is strictly ordered 49 → 50 → 51 → 52: 49 lands
@@ -1,4 +1,4 @@
# WP-45 — `create-ssp` bootstrap generator # WP-45 — `create-frontend` bootstrap generator
Status: done (ad7ca31) Status: done (ad7ca31)
Phase: 8 — platform/DX/showcase Phase: 8 — platform/DX/showcase
@@ -13,7 +13,7 @@ scaffold keeping the enforced architecture + shared building blocks.
## Decisions ## Decisions
- A `create-ssp` script (Node/plop-driven) that clones-and-strips per the `new-ssp` recipe: - A `create-frontend` script (Node/plop-driven) that clones-and-strips per the `new-ssp` recipe:
drop the business contexts, prune their routes/aliases/boundary entries, rename `BigRegister.*`, drop the business contexts, prune their routes/aliases/boundary entries, rename `BigRegister.*`,
re-point the `--rhc-*` token bridge, re-seed the backend, re-run `gen:api`. re-point the `--rhc-*` token bridge, re-seed the backend, re-run `gen:api`.
- Keep-as-is list from `new-ssp` (shared kernel/ui/layout, eslint/boundary config, check-tokens, - Keep-as-is list from `new-ssp` (shared kernel/ui/layout, eslint/boundary config, check-tokens,
@@ -22,7 +22,7 @@ scaffold keeping the enforced architecture + shared building blocks.
## Files ## Files
- New `scripts/create-ssp.*` (+ any templates); documented in `.claude/skills/new-ssp/SKILL.md`. - New `scripts/create-frontend.*` (+ any templates); documented in `.claude/skills/new-ssp/SKILL.md`.
## Acceptance criteria ## Acceptance criteria
+1 -1
View File
@@ -71,7 +71,7 @@ step-by-step and its GREEN-at-every-step verify gate.
- **`gen:context`** ([WP-44](../project/backlog/WP-44-context-generator.md)) — a runnable - **`gen:context`** ([WP-44](../project/backlog/WP-44-context-generator.md)) — a runnable
version of the `new-context` skill. Planned, not shipped. version of the `new-context` skill. Planned, not shipped.
- **`create-ssp`** ([WP-45](../project/backlog/WP-45-create-ssp-generator.md)) — - **`create-frontend`** ([WP-45](../project/backlog/WP-45-create-frontend-generator.md)) —
mechanised `new-ssp`. Planned, not shipped. mechanised `new-ssp`. Planned, not shipped.
Don't assume either command exists — use the corresponding skill until they land. Don't assume either command exists — use the corresponding skill until they land.
+1 -1
View File
@@ -24,7 +24,7 @@
"gen:value-object": "plop value-object", "gen:value-object": "plop value-object",
"gen:form-machine": "plop form-machine", "gen:form-machine": "plop form-machine",
"gen:context": "plop context", "gen:context": "plop context",
"create-ssp": "node scripts/create-ssp.mjs", "create-frontend": "node scripts/create-frontend.mjs",
"serve:i18n": "ng build --configuration development --localize && node scripts/serve-i18n.mjs", "serve:i18n": "ng build --configuration development --localize && node scripts/serve-i18n.mjs",
"ci": "bash scripts/ci-local.sh", "ci": "bash scripts/ci-local.sh",
"e2e": "playwright test", "e2e": "playwright test",
+7 -4
View File
@@ -107,12 +107,15 @@ export default function (plop) {
template: '"paths": {\n "@{{kebabCase name}}/*": ["src/app/{{kebabCase name}}/*"],\n', template: '"paths": {\n "@{{kebabCase name}}/*": ["src/app/{{kebabCase name}}/*"],\n',
}, },
{ {
// Boundary entry (WP-38's single source of truth) — inserted right before the // Boundary entry (WP-38's single source of truth) — inserted right after the
// `showcase: null` line, which never moves. // `const CONTEXT_ALLOWED = {` opening line, which never moves. (Previously anchored
// on the `showcase: null,` line, but create-frontend.mjs strips that entry before running
// this generator, so the modify silently no-op'd and the new context got no fence at
// all — dep:check stayed green with the boundary rule simply missing.)
type: 'modify', type: 'modify',
path: '.dependency-cruiser.js', path: '.dependency-cruiser.js',
pattern: /(\s*)showcase: null,/, pattern: /const CONTEXT_ALLOWED = \{\n/,
template: "$1'{{kebabCase name}}': [],$1showcase: null,", template: 'const CONTEXT_ALLOWED = {\n {{kebabCase name}}: [],\n',
}, },
{ {
// Lazy route — inserted right before the catch-all, which never moves. // Lazy route — inserted right before the catch-all, which never moves.
@@ -9,8 +9,8 @@
// from nothing — those steps print an explicit checklist instead of pretending to solve them. // from nothing — those steps print an explicit checklist instead of pretending to solve them.
// //
// Usage: // Usage:
// node scripts/create-ssp.mjs --name Kvk --context inschrijving // node scripts/create-frontend.mjs --name Kvk --context inschrijving
// node scripts/create-ssp.mjs --name Kvk --context inschrijving --keep registratie --dry-run // node scripts/create-frontend.mjs --name Kvk --context inschrijving --keep registratie --dry-run
// //
// --name <PascalName> replaces BigRegister.* everywhere (required) // --name <PascalName> replaces BigRegister.* everywhere (required)
// --context <name> lowercase Dutch ubiquitous term, passed to `plop context` (required) // --context <name> lowercase Dutch ubiquitous term, passed to `plop context` (required)
@@ -43,7 +43,7 @@ function parseArgs(argv) {
function usageAndExit(message) { function usageAndExit(message) {
if (message) console.error(message + '\n'); if (message) console.error(message + '\n');
console.error( console.error(
'Usage: node scripts/create-ssp.mjs --name <PascalName> --context <lowercase-term> ' + 'Usage: node scripts/create-frontend.mjs --name <PascalName> --context <lowercase-term> ' +
'[--keep <context>] [--dry-run] [--skip-backend]', '[--keep <context>] [--dry-run] [--skip-backend]',
); );
process.exit(1); process.exit(1);
@@ -351,6 +351,7 @@ const RENAME_CONTENT_FILES = [
'playwright.config.ts', 'playwright.config.ts',
'README.md', 'README.md',
'backend/README.md', 'backend/README.md',
'scripts/ci-local.sh',
]; ];
const SKIP_DIRS = new Set(['bin', 'obj', 'node_modules', '.git']); const SKIP_DIRS = new Set(['bin', 'obj', 'node_modules', '.git']);
@@ -465,7 +466,7 @@ function repointDashboard(contextName, registratieWasStripped, args) {
const pageClass = `${pascalCase(contextName)}Page`; const pageClass = `${pascalCase(contextName)}Page`;
const next = content.replace( const next = content.replace(
/loadComponent: \(\) => import\('@registratie\/ui\/dashboard\.page'\)\.then\(\(m\) => m\.DashboardPage\),/, /loadComponent: \(\) => import\('@registratie\/ui\/dashboard\.page'\)\.then\(\(m\) => m\.DashboardPage\),/,
`// TODO(create-ssp): stopgap landing page — point this at a real overview once you have one.\n` + `// TODO(create-frontend): stopgap landing page — point this at a real overview once you have one.\n` +
` loadComponent: () =>\n` + ` loadComponent: () =>\n` +
` import('@${contextName}/ui/${contextName}.page').then((m) => m.${pageClass}),`, ` import('@${contextName}/ui/${contextName}.page').then((m) => m.${pageClass}),`,
); );