Skip to content

Architecture Conventions

Where code lives and which direction dependencies flow. Full rationale: plans/ARCHITECTURE.md §1.

  • apps/* — deployment targets (@apps/web, @apps/cron-*). Thin.
  • packages/* — shared libraries (@packages/db, @packages/auth, @packages/service).
  • Import aliases: @packages/*, @apps/*.
apps/* → packages/service → packages/{db, auth}
packages/auth → packages/db
  • @packages/db depends on nothing internal. Never import service/auth into db.
  • Business logic lives in @packages/service, NOT in @apps/web route handlers or TanStack server functions. Handlers are thin: validate → authorize → call service.
  • Cron jobs (@apps/cron-*) call @packages/service directly (trusted internal context).
  • @packages/service is auth-agnostic: it receives already-authorized input plus an AuditContext. It NEVER checks permissions. requirePermission(...) is called by the Hono route handler BEFORE the service function runs.
  • Service functions that may run in a transaction accept db: DB | TX.
  • Access the DB via the createDB(env) factory + DB / TX types from @packages/db. There is NO module-level db singleton — the connection comes from per-request env (Hyperdrive in prod, NEON_DATABASE_URL in dev).
  • One service operation per file, composed via the mixin pattern — see service-conventions.md.
  • DB schema is domain-split under packages/db/src/schema/, re-exported from schema/index.ts — see schema.md.
  • Relations live only in packages/db/src/relations.ts, never inline in table files.