| name | sdcorejs-nestjs |
| description | NestJS code executor for approved/direct backend work with confirmed requirements. Use after execute-plan or for scaffold project/admin/module/entity CRUD, custom endpoints, actions, workflows, bulk, export work, or reuse of @sdcorejs/utils utilities. Loads _refs/nestjs/write-code/ packs; not for spec/plan/review/unresolved requests. Runs mandatory finish tail. Applies to nestjs. Runtime-localized. |
| allowed-tools | Read, Write, Edit, Bash, Glob, TodoWrite |
07 — Write Code (NestJS Orchestrator)
Shared Protocols
Before executing this skill:
- Read and apply
_refs/shared/tasklist.md for non-trivial execution tasks.
- Read and apply
_refs/shared/persona.md if a project persona exists.
- Read and apply
_refs/shared/project-context.md for project memory, resume checkpoints, summaries, specs/plans, tasks, and relevant memories.
- Current user request, current files, diffs, logs, failing tests, and command output override stored context.
- Before presenting user-facing choices, approval gates, yes/no questions, or mode selections, read and apply
_refs/shared/user-choice-prompt.md so options are presented as sequential numbered choices.
Purpose
Single entry point for generating NestJS modular-monolith backend code on the @sdcorejs/nestjs core. Transforms an approved plan + the user's confirmed scope into runnable backend code:
- App scaffold (one NestJS app, one Postgres, schema-per-module,
SdCoreModule.forRoot kernel)
- Bounded-context modules (
src/modules/<module>/)
- Full CRUD entity stacks (entity / repository / service / controller / Zod schema / DTO)
- Custom / non-CRUD endpoints (domain methods, cross-module access, workflow transitions, bulk operations, Excel export)
This skill is an orchestrator: it does NOT inline the full generation rules for every concern. It picks the right reference pack for each scope item and reads it on demand. The detailed rules + code templates for each concern live in _refs/nestjs/write-code/*.md.
Step 0 — Persona
Read <target>/.sdcorejs/persona.md (project-local persona, if present) and _refs/shared/persona.md to detect technical vs non-technical framing. For a non-technical persona, open each pack in plain language before generating (each pack carries its own "Persona Step 0" narration). For a technical persona, skip the narration and generate directly. Either way, respond in the user's language at runtime.
Step 0.1 — Pre-flight: ensure project summary
Before dispatching ANY reference, run sdcorejs-explore (summary-read). If <target>/.sdcorejs/summary.md is missing or stale in this write-approved executor, run summary-refresh first so generation uses the real layout and does not invent module/base-class paths or duplicate shared abstractions. If the summary exists and is fresh enough, read it and continue. Exception: when this run is itself a brand-new init-project, there is no project to summarize yet; run summary-refresh at the END of init instead (see init-project.md Step 10).
After ensuring the summary exists, READ the profile field from <target>/.sdcorejs/summary.md (default simple if absent). Pass the resolved profile into EVERY dispatched pack (init-project / init-module / init-entity / actions) — each pack emits only that profile's templates (see each pack's 'Profile (read FIRST)' section).
Reference — read the core catalog FIRST
Before generating any backend code, read _refs/nestjs/core-catalog.md. It is the authoritative inventory of the @sdcorejs/nestjs core package — the import sub-paths (@sdcorejs/nestjs, /core, /auth, /services, /validation, /queue, /i18n, /features), the building blocks (BaseEntity + WithAudit / WithTimestamps mixins, BaseRepository, BaseService, BaseController, AuthGuard, @HasPermission, ZodValidationGuard, SdCoreModule.forRoot, ApiResponse / apiError), and the version pin. Every import in the packs MUST match a sub-path the catalog documents — do not invent imports. The architecture WHY behind these choices lives in _refs/nestjs/architecture-principles.md.
Before writing any helper, formatter, normalizer, validator helper, mapper utility, paging/filter helper, random-id helper, query-param helper, or shared constant, read _refs/shared/sdcorejs-utils.md and reuse @sdcorejs/utils when it covers the behavior. The package must be a direct target-project dependency before generated code imports it; do not rely on @sdcorejs/nestjs transitive dependencies. Never use BrowserUtilities in NestJS code.
Per-pack trigger catalog (dispatch table)
For each scope item in the confirmed plan (or the direct request), match it to a pack, READ that pack under _refs/nestjs/write-code/, and follow it. Load ON DEMAND only — read the one pack for the step you are executing, not all four.
| Request / scope item | Pack to read |
|---|
| Scaffold a fresh backend — "initialize backend / init backend", "bootstrap a modular-monolith API on @sdcorejs/nestjs", "set up the NestJS project skeleton" (no existing project yet) | _refs/nestjs/write-code/init-project.md (run FIRST before any module/entity work) |
| Always — the admin module (authn/authz authority): users/roles/permissions [+tenant/department enterprise] | _refs/nestjs/write-code/init-admin.md (ALWAYS run, right after init-project) |
| Add a bounded-context module — "create module X / add a domain module", "scaffold the crm / masterdata / billing module", "set up a new module before adding entities" | _refs/nestjs/write-code/init-module.md |
| Add a full CRUD entity — "add entity X / create CRUD for X", "scaffold the task / customer / invoice entity with full CRUD", "add an entity + repository, service, controller, validation" (entity / repository / service / controller / schema / DTO) | _refs/nestjs/write-code/init-entity.md |
| Custom / non-CRUD endpoints — "add action / approve button / status transition" (workflow), "my screen / team work" (caller-scoped), "export Excel / export report", "import / bulk create / bulk delete", any domain method or cross-module access on top of an existing entity stack | _refs/nestjs/write-code/actions.md |
Each pack further links the literal code templates / snippets it renders. For a brand-new backend, the natural sequence is init-project → admin → init-module → init-entity → actions.
Execution order + subagent fan-out
Execution order: project → admin → module → entity → actions. init-admin ALWAYS runs right after init-project and BEFORE any init-module / init-entity — it owns the project's IPermissionStrategy + user-lookup JwtStrategy, so domain modules' @HasPermission resolve against it. If the plan touches multiple items, run them in this order. Most backend work shares DB / module state, so the default is sequential — do NOT parallelize entity stacks that touch the same module wiring.
Parallel fan-out: let sdcorejs-parallel-dispatch classify plan-derived
units by dependency topology, mechanical path/resource ownership, runtime
capability, and integration cost. Two expensive independent units or
heterogeneous units may qualify; units that append to the same
<module>.module.ts barrels, MODULE_SCHEMAS, shared databases, ports, caches,
or RouterModule.register arrays require separate waves or sequential work.
TDD gate — mandatory before each code-generating step
Before writing any production file (entity / repository / service / controller), invoke sdcorejs-test (tdd mode):
- Write the failing test first (unit test for service logic / business rules; e2e spec for controller endpoints — HTTP verb + expected status + response shape) → run → confirm RED.
- Generate the production file with minimal passing code → run → confirm GREEN.
- Refactor if needed → run → confirm still GREEN.
Skip only for pure config (nest-cli.json, tsconfig.json, .env.example) and the RouterModule.register / MODULE_SCHEMAS registrations (framework wiring, no business behaviour).
Mandatory tail chain
MANDATORY FINISH GATE (always — standalone trigger OR full SDLC flow)
STOP and present the consolidated finish gate from _refs/shared/finish-gate.md before running ANY tail step. UNCONDITIONAL: it fires even when this skill was triggered directly for a one-line request (e.g. "add entity", "add endpoint") — NOT only inside the spec→plan flow. The gate surfaces tests / user-guide / technical-doc / review choices with defaults so the user always knows these steps exist and can opt out of new user/technical docs. "Small change" is not a reason to skip the gate.
Then hand off in this exact order, honoring the gate's answers (skip = omit
that step; everything not skipped runs):
Documentation supplement: immediately after the Finish Gate test decision, run
sdcorejs-documentation (documentation-gate mode) and read
_refs/documentation/gate.md. This gate asks or loads saved project
preferences from <target>/.sdcorejs/documentation/preferences.md for
user-guide and technical-doc only. It must ask before
creating a missing corresponding user-guide or technical-doc for a new feature.
code-documentation is automatic for touched source files and is not controlled
by this approval gate.
- (if Tests not skipped)
sdcorejs-test - happy-path tests for what was generated (unit + integration via real DI + pg-mem; e2e via supertest against a real test PG where the layer warrants it)
- (if Review not skipped)
sdcorejs-review (auto-detects NestJS and loads _refs/nestjs/review-code.md) - NestJS/PostgreSQL/TypeORM/Zod code-review table with severity, group, file/line, risk, fix, and gate
- (if Review not skipped)
sdcorejs-repair-loop - apply findings, iterate until BLOCKER/REQUIRED findings are fixed or explicitly deferred
sdcorejs-documentation (code-documentation mode) - automatically apply concise source-code documentation rules to touched source files. Do NOT ASK for approval. Rules live in _refs/documentation/code-documentation.md.
sdcorejs-product (when user-visible feature traceability is needed) - seed/update .sdcorejs/docs/product/ with requirement, implementation, and test mapping
- (if Technical doc approved)
sdcorejs-documentation (write-technical-doc mode) - create/update the approved technical doc from source evidence.
_refs/orchestration/tail/auto-docs.md (always) - session summary written to <target>/.sdcorejs/docs/nestjs/
- (if User guide approved)
sdcorejs-documentation (write-user-guide mode) - create/update the touched module's .sdcorejs/documentation/user-guides/<module>.md only when approved by the documentation gate or explicitly requested. Per-module incremental; the aggregate rebuilds under .sdcorejs/documentation/ at ship.
_refs/orchestration/tail/auto-task-tracker.md (always) - tick [x] completed tasks, append new ones from the doc's "Next suggested action" / "Open questions"
sdcorejs-explore (memories mode) - only if durable knowledge surfaced (recurring convention, stakeholder constraint, anti-pattern)
sdcorejs-ship (verify-before-done mode) (always) - BLOCK "done" until every acceptance criterion in the selected scope is verified or explicitly deferred
sdcorejs-ship (branch-ready mode) (always) - final read-only branch-ready gate over the final diff before any Git artifact handoff. No writes after branch-ready unless branch-ready is run again.
The FINISH GATE is mandatory and unconditional. The always-on plumbing steps (auto-docs tail ref, auto-task-tracker tail ref, memories, sdcorejs-ship (verify-before-done mode), and final sdcorejs-ship (branch-ready mode)) run regardless of gate answers. Do NOT skip sdcorejs-ship (verify-before-done mode); that is how acceptance criteria silently slip.
When to use
- After
sdcorejs-execute-plan dispatches an approved NestJS plan (user said "OK", "approve", "go ahead", or equivalent at sdcorejs-plan, sdcorejs-plan has written the approved plan snapshot, and the user answered the sequential/parallel question).
- OR as the single entry point for any direct backend code-gen request matching the dispatch table above.
If no approved plan exists and the request is non-trivial, route back to sdcorejs-brainstorming / sdcorejs-spec / sdcorejs-plan first. NOT for spec/plan authoring, code review, or angular/nextjs/test work (those are separate skills).
Critical write-target rule
All generated files are written to the TARGET backend project, NEVER into this agent repo (sdcorejs-agent). The packs are the source of truth — render them into the user's chosen project directory.
Rules
MUST DO
- Show a live progress checklist with TodoWrite from the START of generation — one checkbox item per planned unit (each entity / module / endpoint / pack step) PLUS the finishing steps (tests, review, code-documentation, technical-doc, user-guide). Keep exactly one item
in_progress; flip it to completed the moment that unit is done and start the next. Update after EACH task, never batch at the end — this is how the user tracks progress. Create it before writing the first file.
- Present the MANDATORY FINISH GATE (
_refs/shared/finish-gate.md) after EVERY code-gen — standalone trigger or full SDLC flow. It surfaces tests / user-guide / technical-doc / review so the user always knows these exist. NEVER silently end after generating code, and NEVER skip the gate because the request was a one-liner.
- Every generated backend includes the
admin module (init-admin) — the authn/authz authority. Run it right after init-project, before domain modules. Account ops proxy the Keycloak Admin API; permissions are app-DB role→code (NOT realm roles).
- Read
_refs/nestjs/core-catalog.md before generating; every import must match a documented sub-path.
- Dispatch the matching pack on demand; follow it instead of re-deriving rules here.
- Enforce the architecture principles (
_refs/nestjs/architecture-principles.md) on every generated file: WithAudit(BaseEntity) base, BaseRepository / BaseService / BaseController inheritance, guard order @UseGuards(AuthGuard, ZodValidationGuard(schema)) + per-route @HasPermission, Zod-not-class-validator, explicit QueryRunner for multi-table writes, soft-delete by default, bilingual error envelope via the i18n catalog.
- Resolve the
profile (simple default | enterprise) once from .sdcorejs/summary.md and emit it CONSISTENTLY across every pack in the project — never mix profiles within one backend.
- Match the user's language at runtime; all error messages, log messages, and comments preserve locale-specific marks.
- Run the
@sdcorejs/utils reuse preflight before writing helper/formatter/normalizer/mapper/paging/filter utility code; report reused utilities and justify any custom helper.
- Run the full tail chain after the last step.
Documentation Gate Rule
- Inside the mandatory finish gate, run
_refs/documentation/gate.md immediately after the test decision. It owns user-guide / technical-doc creation or update approval. code-documentation is automatic and is not controlled by this gate.
MUST NOT
- Generate code outside the approved plan (no surprise utility files).
- Invent imports the core catalog does not document.
- Inline
class-validator decorators — Zod is the validation contract.
- Return single-language error messages — go through the i18n catalog (
{ code, message }).
- Skip the guard order (
AuthGuard before ZodValidationGuard).
- Skip
sdcorejs-ship (verify-before-done mode) — even when tests pass, acceptance criteria are a separate check.
- Recreate helper behavior already covered by
@sdcorejs/utils, deep-import from @sdcorejs/utils/dist/*, or use browser-only utilities in backend code.
Related references
_refs/nestjs/core-catalog.md — @sdcorejs/nestjs core API inventory (read FIRST)
_refs/nestjs/write-code/{init-project,init-admin,init-module,init-entity,actions}.md — the on-demand packs
_refs/nestjs/architecture-principles.md — the WHY behind the conventions
_refs/sdlc/nestjs.md — design-phase (brainstorming/spec/plan) patterns
sdcorejs-execute-plan — runs before; the approved plan is the input
- Tail chain — see "Mandatory tail chain" above