Skip to content

Conventions and contributing

Work is organised as briefs under docs/tasks/, one file per unit of work, written to be handed to an agent cold: the files to open, the API surface to add, the tests that must pass, and what is out of scope. Each opens with frontmatter that is the single source of truth for status, and npm run roadmap generates docs/roadmap.html from it. Understood-but-undecided work lives in docs/gaps/, deliberately outside the numbering, so listing it does not claim a plan that does not exist.

docs/tasks/README.md holds the invariants; read it before any brief.

  • Validation lives in shared/ as zod schemas, imported by both sides of the wire. Input schemas go in shared/api.ts (or shared/orders.ts for order shapes), never inline in a route.
  • Routes stay thin. Parse, call a repository function, respond. SQL lives in db/*-repository.ts.
  • Errors use httpError(status, message); messages are user-facing.
  • Client mutations go through csrfPost / csrfPut / csrfDelete, wrapped in a hook in src/admin/queries.ts that invalidates its own key and the public store key.
  • Comments explain why, not what. The codebase comments decisions and the mistakes they head off. Match that register.
  • Money is integer cents, and CSV columns are *_cents for the same reason.
Terminal window
npm run typecheck # tsc -b
npm run lint # eslint
npm test # vitest: unit, component, and both database dialects
npm run test:e2e # playwright
npm run db:generate # after editing BOTH schema files
npm run db:migrate # apply
  • A fresh checkout has no store in it. npm test seeds per suite, but npm run test:e2e drives the real app against data/beluga.sqlite. In a new clone or worktree the whole suite fails on a missing heading, which reads as a broken storefront and is an empty database. npm run db:migrate && npm run db:seed once per checkout.
  • .env is irrelevant to e2e. Playwright points ENV_FILE at a file that does not exist, on purpose.
  • Postgres skips silently in db/dialect.test.ts if embedded-postgres cannot start. Confirm with --reporter=verbose and look for repository on postgres.
  • npm run typecheck && npm run lint && npm test pass.
  • New routes are in MUTATIONS or READS in server/security.test.ts.
  • New schema fields are in both dialect files and both migration folders.
  • The README section for the area is updated if behaviour changed.
  • No console.log left behind except deliberate operator-facing lines.
  • The brief’s frontmatter says done with a date and a PR number, and npm run roadmap output is committed.

The base branch is main. Branch from it, open pull requests against it, and delete the branch when it lands. Several sessions may be working in the repository at once, so always create a branch before starting.