Skip to content

Architecture overview

A pnpm + Turborepo monorepo. How it works, why it exists, where to change it:

Piece What Where
apps/web Next.js app (client components over a generated API client) UI surfaces, panes, routing
apps/api NestJS + Fastify Controllers → services → repositories
apps/worker Queue/outbox consumers (email retry, heartbeat) Background behavior
apps/mobile Expo React Native Mobile loop
apps/docs This site (Astro Starlight) Documentation
packages/schemas Zod contract registry — the API’s single source of truth Request/response shapes, operation registry
packages/api-client Generated from the registry; CI fails on drift (pnpm check:api) Never edited by hand
packages/db Drizzle schema + migrations Tables, migration harness
packages/domain Pure shared logic (identifiers, CSV, markdown parser, filters) Cross-platform rules
packages/ui-web Primitives + Storybook Buttons, dialogs, tokens usage
packages/design-tokens Platform-neutral tokens Color/type/spacing/motion

Key patterns:

  • One contract: web and mobile both consume the generated client; a contract change is a versioned, additive registry edit (ADR-012).
  • Optimistic, revision-checked mutations everywhere a field is edited (ADR-013).
  • Outbox events power notifications, realtime (SSE), and email — written atomically with the mutation (ADR-026).
  • One URL, two presentations for task detail via Next intercepting/parallel routes (ADR-027).

Deep dive: SYSTEM_CONTEXT.