Skip to main content
Status: Accepted Date: 2026-02-06 Deciders: Reflections Maintainers

Context

The repository contains multiple deployable applications and shared packages that need strict boundaries to prevent cyclic dependencies, hidden coupling, and runtime leakage between planes.

Decision

Use a pnpm + Turborepo monorepo with explicit app/package separation:
  • Apps (apps/*) consume packages (packages/*) through public package entrypoints only.
  • Packages never depend on apps.
  • DB query capabilities are segmented by entrypoint (read, write, admin) and enforced by tests/lint patterns.
  • Workspace-wide commands are orchestrated with Turbo pipelines.

Alternatives considered

Alternative 1: Polyrepo per app/service

Pros:
  • Strong physical isolation.
  • Independent release cycles.
Cons:
  • High coordination overhead for shared schema and API contracts.
  • Duplicate tooling/config and slower cross-cutting refactors.

Alternative 2: Monorepo with unrestricted imports

Pros:
  • Fast initial development.
  • Fewer structural constraints.
Cons:
  • Boundary drift and accidental coupling.
  • Safety-critical invariants harder to enforce (especially realtime read-only constraints).

Alternative 3: Single deployable app with internal modules

Pros:
  • Minimal repo complexity.
  • Simplified local development topology.
Cons:
  • Blurs runtime boundaries between realtime and background planes.
  • Harder to scale teams and service responsibilities independently.

Consequences

Benefits:
  • Clear dependency flow and lower coupling.
  • Faster coordinated refactors across apps/packages with one change set.
  • Explicit safety checks for read-only constraints in realtime paths.
Costs:
  • Additional up-front discipline around exports and boundaries.
  • Monorepo pipeline setup and caching maintenance.

Implementation notes

  • Enforce import boundaries through three layers (see ADR-0022):
    • ESLint: no-restricted-imports blocks deep imports, admin queries from realtime/API planes, and direct vendor SDK imports outside packages/vendors.
    • Architecture guard: simplicity-guard.mjs catches dynamic imports and cross-plane violations in CI.
    • File-scan tests: dedicated test files verify no admin imports leak into realtime packages.
  • Maintain package exports in packages/*/package.json and avoid deep imports.