docs(skills): extract house recipes as Claude Code skills for SSP templating
8 template-generic skills in .claude/skills/ (new-feature, new-context, value-object, form-machine, bff-endpoint, mutation-command, ui-component, new-ssp), condensed from CLAUDE.md/ARCHITECTURE/fp-tea/ADRs and pointing at this repo's worked examples. CLAUDE.md gains a pointer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
51
.claude/skills/new-context/SKILL.md
Normal file
51
.claude/skills/new-context/SKILL.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
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.
|
||||
---
|
||||
|
||||
# New bounded context
|
||||
|
||||
A context is a business **capability**, not a user group — a user group is an actor
|
||||
that may span contexts (ADR-0002). Check first whether the capability belongs in an
|
||||
existing context; new contexts are rare.
|
||||
|
||||
Naming: domain contexts are **Dutch** (`registratie`, `herregistratie`); only
|
||||
shared/reusable code is English. The context name is the ubiquitous language term.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Folders** — `src/app/<ctx>/{domain,application,infrastructure,ui}` (`contracts/`
|
||||
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.
|
||||
4. **Route** — lazy child under the persistent shell in `app.routes.ts`:
|
||||
|
||||
```ts
|
||||
{ path: '<ctx>', canActivate: [authGuard],
|
||||
loadComponent: () => import('@<ctx>/ui/<ctx>.page').then(m => m.CtxPage) }
|
||||
```
|
||||
|
||||
5. Build the first feature slice with the **new-feature** skill.
|
||||
|
||||
## 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`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
npm run lint && npm run build
|
||||
# prove the fence works: add a forbidden import (e.g. new ctx → @herregistratie/*),
|
||||
# confirm lint fails, remove it.
|
||||
```
|
||||
Reference in New Issue
Block a user