agentsclimarketplace

Ts ddd controller

Skill llodev/skills/skills/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

Install
npx -y skills add llodev/skills --skill ts-ddd-controller

Assembled 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.md completely.
  • 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? (200 payload, 201 CREATED, 204 NO_CONTENT, 200 for explicit OK on actions like /publish).
  • Mutation?: If yes, @UseGuards(ApiKeyGuard) is required (writes are 401 without x-api-key, 503 MUTATIONS_DISABLED when API_WRITE_KEY is unset — see references/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 with mapResultToHttp(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 canonical CelebrationsController mixes 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 throw a NestJS HttpException (or its subclasses like BadRequestException / NotFoundException) directly from a controller. Why: the error-code catalog in apps/api/src/shared/http/error-codes.ts is the single source of truth for code → HTTP status mapping. Throwing inline forks that mapping, defeats the Result pattern in use cases, and produces envelopes that don't match HttpExceptionFilter. Always pipe Result failures through mapResultToHttp.
  • 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 ApiKeyGuard on a write to "fix" a 503; the 503 is the intentional MUTATIONS_DISABLED contract when API_WRITE_KEY is 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. Date objects, raw storagePath without signed URL) into the response — funnel through the mapper.

References

  • references/controller-pattern.md — repo-grounded: folder layout, ZodValidationPipe, ApiKeyGuard semantics, 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-validated ConfigModule.forRoot, @nestjs/testing + supertest test bed.
  • examples/product.controller.nestjs.ts — runnable-style mirror of CelebrationsController.

What ships with it: 9 files

51.9 KB alongside SKILL.md, 1 of them executable

examples/

references/

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.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.