API
Overview
The API (apps/api/) is a Next.js App Router used purely as a backend — no frontend rendering, no HTML. Every route lives under src/app/api/ and serves JSON. It handles all business logic, Stripe integration, Supabase auth, background jobs, email/SMS, and physical access control. The frontend calls it via @mg/api-client (typed fetch).
The Request Pipeline
Every request flows through the same pipeline, regardless of domain:
graph LR
Request --> Auth["Authenticate"]
Auth --> Validate["Validate input"]
Validate --> Logic["Business logic"]
Logic --> Response["Typed response"]
Authenticate — extract and verify the JWT, resolve the user's roles, set audit context. See [[auth]].
Validate input — parse the request body or query params against a Zod schema. Invalid input returns a 400 immediately, before any business logic runs. See [[api/validation|Validation]].
Business logic — the actual work: database queries, Stripe calls, side effects. Services receive a transaction client and never manage their own transactions. See [[database]].
Typed response — every endpoint returns the same JSON envelope shape. Success, error, and paginated list responses all follow a predictable contract. See [[api/response-envelopes|Response Envelopes]].
If anything throws during business logic, the withErrorHandling wrapper catches it and returns a structured error response. The caller never sees a raw stack trace. Sentry is reserved for 5xx outcomes — thrown 4xx AppErrors are silent in monitoring, since they're caused by client behavior. See [[api/error-handling|Error Handling]].
Key Concepts
[[api/route-handlers|Route Handlers]] — how route files are structured, the withErrorHandling wrapper, dynamic segments, method aliasing. This is the concrete implementation of the pipeline above.
[[api/response-envelopes|Response Envelopes]] — the { success, data } / { success, error } JSON shape that every endpoint returns. Includes pagination conventions for list endpoints.
[[api/validation|Validation]] — how request bodies and query params are validated using Zod schemas from @mg/shared-schemas. Covers the simple validators, the advanced query parser for list endpoints, and where schemas are defined.
[[api/error-handling|Error Handling]] — the AppError class, the ErrorType enum, and the critical distinction between returning errors (expected, not tracked) and throwing them (unexpected, Sentry-reported).
Authentication — covered in its own top-level page at [[auth]], not here. Every route starts with validateAuthentication() — the auth page explains what that does and how roles work.
Code Map
src/app/api/ 50+ route groups, organized by domain
src/lib/api/
response/
factory.ts Response envelope factories
middleware.ts withErrorHandling wrapper
request/
query-parser.ts Advanced query param parser
route-types.ts TypeScript types for route handlers
src/lib/validation/
api-validator.ts Body and query param validators
See Also
- [[auth]] — Authentication and authorization
- [[database]] — Transactions, audit context, and the service pattern
- [[shared-packages]] — Where schemas, types, and envelopes are defined
- [[overview]] — System architecture overview