backend
Installation
SKILL.md
Backend
Rules
Layout
- One package per bounded context; layers are its top-level folders:
domain/,application/,infrastructure/,api/. domain/imports nothing from the other layers, and nothing from NestJS, the ORM or HTTP. No decorators on domain classes, ever.api/is how the outside world drives the context, one folder per transport (http/,graphql/,ws/,consumers/);infrastructure/is how the context drives the outside world. A transport translates a request into a command or query and does nothing else.- A context owns its database — schema, client and migration history under
infrastructure/persistence/, never in a shared package. - Two shared backend packages, and no third:
kernelholds what a domain model extends (AggregateRoot,EntityId,DomainEvent, the exception bases) and has no dependencies whatsoever;applicationholds the machinery that runs a use case (transaction boundary, command bus, event dispatch) and may know NestJS. Neither ever holds a domain concept — something one context uses lives in that context.api-contractsis not a third: it is the wire, not the backend. - Repository interfaces live in
domain/repositories/;application/ports/is only for what the domain cannot express — clock, id generator, outbound calls. - Every folder that holds classes has a barrel
index.ts, so a file imports another folder in one line instead of one per class. A layer folder —domain/,application/,infrastructure/,api/— has none: nothing imports a layer as a whole. - Import any folder but your own through its barrel, however far away it is; import a sibling file inside your own folder directly. Going through your own barrel is a cycle.
- The package's own
index.tsis different: it is the context's public surface, and exports only the module, its commands and queries, and public id types. Never aggregates, entities, value objects or repositories. - kebab-case with a role suffix (
board.aggregate.ts,title.vo.ts,place-task.handler.ts). A use case is a folder holding its command and handler together.