Appearance
API Review Checklist
This checklist is the operational companion to API Review Guidelines.
Use it when reviewing backend PRs manually or when automating review prompts for AI agents.
Review Output Contract
- Always report findings in this order:
hard-fail,warn,pass - A
hard-failblocks merge unless the PR includes an explicit architectural reason and the docs are updated in the same change - A
warndoes not block merge by itself, but should request alignment when the change is still easy to correct - A
passmeans the reviewer checked the item and found no issue worth reporting - Every finding should include the file path, the violated rule, why it matters, and what the preferred fix looks like
Hard-Fail Checklist
- [ ] No new direct dependency reaches into another feature module's private internals
- [ ] New request and response contracts live in
packages/schemasinstead of ad hoc API-local DTOs - [ ] Every new body payload is validated at the controller boundary with
@Body(new ZodValidationPipe(...)) - [ ] Persistence logic stays in repositories, not in controllers or command/query handlers
- [ ] Repository implementations handle persistence mapping explicitly and keep repository telemetry inside the repository when metrics exist
- [ ] Commands with multiple related writes use a single transaction
- [ ] Public endpoints do not leak private, draft, admin-only, or internal metadata when a public/private split is required by the domain
- [ ] Not-found and similar domain errors match the actual aggregate or resource being loaded
- [ ] New persistence entities extend
BasePersistenceEntitycleanly without redefining inheritedid,createdAt, orupdatedAt - [ ] SQL table and column names stay in
snake_casewhile TypeScript properties stay incamelCase - [ ] Shared repository, port, and service boundaries use
I...interfaces plus Symbol DI tokens
Warn Checklist
- [ ] Controllers stay thin: validate input, gather context, dispatch CQRS, unwrap results, and return the final HTTP contract
- [ ] Mutation endpoints return an explicit response contract instead of leaving the response shape implicit
- [ ] Presentation code owns DTO mapping, especially when deciding public vs private output
- [ ]
toDtomethods acceptoptions: IMapperOptions = DefaultMapperOptionsand validate by default - [ ]
toDtomappings whitelist response fields explicitly instead of spreading the whole entity or persistence object - [ ] Internal
toDomainandtoPersistencepaths prefer safe helpers such asmapProperties(...)or controlled spread-based mapping when that reduces missed fields - [ ] Simple one-off command/query definitions stay in the same file as the handler unless reuse justifies a split
- [ ] Cross-boundary imports prefer
@api/*aliases over deep relative chains - [ ] New shared schema identifiers use explicit UUID v7 validation such as
z.uuidv7() - [ ] Schema defaults match currently supported product behavior and do not introduce unsupported business states
- [ ] Tests mirror the app structure and stay focused on the behavior under review
Common Fix Patterns
- Controller contract: if a command endpoint currently returns nothing, return the updated DTO, a shared success payload, or an explicit empty object when that is the established API contract
- Public/private mapping: create separate public and private controller flows and pass mapper options such as
publicVersionfrom the presentation layer - Mapper safety: use broad mapping helpers only for internal transformations; keep
toDtoexplicit and field-by-field - Persistence base model: keep business identifiers in dedicated columns like
orgId; do not replace the semantic role of the base primary key - Repository save flow: return the saved aggregate when the caller needs the persisted state after update
- CQRS file layout: keep the message type and handler together until a real reuse case appears
- Schema constraints: tighten IDs and defaults in
packages/schemasto match the real API contract, not placeholder assumptions
Suggested AI Review Response Shape
md
## Hard-Fail
- [ ] <file>: <rule> - <why this is a blocking issue> - <preferred fix>
## Warn
- [ ] <file>: <rule> - <why this should be aligned> - <preferred fix>
## Pass
- [x] Checked controller boundary validation
- [x] Checked repository/persistence ownershipEscalation Rule
- If a PR intentionally breaks a
hard-failrule, ask for the architectural reason explicitly - If the change is accepted as a new convention, update
apps/docs/conventions/backend/api-review-guidelines.mdand this checklist in the same PR