Skip to content

Conventions and contributing

This page collects the conventions contributors follow. The authoritative sources in the repository are AGENTS.md, .github/copilot-instructions.md and the decision records in docs/decisions/; where this page and those files disagree, the files win.

  1. Read the accepted decisions in docs/decisions/README.md that apply to the paths you’re changing, and follow them. Don’t reopen a decision unless the team asks to.
  2. Check the backlog in docs/TODO.md.
  3. Get the app running locally: Local development.
You’re adding… Put it in
Supabase reads, writes, RPC calls, storage apps/web/src/api/ (the only data-access layer)
A reusable UI component apps/web/src/components/
UI owned by one role’s workspace apps/web/src/screens/<role>/
Workspace data loading and actions apps/web/src/hooks/<role>/
A pure domain helper apps/web/src/utils/
A low-level helper apps/web/src/lib/
A shared status or workflow constant apps/web/src/constants/
A runtime feature gate apps/web/src/config/runtime.ts
A schema or policy change a new migration in supabase/migrations/

Role-specific code lives in role-named subfolders (admin/, tester/, developer/, product-manager/, stakeholder/).

Kind Style Example
Components and screens PascalCase ConfirmDialog.tsx, AdminDashboard.tsx
Hooks camelCase with use useAppSession.ts
API modules, utilities, constants kebab-case admin-task-directory.ts, task-request-status.ts
  • Name functions load* for reads, save* for create/update and delete* for deletes.
  • Return a result envelope with source and message instead of throwing.
  • Define mutation inputs as Save*Input interfaces with explicit fields.
  • Use the single Supabase client from apps/web/src/api/supabase.ts.
  • Enforce access in RLS, not only in the UI.
  • Interfaces for domain models; type aliases for unions and workflow states.
  • Separate database row interfaces from domain types.
  • Explicit prop interfaces; no any.
  • Keep components thin; move logic into hooks.
  • The import alias @/ resolves to apps/web/, not apps/web/src/, so write @/src/lib/utils.
  • strict isn’t enabled in tsconfig.json; be explicit anyway.
  • Use the in-house router; don’t add react-router-dom.
  • Charts are native SVG; don’t add a charting library.
  • apps/web/src/api is the only data-access boundary.
  • Public self-sign-up stays disabled.
  • VITE_DEV_LOGIN_SHORTCUTS lives only in .env.development.local.
  • RLS policies use SECURITY DEFINER helpers, never recursive queries on profiles.
  • Don’t wrap the app in React StrictMode in development.
  • npm is the package manager; package-lock.json changes only through npm install or npm uninstall.
  • Delivery lifecycle and QA execution stay separate fields.
  • Every schema or policy change is a new migration. Don’t edit applied migrations, and don’t patch tables by hand.
  • New privileged mutations should write audit rows.
  • Test locally with supabase db reset and the validation scripts.
  • Never commit env files; .gitignore excludes them.
  • Never put a service-role key in a VITE_ variable.
  • If you find a committed secret, report its path and stop. Don’t paste the value anywhere.
  • The emails and passwords in README.md and supabase/seed.sql are deliberate local seed accounts, not leaked secrets.
  • .naso/tooling/ is vendored; never edit it by hand.
  • The list between the decision markers in docs/decisions/README.md is generated.

Commit subjects follow type(scope): summary, for example:

feat(tester): add retest badge to queue rows
fix(api): scope task request attachments to owner
docs(readme): update local ports

Types in use: feat, fix, refactor, chore, docs, modify.

  • Don’t bypass the pre-commit hook; fix what it reports and commit again. It blocks lines shaped like secrets and reports files outside your declared scope (NASO_SCOPE).
  • Ask which branch a change belongs on; there’s no written branching rule.
  1. npm run lint passes.
  2. npm run build succeeds if you touched build-relevant code.
  3. npm run validate:core passes if you touched workflows, RLS or RPCs.
  4. Update the docs in docs/ and this site if behaviour changed.