Skip to main content

Contracts

Two things keep the API, the web app and the worker in agreement about data shapes:

  • packages/contracts: hand-written shared types, constants and Zod schemas.
  • The OpenAPI spec: apps/api/openapi.json, generated from the API code, and the TypeScript types generated from it for the web app.

Shared package: @booking/contracts​

packages/contracts is imported by apps/api, apps/web, apps/worker and packages/db. Put code here when more than one of them needs the same definition.

Folder / fileContents
booking-status.tsLifecycle, payment and display status constants and types
authz/The permission catalog, the system role bundles and RBAC request schemas
analytics/GA4 event schemas, custom dimensions and the parseGaCookies() helper
availability/validators.tsAvailability request validators
product/Add-on groups and visibility, checkout offers, duration options
pricing/, policies/Pricing and policy schemas
events/Domain event and outbound webhook payload types

The package has three entry points: @booking/contracts, @booking/contracts/analytics and @booking/contracts/availability/validators.

Other workspaces import the built output in packages/contracts/dist. After you change a file in packages/contracts/src, rebuild it:

pnpm -F @booking/contracts build

pnpm build:packages rebuilds all shared packages.

OpenAPI spec​

apps/api/openapi.json is the committed description of every API route. It is generated from the @nestjs/swagger decorators on the controllers and DTOs, so the code is the source of truth. Do not edit the file by hand.

The web app gets TypeScript types from it: apps/web/lib/api/generated/openapi.d.ts, produced with openapi-typescript. The API clients in apps/web/lib/api/ use these types, so a DTO change that the frontend does not follow becomes a type error.

Regenerate after an API change​

Whenever you add or change a route, a DTO or a Swagger description, run:

pnpm contracts:regen

It runs two steps:

  1. pnpm -F api run spec:dump boots the Nest app without a database or an HTTP listener and writes apps/api/openapi.json.
  2. pnpm -F web run types:gen writes apps/web/lib/api/generated/openapi.d.ts.

Commit both files with your change.

Drift check​

pnpm contracts:check regenerates both files and fails if either differs from the committed copy. It runs in the pre-push hook and in CI. See Quality gates.

Swagger UI​

When the API runs outside production, it serves interactive docs of the same spec at /api-docs, for example http://localhost:3001/api-docs in development. Use the Authorize button with a JWT to call admin routes. Swagger UI is turned off in production.