Adding an API endpoint
- Add or extend a controller in
src/modules/<area>/<feature>/. Do not put a new domain controller insrc/commonunless it is cross-cutting auth or files, which is where those already live. - Set the path without the
/v1prefix. Versioning adds it. UseVERSION_NEUTRALonly when you mean to, as health and voice webhooks do. - Declare a DTO class with class-validator. The global
ValidationPipeusestransform,whitelist, andforbidNonWhitelisted. - Add
@ApiOperationand@DocResponseso the generated OpenAPI document picks the route up. Do not also hand-write the fields into this docs site. - Add
@TenantScoped()for tenant data. - Add
@RequirePermissions('AREA:ACTION')unless every authenticated user should be allowed. There is no later deny. - Add
@AuditLogif the call mutates and should be audited. The listener writes in-process. - Inject a service, not
DatabaseService. - If the write has a side effect, enqueue the outbox inside the service transaction. Do not emit from the controller.
- Add a Jest spec under
test/and runyarn verify:test-pairs.
Public routes (@PublicRoute) skip the access JWT. Refresh token is the pattern that is public and still has its own guard. Copy that only when you have a second credential to check.
Warehouse-sensitive routes still pass WarehouseGuard for logged-in users. You do not need a second warehouse check if the id is in the header, route, query, or body. The guard already narrows.