Code standard

How to write a change that fits the copy. These are conventions, not a second design of the system.

TypeScript

UI is .tsx. Everything else is .ts. JavaScript source is refused, including tests and config. Types close shape bugs in the program you wrote. They do not see a request body.

Boundaries

A boundary is a value the program did not create: form data, search params, process.env, JSON, a vendor payload, a cookie. Parse it with Zod where it enters. A failed parse is a 400 or an error at that edge.

as and an unchecked annotation at a boundary are refused. Yup, Joi, and class-validator are refused. Inside the boundary, TypeScript owns the shapes again.

Format and lint

Oxfmt is the only writer of layout. Oxlint is the linter and does not format. One formatter and one linter stay two programs so they do not rewrite each other.

  • npm run format writes. npm run format:check is what validate runs.
  • npm run lint fails above zero warnings.
  • Editor-only formatting, Prettier beside Oxfmt, and stylistic lint rules are refused.

Tests

Unit tests are Vitest, so a test can import .tsx and CSS through Vite. node:test and Jest are refused. jsdom and happy-dom are not the default environment. A module test does not need a document.

npm run validate is format, lint, typecheck, and the test run. Typecheck generates the Prisma client and the route types before tsc.

Environment

Copy .env.example to .env. Zod parses the result in app/lib/env.server.ts. The example file is what a person copies. It is not the parser, and Zod does not fill in a missing flag.

DATABASE_URL is required. EMAIL_LOGIN, GITHUB_LOGIN, EMAIL_LOGIN_MOCK, GITHUB_LOGIN_MOCK, and SUBSCRIPTIONS are each "true" or "false". When a mock flag is true, that branch does not ask for the vendor credentials. When subscriptions are off, the Stripe keys are not part of the schema.

Packages

The package manager is npm. The committed lockfile is package-lock.json. CI and Docker install with npm ci. A second lockfile is refused. Switching to pnpm, yarn, or Bun means rewriting the lockfile, the Dockerfile, and CI in the same change.