Skip to content

Developer Guide

Onboarding guide for engineers working on the XPrivate Education dashboard monorepo.

apps/web/ TanStack Start (React SSR) + oRPC API — CF Workers
apps/cron-*/ CF Cron Workers (one per job)
packages/db/ Drizzle schema + createDB(env) factory
packages/auth/ RBAC resolution + permission middleware + AccountState machine
packages/service/ Business logic (auth-agnostic)
packages/contract/ oRPC contract + Zod base I/O schemas
plans/ Locked planning docs (ARCHITECTURE, scope, RESUME)

Dependency direction: apps → {service, contract}, service → {db, auth, contract}, auth → db. contract is a leaf (no internal deps). Never reverse.

LayerTechnology
Frontend / SSRTanStack Start (React) on Cloudflare Workers
APIoRPC (contract-first)
DatabaseDrizzle ORM + Neon Postgres via Hyperdrive
AuthBetter Auth + custom RBAC
SecretsInfisical (no secrets in wrangler config or env files)
RuntimeBun

Run from the repo root:

Terminal window
bun install # install deps + lefthook pre-commit hooks
bun run typecheck # tsc -b (project references)
bun run lint # biome check
bun run test # vitest unit (no DB)
bun run test:integration # vitest integration (needs NEON_DATABASE_URL)
bun run dev # apps/web dev server
bun run db:generate # generate Drizzle migration
bun run db:migrate # apply migrations
bun run db:studio # open Drizzle Studio

Pre-commit hooks (lefthook): biome auto-fix + re-stage, secretlint on staged files. Escape hatch: LEFTHOOK=0 git commit.

Full architecture is locked in plans/ARCHITECTURE.md (22 sections). Key conventions:

  • Business logic lives in packages/service, not in route handlers. Handlers are thin: validate → authorize → call service.
  • DB client is per-request via createDB(env) — no module-level singleton.
  • Service functions are auth-agnostic; permission checks happen in the Hono route handler before the service call.
  • CF Workers: never cache per-request I/O (db/auth) in module scope.

See the Reference section for auto-generated architecture docs.