Skip to main content

Conventions

Code style

  • Prettier for all formatting (config: packages/config/prettier.js, defaults).
  • ESLint 10 flat config (packages/config/eslint.config.js) with typescript-eslint and eslint-plugin-import-x.
  • TypeScript strict mode — no any, no implicit any, no ! non-null asserts unless justified.
  • Comments follow the CLAUDE.md rule: default to none, write only when the why isn't obvious from names.

Commit messages

Conventional-Commits style, matching what already exists in git log:

feat(api): add PIX payment routes and drain webhook handling
fix(api): regenerate worker types before typecheck
docs(openspec): archive pix-payment-flow change
chore(api): drop redundant @cloudflare/workers-types dep

Scopes: api, mobile, web, docs, shared, config, openspec, ci.

Zod schemas

  • Every request and response for every API endpoint has a Zod schema in packages/shared/src/<domain>/schemas.ts.
  • The API imports and validates with .parse() on requests; responses are typed off the inferred schema.
  • Mobile imports the same schema for typed API calls — one source of truth.

Naming

  • Files: kebab-case (pix-payments.ts, not pixPayments.ts).
  • Zod schemas: PascalCaseSchema suffix (CreatePixPaymentRequestSchema).
  • Inferred types: same name, no Schema suffix (CreatePixPaymentRequest).
  • DB tables: snake_case in the DB, camelCase in Drizzle (pixPayments in TS → pix_payments in Postgres).

Errors

  • API returns { error: string, code?: string } with a 4xx status for user errors, 5xx for our fault.
  • Bridge errors bubble as BridgeApiError — the client (apps/api/src/bridge/client.ts) parses status, code, and body.
  • Never leak Bridge API keys or full error bodies to mobile — surface the user-facing message only.

Feature flags

Not currently used. When we need them, keep them close to the code they gate — no central registry.

OpenSpec

  • Use OpenSpec for anything user-visible or architectural. Bug fixes and refactors don't need a spec.
  • Archive completed changes with /opsx:archive — this moves them under openspec/changes/archive/YYYY-MM-DD-<name>/.