Imported from jagodabie/body-harmony-BE (
.cursor/skills/add-domain-module/SKILL.md). Install upstream withnpx skills add jagodabie/body-harmony-BE --skill add-domain-module. Copyright stays with the author.
Add Domain Module
Your goal is to generate a complete domain module scaffold that strictly follows the project’s layered architecture and conventions.
How to invoke
User types: /add-domain-module
Required input from the user
If not explicitly provided, ask for:
- domain name (e.g.
weight,nutrition,activity) — kebab-case only - list of endpoints (at least one): HTTP method + path + short description
example:
GET /weights – list - whether a Mongo model is required (yes / no)
If the user provides only the domain name, suggest and generate a default CRUD.
Required file structure (MUST)
For domain <domain> generate:
src/routes/<domain>.routes.tssrc/controllers/<domain>.controller.tssrc/controllers/<domain>.types.ts(if controller-level DTOs are needed)src/services/<domain>/<domain>.service.tssrc/services/<domain>/<domain>.types.ts(service input/output DTOs)src/repository/<domain>/<domain>.repository.ts(DB-agnostic interface)src/repository/<domain>/<domain>.mongo.repository.ts(Mongo implementation)src/repository/<domain>/<domain>.instance.ts(exports chosen implementation)src/repository/<domain>/<domain>.types.ts(repository-local types)
Swagger/OpenAPI documentation (if project uses separated docs pattern):
src/swagger/schemas/<domain>.schema.ts(component schemas: DTOs, models, errors)src/swagger/paths/<domain>.paths.ts(endpoint documentation)
If a model is required (Mongo-only):
src/models/<domain>/<domain>.model.tssrc/models/<domain>/<domain>.types.ts(optional)
All files and folders MUST use kebab-case and required suffixes.
Layer responsibilities (MUST)
routes
- Express route definitions only
- Connect routes to controllers
- No business logic
controllers
-
HTTP boundary only:
- parse request
- validate input
- map to DTOs
- call service
-
Return response or call
next(error) -
No database access
-
No business logic
services
- Business logic and orchestration
- Must NOT import Express types
- Must NOT import Mongo/Mongoose
- Depends only on repository interfaces / instances
- Throws domain errors (e.g.
NotFoundError,ValidationError)
repository
- Data access layer
- Implements DB-agnostic repository interfaces
- Allowed to import Mongo models and DB config
models
- Mongo-only (Mongoose schemas/models)
- Must NOT be imported outside repository
Types & DTOs (MUST)
-
Shared DB-agnostic contracts live in
src/types -
Domain-specific:
services/<domain>/<domain>.types.ts→ service DTOsrepository/<domain>/<domain>.types.ts→ repository types
Never pass raw req.body outside controllers.
Repository pattern (MUST)
<domain>.repository.tsexports an interface<domain>.mongo.repository.tsimplements the interface<domain>.instance.tsexports the chosen implementation instance- Services depend ONLY on the interface/instance, never on Mongo details
Import rules (MUST)
Controller may import:
- services
- types
- helpers
- middleware (if needed)
Service may import:
- repository interface (
*.repository.ts) - repository instance (
*.instance.ts) - types
- helpers
- non-DB config
Repository may import:
- Mongo models (from
src/models/**) - DB config
- helpers
- DB-agnostic types
Forbidden:
- controllers importing repositories directly
- services importing Mongo/Mongoose or models
- upward imports between layers
Default CRUD (if endpoints not provided)
Generate:
GET /<domain>– listGET /<domain>/:id– get by idPOST /<domain>– createPUT /<domain>/:id– updateDELETE /<domain>/:id– delete
Validation:
- Controller validates
idparams and create/update body (basic validation + TODO allowed) - Service assumes validated input
HTTP:
- list → 200
- get → 200 or NotFound
- create → 201
- update → 200 or NotFound
- delete → 204 or NotFound
Swagger / OpenAPI update (MUST)
After generating routes/controllers/services/repository, you MUST update the Swagger/OpenAPI documentation so the new endpoints appear in the docs.
Step 1: Detect Swagger setup
Search the codebase for one of these patterns:
src/swagger/folder withschemas/andpaths/subfolders → use pattern C (separated docs)swagger-jsdocwith annotations in routes → use pattern Aswagger-ui-express@swagger/@openapiannotations in route/controller filesopenapi.yaml/openapi.yml/swagger.yaml/swagger.yml→ use pattern B- a generated spec file (e.g.
src/swagger.ts,src/openapi.ts,docs/openapi.yaml)
Priority order:
- If
src/swagger/schemas/andsrc/swagger/paths/exist → use pattern C (PREFERRED) - If YAML/JSON OpenAPI file exists → use pattern B
- If annotations in routes → use pattern A
Check src/config/swagger.ts to see which paths are scanned by swagger-jsdoc.
Step 2: Update docs in the existing style
Depending on what you detect:
A) If the project uses inline annotation-based docs (swagger-jsdoc in routes)
-
Add JSDoc
@openapi(or@swagger) blocks for each endpoint near the route definition (preferred) or controller handler. -
Ensure:
tags: [<domain>]- request body schema for POST/PUT
- params schema for
id - response schemas (at least minimal)
-
Keep naming consistent with existing docs patterns.
B) If the project uses a YAML/JSON OpenAPI file
-
Add:
- new tag
<domain> pathsentries for each endpointcomponents.schemasfor create/update DTOs and response model
- new tag
-
Reuse shared schemas if they already exist.
C) If the project uses separated Swagger docs (PREFERRED)
Check if src/swagger/ folder exists with schemas/ and paths/ subfolders. If yes, this is the preferred pattern.
Create schema file: src/swagger/schemas/<domain>.schema.ts
/**
* @swagger
* components:
* schemas:
* <Domain>:
* type: object
* properties:
* id:
* type: string
* example: "507f1f77bcf86cd799439011"
* # ... other fields
* createdAt:
* type: string
* format: date-time
* updatedAt:
* type: string
* format: date-time
*
* Create<Domain>Request:
* type: object
* required:
* - <requiredField>
* properties:
* # ... fields for creation
*
* Update<Domain>Request:
* type: object
* properties:
* # ... fields for update (all optional)
*/
export {};
Create paths file: src/swagger/paths/<domain>.paths.ts
/**
* @swagger
* tags:
* - name: <Domain>
* description: <Domain> management endpoints
*/
/**
* @swagger
* /api/<domain>:
* get:
* summary: Get all <domain> entries
* tags: [<Domain>]
* responses:
* 200:
* description: List of <domain> entries
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: '#/components/schemas/<Domain>'
*/
/**
* @swagger
* /api/<domain>:
* post:
* summary: Create a new <domain> entry
* tags: [<Domain>]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Create<Domain>Request'
* responses:
* 201:
* description: Created successfully
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/<Domain>'
*/
/**
* @swagger
* /api/<domain>/{id}:
* get:
* summary: Get <domain> by ID
* tags: [<Domain>]
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Found
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/<Domain>'
* 404:
* description: Not found
*/
/**
* @swagger
* /api/<domain>/{id}:
* put:
* summary: Update <domain>
* tags: [<Domain>]
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Update<Domain>Request'
* responses:
* 200:
* description: Updated successfully
* 404:
* description: Not found
*/
/**
* @swagger
* /api/<domain>/{id}:
* delete:
* summary: Delete <domain>
* tags: [<Domain>]
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Deleted successfully
* 404:
* description: Not found
*/
export {};
Benefits of this pattern:
- Routes file stays clean and scannable (routing logic only)
- Schemas are reusable across multiple endpoints
- Clear separation: data models vs endpoint documentation
- Easy to review and maintain independently
Step 3: Keep it minimal but valid
Swagger additions MUST be valid OpenAPI and must not invent fields the API does not return. If DTO shapes are not fully defined yet, use a minimal schema and add TODOs.
Reuse shared schemas from src/swagger/schemas/ if they already exist (e.g., Error, ValidationError).
Final checklist before finishing
-
Verify folder/file placement
-
Verify kebab-case naming + suffixes
-
Ensure no illegal imports
-
Ensure services contain no Express or Mongo code
-
Ensure controllers do not touch repositories
-
Ensure every endpoint has:
- route
- controller handler
- service method
- repository method stub
-
Swagger/OpenAPI documentation:
- If using separated docs (pattern C):
src/swagger/schemas/<domain>.schema.tsexists with all DTOssrc/swagger/paths/<domain>.paths.tsexists with all endpoints- Routes file contains NO Swagger annotations (clean routing only)
- If using inline docs (pattern A/B):
- All endpoints have proper annotations/entries
- If using separated docs (pattern C):
-
Ensure Swagger/OpenAPI shows the new endpoints and schemas (test by visiting
/api-docs)