Code style
Follow the repository's TypeScript, data access, logging and test conventions.
Edit on GitHubUse the repository's checks and existing module patterns when changing code. package.json defines the commands, while biome.json and the Ultracite configuration define formatting and lint rules.
Checks
Run the named scripts before submitting a change:
pnpm lint
pnpm typecheck
pnpm test:unit
pnpm test:integrationpnpm format applies the Ultracite fixes. The integration suite needs its PostgreSQL test database.
Outside CI, pnpm test:e2e runs prisma migrate reset --force and reseeds whatever database DATABASE_URL names. Run it only against a disposable database after checking that URL.
The pull request guide explains the local hooks and CI checks.
TypeScript and imports
Keep types close to the domain code that owns them. Reusable types live in types/, and request validation schemas live in lib/schemas/. Prisma generates its client into src/generated/prisma; import generated types from @/src/generated/prisma where needed. Prefer a precise type or unknown with a guard over an unchecked any.
Use the @/ alias for imports from the repository root. Follow the import order enforced by the formatter rather than arranging groups by hand. React components that use browser state or effects carry the "use client" directive; pages can remain server components when they do not need those browser APIs. In the App Router, dynamic route params may be a promise and are awaited in the current case page.
Data access and expected failures
Keep application Prisma access in services and lib/prisma.ts. Never add direct Prisma access to routes, actions, components or hooks. API handlers and server actions should authenticate callers, validate input and delegate domain operations to lib/services/. Importing Prisma into a new action simply to bypass a service also bypasses the established permission and validation paths. lib/prisma.ts owns the configured client, including element validation on writes.
Services commonly use ServiceResult from types/service.ts for expected success or failure. Follow the result shape of the service you are extending. lib/schemas/ holds the Zod schemas used at boundaries. For an element change, check both the schema and the service rule; the database enum alone does not express every allowed combination.
Names, wording and logging
Most source files use kebab case, exported React components use PascalCase, and functions and values use camelCase. Match the neighbouring code. Use British spelling in product text where external API names do not dictate a spelling. Follow the existing Tailwind CSS v4 conventions for styling.
Use the structured logger in lib/logger.ts for application events and errors. A child logger can bind a component name. Supply useful fields without placing secrets or raw credentials in a log entry. Keep comments for a rule, trade-off or surprising behaviour that the code alone does not explain.
For changes to documented API routes, run pnpm docs:generate and include the updated public/openapi.json; CI checks for drift.
Tests
Tests are not all beside the file they cover. Component and service tests often sit in a nearby __tests__/ directory; broader integration tests are under src/__tests__/integration/, and browser tests are under e2e/. Add a test at the level that exercises the behaviour you changed. The CI workflow runs unit, integration and Playwright suites, and merges the first two suites' coverage for its structural-quality check.