feat(WP-67): merge behandelportal into this repo as a monorepo
Restructures into apps/ssp + apps/behandelportal (two Angular projects) plus libs/shared + libs/beheer (cross-app libraries), replacing WP-61's separate sibling repo. That split had already produced real drift: a hand-vendored copy of the backend's OpenAPI doc, a shared/ui+layout tree forked and silently diverging (7 files), and beheer + the styles.scss token bridge duplicated byte-for-byte across both repos. - git mv the SSP's src/app/* into apps/ssp/; fold shared/, beheer/, environments/, the Storybook docs/*.mdx, and styles.scss into libs/shared + libs/beheer (all confirmed identical between the two repos before merging). auth stays deliberately duplicated per ADR-0002 (actor-specific, expected to diverge) - amended there. - One generated API client (libs/shared), no more vendored swagger.json. - .dependency-cruiser split into a base factory + one config per app, and Storybook into .storybook-ssp/.storybook-behandelportal - both forced by the @auth/* alias resolving to different directories per app. - SiteHeaderComponent/ShellComponent gained HEADER_NAV_ITEMS/ HEADER_ADMIN_LINKS/DEBUG_PANEL injection tokens so each app supplies its own nav/admin-links/dev-panel instead of one being hardcoded. - CLAUDE.md, ARCHITECTURE.md, dependencies.md, and ADR-0002 updated; WP-67 backlog entry documents the full decision trail. npm run ci green (lint, dep:check x2, 360 tests across ssp/ behandelportal/shared/beheer, both localized builds, backend tests, snippet + api-client drift); both dev servers, both Storybook instances, and docker compose verified working. The old sibling repo (/home/eho/repos/behandelportal) is left untouched, not deleted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+31
-20
@@ -12,13 +12,21 @@
|
||||
* Positional args skip the prompts, e.g. `npx plop value-object registratie KvkNummer`.
|
||||
*/
|
||||
export default function (plop) {
|
||||
// WP-67: shared/beheer moved to libs/ (cross-app libraries); every other context is
|
||||
// ssp-only today (behandelportal has its own auth/behandeling, not covered by this
|
||||
// ssp-assuming heuristic — run these generators by hand for a behandelportal context).
|
||||
const LIBS = ['shared', 'beheer'];
|
||||
plop.setHelper('ctxRoot', (context) =>
|
||||
LIBS.includes(context) ? `libs/${context}/src` : `apps/ssp/src/app/${context}`,
|
||||
);
|
||||
|
||||
const CONTEXT_PROMPT = {
|
||||
type: 'input',
|
||||
name: 'context',
|
||||
message: 'Context (shared | auth | registratie | herregistratie | brief | beheer):',
|
||||
message: 'Context (shared | beheer | auth | registratie | herregistratie | brief):',
|
||||
};
|
||||
const remindEnXlf = () =>
|
||||
'⚠ The generated $localize id needs an English <target> in src/locale/messages.en.xlf before `npm run ci` (the localize gate fails otherwise).';
|
||||
'⚠ The generated $localize id needs an English <target> in apps/ssp/src/locale/messages.en.xlf before `npm run ci` (the localize gate fails otherwise).';
|
||||
|
||||
plop.setGenerator('value-object', {
|
||||
description: 'Branded value object + parser + spec ("parse, don\'t validate")',
|
||||
@@ -29,12 +37,12 @@ export default function (plop) {
|
||||
actions: [
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/app/{{context}}/domain/value-objects/{{kebabCase name}}.ts',
|
||||
path: '{{ctxRoot context}}/domain/value-objects/{{kebabCase name}}.ts',
|
||||
templateFile: 'plop-templates/value-object.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/app/{{context}}/domain/value-objects/{{kebabCase name}}.spec.ts',
|
||||
path: '{{ctxRoot context}}/domain/value-objects/{{kebabCase name}}.spec.ts',
|
||||
templateFile: 'plop-templates/value-object.spec.hbs',
|
||||
},
|
||||
remindEnXlf,
|
||||
@@ -50,12 +58,12 @@ export default function (plop) {
|
||||
actions: [
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/app/{{context}}/domain/{{kebabCase name}}.machine.ts',
|
||||
path: '{{ctxRoot context}}/domain/{{kebabCase name}}.machine.ts',
|
||||
templateFile: 'plop-templates/form-machine.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/app/{{context}}/domain/{{kebabCase name}}.machine.spec.ts',
|
||||
path: '{{ctxRoot context}}/domain/{{kebabCase name}}.machine.spec.ts',
|
||||
templateFile: 'plop-templates/form-machine.spec.hbs',
|
||||
},
|
||||
remindEnXlf,
|
||||
@@ -73,54 +81,57 @@ export default function (plop) {
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
// WP-67: this generator only scaffolds an ssp context — behandelportal's contexts
|
||||
// (auth, behandeling) predate it and aren't covered by this heuristic.
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/app/{{kebabCase name}}/ui/{{kebabCase name}}.page.ts',
|
||||
path: 'apps/ssp/src/app/{{kebabCase name}}/ui/{{kebabCase name}}.page.ts',
|
||||
templateFile: 'plop-templates/context.page.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/app/{{kebabCase name}}/domain/.gitkeep',
|
||||
path: 'apps/ssp/src/app/{{kebabCase name}}/domain/.gitkeep',
|
||||
templateFile: 'plop-templates/gitkeep.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/app/{{kebabCase name}}/application/.gitkeep',
|
||||
path: 'apps/ssp/src/app/{{kebabCase name}}/application/.gitkeep',
|
||||
templateFile: 'plop-templates/gitkeep.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/app/{{kebabCase name}}/infrastructure/.gitkeep',
|
||||
path: 'apps/ssp/src/app/{{kebabCase name}}/infrastructure/.gitkeep',
|
||||
templateFile: 'plop-templates/gitkeep.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: 'src/app/{{kebabCase name}}/contracts/.gitkeep',
|
||||
path: 'apps/ssp/src/app/{{kebabCase name}}/contracts/.gitkeep',
|
||||
templateFile: 'plop-templates/gitkeep.hbs',
|
||||
},
|
||||
{
|
||||
// tsconfig path alias — inserted right after the `"paths": {` line so it's stable
|
||||
// across repeated runs regardless of what's already been added.
|
||||
type: 'modify',
|
||||
path: 'tsconfig.json',
|
||||
path: 'apps/ssp/tsconfig.json',
|
||||
pattern: /"paths": \{\n/,
|
||||
template: '"paths": {\n "@{{kebabCase name}}/*": ["src/app/{{kebabCase name}}/*"],\n',
|
||||
},
|
||||
{
|
||||
// Boundary entry (WP-38's single source of truth) — inserted right after the
|
||||
// `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.)
|
||||
// ssp dep-cruiser config's CONTEXT_ALLOWED object literal opens, 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',
|
||||
path: '.dependency-cruiser.js',
|
||||
pattern: /const CONTEXT_ALLOWED = \{\n/,
|
||||
template: 'const CONTEXT_ALLOWED = {\n {{kebabCase name}}: [],\n',
|
||||
path: '.dependency-cruiser.ssp.js',
|
||||
pattern: /\.dependency-cruiser\.base\.js'\)\(\n {2}\{\n/,
|
||||
template: ".dependency-cruiser.base.js')(\n {\n {{kebabCase name}}: [],\n",
|
||||
},
|
||||
{
|
||||
// Lazy route — inserted right before the catch-all, which never moves.
|
||||
type: 'modify',
|
||||
path: 'src/app/app.routes.ts',
|
||||
path: 'apps/ssp/src/app/app.routes.ts',
|
||||
pattern: " { path: '**', redirectTo: 'login' },",
|
||||
template: ` {
|
||||
path: '{{kebabCase name}}',
|
||||
|
||||
Reference in New Issue
Block a user