- Never commit or push directly to
main. Always create a branch first (feat/…,fix/…,chore/…,docs/…) and open a pull request intomain. - One focused change per branch/PR. Keep commits small and descriptive.
- Do not add
Co-Authored-Bytrailers or "Generated with Claude Code" lines to commits or PR descriptions. - Never force-push or rewrite history on
main. - Lint, format, typecheck, tests and
db:checkrun in GitHub Actions (.github/workflows/ci.yml), not in a pre-commit hook and not by default on the developer machine, so development and browser testing stay fast. Do not run the full suite locally after every change; run a single targeted test oreslint <files>only when it helps you finish the task. - Boy Scout rule: when CI reports lint, format or test failures in code related to the feature you
are working on, fix them in the same branch before starting new work. Do not leave them to pile
up. Failures in unrelated code get their own
chore/branch, never a drive-by in a feature PR.
The binding specification is Interactive Marketing Platform Specification v2.0; the working
plan is docs/execution-plan.md. Key rules for code in this repo:
- Every
idand id-reference column is a UUID (uuid(7)defaults); onlyoutbox_events.seqis a non-UUID ordering sequence. - Tenant tables are accessed only through
withTenant(RLS enforced); never useplatformDborsystemDboutside the allowed modules. - Raw SQL only via tagged-template
$queryRaw/$executeRaw; unsafe variants are banned. - Schema changes ship as reviewed migrations; roles are provisioned by
db:provision-roles, never in SQL with passwords. Secrets live in.env(gitignored), never in the repo.
Active decisions and practices are in docs/frontend/README.md (ADR-F001 to ADR-F011 in
docs/frontend/adr/). Cite the decision you apply in PR descriptions.
- Reuse first: search the gallery (
/ui/components) ordocs/frontend/component-catalogue.mdbefore writing UI. Compose existing components, then extend one, and only then add a new one (a new component needs a registry entry and a gallery demo block, enforced by tests). - Reusable UI lives in
packages/ui(@imp/ui), never inapps/web. Features useUi*components, not raw<button>/<input>. - Semantic tokens only (
var(--ui-*)), logical CSS properties, no hard-coded colours/sizes, nov-html. The UI kit checks run in CI. - Generated files: after changing a
@imp/uicomponent's props, slots or events, runnpm run catalogue:build -w @imp/uiand commit the regeneratedcomponent-catalogue.mdandcomposition.generated.ts; after editingtokens.json, runnpm run tokens:build -w @imp/ui. CI fails with "stale" otherwise. - Strings come from the catalogue (
i18n/en.ts) or props; every state in spec section 11 usesUiSystemState; status usesUiStatusChipvocabularies. - No module-level mutable state in SSR code; no storing participant form state in browser storage.