Ts ddd controller
Create, review, or guide HTTP controllers in a TypeScript + DDD api. Use when the request involves `*.controller.ts` under `apps/api/src/<bc>/presentation/controllers/`, route definition, `ApiKeyGuard` on mutations, `ZodValidationPipe` against `@acme/<bc>-contracts` schemas, use case orchestration, mapping `Result` to HTTP via `mapResultToHttp`, signed-URL enrichment through a response mapper, HTTP status conventions (200/201/204), or controller tests using `@nestjs/testing` + `supertest` with an in-memory repository.From its SKILL.md
npx -y skills add llodev/skills --skill ts-ddd-controllerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- reads credentialsReads from 1 credential source: `API_WRITE_KEY`.
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.1 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it
TypeScript DDD Controller
MANDATORY — READ ENTIRE FILE: before writing or reviewing any controller, read
references/controller-pattern.md completely.
Then load the framework reference:
- NestJS 11 (this repo) → also read
references/nestjs.mdcompletely. - Other frameworks (Express, Fastify, Hono…) are not yet documented; apply the principles from
controller-pattern.md.
Do NOT load sibling DDD skills (ts-ddd-entity, ts-ddd-use-case, ts-ddd-repository, ts-ddd-dto, ts-ddd-value-object) unless the request explicitly asks for them.
When to trigger this skill
- File path matches
apps/api/src/<bc>/presentation/controllers/*.controller.ts. - Request mentions
@Controller,@Get/@Post/@Put/@Delete,@UseGuards(ApiKeyGuard),ZodValidationPipe,mapResultToHttp, or a response mapper. - Adding/changing routes for a bounded context (e.g.
celebrations). - Wiring controllers into a
<bc>.module.ts. - Writing a controller test under
apps/api/test/<bc>/presentation/controllers/*.controller.test.ts.
Where controllers live
apps/api/src/<bc>/
presentation/
controllers/<name>.controller.ts
guards/api-key.guard.ts
mappers/<name>-response.mapper.ts
index.ts ← barrel per leaf folder
application/
usecases/ ← injected here
<bc>.module.ts ← registers controllers, mappers, guard, use cases
Every leaf folder exports through an index.ts barrel. Imports across layers use the path aliases @<bc>/* (e.g. @celebrations/application/usecases) and @shared/* (apps/api/src/shared/*); inside the same folder use relative paths. Cross-package types come from @acme/<bc>-contracts and @acme/shared — never @ddd/shared or any older name.
Before You Start
Answer these before writing a handler:
- Contract: status + payload? (
200payload,201 CREATED,204 NO_CONTENT,200for explicit OK on actions like/publish). - Mutation?: If yes,
@UseGuards(ApiKeyGuard)is required (writes are 401 withoutx-api-key, 503MUTATIONS_DISABLEDwhenAPI_WRITE_KEYis unset — seereferences/controller-pattern.md). - Wire shape: Which Zod schema in the contracts package validates
@Body/@Param? Don't redefine wire types locally. - Failure mapping: Is the error code already in
apps/api/src/shared/http/error-codes.ts? If new, add it there with the right HTTP status before throwing it from a use case. - Response shape: Does the entity need enrichment (signed Storage URLs, ISO dates)? Then go through the response mapper, not raw entity props.
Core Rules
- Controllers are thin translators between HTTP and the application layer. No business logic, no domain conditionals, no repository calls.
- Inject use cases and mappers via the constructor — never
new UseCase(...). - Validate at the boundary with
ZodValidationPipe(schema)over schemas exported by the BC's contracts package. - Map
Result→ HTTP withmapResultToHttp(result, ok => …)from@shared/http. Don't throw NestJS exceptions directly from controller handlers. - Mutations carry
@UseGuards(ApiKeyGuard). Reads stay public. - Enrich entity → response DTO inside a dedicated mapper (e.g.
CelebrationResponseMapper) — that's where signed URLs, date serialization, and tagged-union variant handling live.
NEVER
- NEVER apply
@UseGuards(ApiKeyGuard)at the class level. Why: it 401s every read. The canonicalCelebrationsControllermixes public reads (GET /celebrations,GET /celebrations/:slug) with per-method-guarded writes; a class-level guard breaks that mix and silently breaks the public web client. Always attach@UseGuards(ApiKeyGuard)to each mutating handler individually. - NEVER
throwa NestJSHttpException(or its subclasses likeBadRequestException/NotFoundException) directly from a controller. Why: the error-code catalog inapps/api/src/shared/http/error-codes.tsis the single source of truth forcode → HTTP statusmapping. Throwing inline forks that mapping, defeats theResultpattern in use cases, and produces envelopes that don't matchHttpExceptionFilter. Always pipeResultfailures throughmapResultToHttp. - NEVER put domain logic, branching, or repository access inside a controller method.
- NEVER instantiate use cases or mappers with
new— breaks DI and tests. - NEVER remove
ApiKeyGuardon a write to "fix" a 503; the 503 is the intentionalMUTATIONS_DISABLEDcontract whenAPI_WRITE_KEYis unset. - NEVER redefine wire-shape interfaces in the controller; import the DTO type + Zod schema from
@acme/<bc>-contracts. - NEVER leak entity internals (e.g.
Dateobjects, rawstoragePathwithout signed URL) into the response — funnel through the mapper.
References
references/controller-pattern.md— repo-grounded: folder layout,ZodValidationPipe,ApiKeyGuardsemantics,mapResultToHttp, response mapper, test strategy (enum members in fixtures).references/nestjs.md— NestJS 11 patterns actually used here: DI symbol tokens (FIREBASE_APP),@Inject(SYMBOL),@Global()modules (FirebaseModule,AppConfigModule), Zod-validatedConfigModule.forRoot,@nestjs/testing+supertesttest bed.examples/product.controller.nestjs.ts— runnable-style mirror ofCelebrationsController.
What ships with it: 9 files
51.9 KB alongside SKILL.md, 1 of them executable
docs/
- i18n/README.es-ES.md5.1 KB
- i18n/README.pt-BR.md5.0 KB
examples/
- product.controller.nestjs.tsruns4.1 KB
references/
- controller-pattern.md19.1 KB
- nestjs.md11.2 KB
- CHANGELOG.md1012 B
- LICENSE1.1 KB
- package.json818 B
- README.md4.7 KB
Gives 0 of the 12 instructions most test skills give in ~1.3k tokens
Counted across 1,201 of the 2,096 authors here whose files we hold, read 2026-09-06
- Write a failing test before writing codein 43 of 1201, across 36 files
- Run the full test suitein 36 of 1201, across 35 files
- Test only one variable per experimentin 34 of 1201, across 17 files
- Read product marketing context before asking questionsin 34 of 1201, across 14 files
- Mock external dependenciesin 34 of 1201, across 30 files
- Define primary, secondary, and guardrail metricsin 33 of 1201, across 16 files
- Pre-determine sample size before startingin 31 of 1201, across 14 files
- Test behavior rather than implementationin 31 of 1201, across 29 files
- Formulate a hypothesis before designing a testin 30 of 1201, across 13 files
- Document every test hypothesis, variant, and resultin 29 of 1201, across 11 files
- Use descriptive test function namesin 25 of 1201, across 21 files
- Commit to the methodology without stopping earlyin 24 of 1201, across 8 files
Said here and by no other author read
- Read controller pattern and NestJS references before starting
- Keep controllers as thin translators between HTTP and application layer
- Inject use cases and mappers via the constructor
- Validate request data using ZodValidationPipe and contract schemas
- Map Result objects to HTTP responses using mapResultToHttp
- Attach ApiKeyGuard to individual mutating handlers only
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.