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>
2.2 KiB
name, description
| name | description |
|---|---|
| new-context | 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
-
Folders —
src/app/<ctx>/{domain,application,infrastructure,ui}(contracts/only once it gets a wire seam). Empty layers can wait; don't scaffold placeholders. -
Path alias — add
"@<ctx>/*": ["src/app/<ctx>/*"]totsconfig.jsonpaths. Aliases are direction statements; always import cross-context via the alias. -
eslint boundaries (
eslint.config.mjs) — dependencies point inward and towardsharedonly. Copy the existing per-context block (thebriefblock is the minimal leaf-context example) and:- add a block for
src/app/<ctx>/**/*.tsbanning imports from every context it may not depend on; - add
@<ctx>/*to the ban lists ofshared/**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 importsinfrastructure) match by glob and cover the new context automatically.
- add a block for
-
Route — lazy child under the persistent shell in
app.routes.ts:{ path: '<ctx>', canActivate: [authGuard], loadComponent: () => import('@<ctx>/ui/<ctx>.page').then(m => m.CtxPage) } -
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
npm run lint && npm run build
# prove the fence works: add a forbidden import (e.g. new ctx → @herregistratie/*),
# confirm lint fails, remove it.