CafébecDocs

Architecture

Where each piece of the Cafébec platform lives and why.

Five apps, three shared packages, one database. Everything runs from a single VM behind Traefik.

Apps

apps/api — NestJS REST service. Every mutating request flows through an @CurrentActor() guard that resolves either a Better Auth session cookie or an Authorization: Bearer vnd_… API key into the same Actor object. Controllers never care which track authenticated the request; the audit log records both identically.

apps/web — Vite + React 19 + TanStack Router SPA. Reads the API through its own fetch wrapper with credentials: 'include'; behind Traefik in prod, both land on *.cafebec.ca so the session cookie is same-origin.

apps/mcp — Standalone @modelcontextprotocol/sdk HTTP server. Each tool call goes through the REST API using a system API key rather than touching Prisma directly — keeping business logic and audit trail in one place.

apps/docs — This site. Fumadocs on TanStack Start, prerendered to static HTML at build time, served by nginx. Bakes api.cafebec.ca/openapi.json into the bundle at image build — no runtime dependency on the API.

Shared packages

packages/schemas — Zod schemas. The contract across API, MCP server, operator console. Types derive from schemas; no hand-written TS types for API shapes.

packages/db — Prisma schema + migrations + seed. A GiST exclusion constraint on machine_agreement prevents overlapping active agreements in the same direction — the only Phase-1 constraint that lives in raw SQL instead of Prisma schema.

packages/settlement-engine — Pure functions for commission and invoice math. No DB access. Every path is covered by fixture-based tests to the cent. The API orchestrates the engine with persistence; the engine stays framework-agnostic.

Database

Postgres 16 with pgvector, btree_gist, citext, pgcrypto extensions. Same image in dev (via docker-compose) and prod (via the deploy compose). Prisma owns migrations; the one raw-SQL migration adds the agreement-overlap exclusion constraint.

Design principles

  • Tests before features for the settlement engine and CSV import. The math and the import transforms are load-bearing; regressions are expensive.
  • Schemas are the source of truth. No hand-written API types. Zod drives runtime validation + TS types + the OpenAPI spec.
  • Pure logic in packages, side effects in apps. The settlement engine never touches a database.
  • Every write is auditable. API, MCP, seed scripts — all go through the same audited service methods. No direct DB writes.
  • Agent-friendly error design. Structured errors carry a code and next_actions. An agent that fails should always know what to try next.

On this page