Skip to content

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