Skip to content

Your first task

Four common shapes of work and the path each one takes.

  1. Add the column in packages/db/src/schema.ts with webSchema.table().
  2. bun run db:generate, read the generated SQL, then bun run db:migrate:beta.
  3. Widen the Zod input in the tRPC procedure in packages/core/src/server/trpc/routers/<router>.ts.
  4. Set updatedAt in the update path.
  5. Surface it in the page or component in apps/web/src.
  6. bun run lint && bun run typecheck.

New domain means a new tRPC router in packages/core/src/server/trpc/routers/, registered in the root router. It follows a fixed shape — Zod schemas, procedure types, logAudit on every mutation, Sentry capture. The trpc-router skill scaffolds it.

If mobile needs the same domain, add a /v1 route in apps/api/src/v1/routes/ that calls the router through createCaller. Never re-implement the rule.

  1. Router and procedures first (above).
  2. Page under apps/web/src/app/(main)/admin/<area>/page.tsx.
  3. Register the path in PAGE_ACCESS in packages/core/src/lib/rbac.ts — a 403 on a new admin page is almost always this step being skipped.
  4. Add the nav entry in AdminLayoutClient.tsx.
  5. Audit-log every mutation.

The admin-crud skill scaffolds the router, page and table together.

A new HTTP endpoint (webhook, cron, upload)

Section titled “A new HTTP endpoint (webhook, cron, upload)”
  1. Handler in packages/core/src/http/.
  2. Mount it in the mounts array in apps/api/src/index.ts.
  3. Only if the web origin must serve it too, add the path to PROXIED_PREFIXES or PROXIED_EXACT in apps/web/src/proxy.ts.

main is production and is never pushed to directly. Branch off beta, PR into beta, and promote betamain when it is verified on staging. CI runs Biome, typecheck, unit tests, the migration-ledger check and audit coverage on every PR and again before the image is built.

If you work in parallel worktrees, coordinate migration numbers — two branches both generating 00NN collide in the journal.