Read
.agents/software-principles/SKILL.mdfirst.
Pre-Code Checklist
- Resource + HTTP method + action
- Request → response contract (input shape, output shape, errors)
- Auth requirement (public / authenticated / role-gated)
- Failure scenarios + validation rules
Response Envelope
Follow existing convention if one exists. If starting fresh, pick one shape and apply consistently. Never mix shapes across endpoints.
Required regardless of shape:
- Success and error responses must be distinguishable
- Validation errors must include field-level detail, not just a generic message
- Error responses must never expose stack traces, query strings, or internal paths
- Never return untyped raw objects
Design Rules
- Versioning — prefix all routes
/api/v1/ - Endpoints — plural nouns, kebab-case:
/api/v1/posts,/api/v1/post-categories - Query params —
page,limit,sort,filter[key]=value - Auth —
Authorization: Bearer <token>(JWT/opaque) or HTTP-only cookie (same parent domain) - Pagination — all list endpoints:
data: { items: T[], pagination: { page, limit, totalItems, totalPages } } - CORS — exact origin only. Never wildcard with credentials
- Naming — camelCase or snake_case — consistent throughout project
- Docs — expose OpenAPI spec at
/api/docsor/openapi.jsonwhen feasible
Architecture
- Route handlers thin — business logic in service/use-case layer
- Global error handler → catches all unhandled errors → safe fallback response
- DB connection pooling. Async/non-blocking I/O
Security (non-negotiable)
- Secrets via env vars only — never hardcoded
- Parameterized queries/ORM — no string-concatenated SQL
- Hash passwords (bcrypt/argon2 or language equivalent)
- Rate-limit auth endpoints (login, register, password reset)
- Limit request body size
- Security headers in production (X-Frame-Options, CSP, HSTS)
- Validate all input at boundary before processing
Never Do
- Trust unvalidated client input or hardcode secrets
- Business logic directly in route handlers