Feature workflow
The full lifecycle for shipping a change: branch → build → test → review → staging → production.
For local setup itself see local-setup.md. For the deploy mechanics (Vercel, GitHub Actions, secrets, rollback) see deploy.md.
1. Start a feature branch
git checkout staging
git pull --ff-only
git checkout -b <username>/<AIM-NNN>-<short-description>
Branch-name convention (per CLAUDE.md):
- Prefix with your GitHub handle:
petter/... - Include the Linear ticket ID if there is one:
petter/AIM-815-fix-emissions-sorting - No ticket? Just describe the change:
petter/docs-feature-workflow
Never commit on staging or production directly.
2. Develop
npm run dev # http://localhost:3000
Where things live (see architecture.md):
- Routes / pages →
app/routes/ - Reusable UI →
app/components/(domain) orapp/@/components/ui/(design system) - Server-only services →
app/.server/ - Background jobs →
tasks/<service>/ - Schema changes →
npm run migr <name>then editsupabase/migrations/<timestamp>_<name>.sql
If you change the schema:
- Always enable RLS on new
publictables, with an account-scoped policy. Seearchitecture.mdfor the template. - Use
SECURITY_INVOKERon views and preferSECURITY INVOKERon functions. - Test the migration from scratch:
npm run reset. If it errors, fix the migration — never edit a previously-merged one.
3. Test locally
Cheap iteration:
npm run typecheck # TS errors
npm run fix # eslint --fix .
Before you push, run the full gate the CI mirrors:
npm run precommit
That runs, in order: check-if-production-database → fix → supabase db reset (re-applies every migration on a clean DB) → supabase test db → gentypes → gendocs → fix → build.
If precommit fails, fix it locally. CI will run the same checks on your PR and reject it for the same reason.
Manual smoke test in the browser: log in (see local-setup.md#login), exercise the feature path, hit edge cases. Type-checking and tests verify correctness of code, not correctness of feature.
4. Open a PR
git push -u origin <branch>
gh pr create --base staging \
--title "<short, imperative>" \
--body "<what changed, why, how to test>"
PR target is always staging, never production directly.
PR description should include:
- Summary — 1–3 bullets, what and why
- Test plan — checklist of what to verify on the staging deploy
- Migrations / RLS — if you added either, call out the impact
What CI will run on the PR (ci.yml, database-tests.yml):
| Job | What it checks |
|---|---|
CI / test | gentypes + gendocs produce no diff → PR fails if app/types/supabase/, tasks/*/src/supabase.d.ts, or docs/schema/ is stale |
database-tests | Runs every .sql test in supabase/tests/database/ against a fresh DB |
If either fails, fix and push again — the workflows re-run automatically.
5. Review and merge to staging
- Self-review the diff on GitHub — easier to spot mistakes in the rendered view than in your editor.
- Request review from a teammate via Linear or Slack.
- Address comments by pushing more commits to the same branch (don't force-push unless you have to).
- Once approved and CI is green, merge the PR (squash unless the commits are individually meaningful).
The merge triggers, on staging:
| Workflow | What it does |
|---|---|
| Vercel | Builds and deploys frontend to https://app-staging.aimabel.ai/ |
staging.yml | supabase db push (applies new migrations) + supabase functions deploy |
update-docs.yml | Regenerates types + schema docs; auto-commits if anything drifted |
Watch them land:
gh pr checks <pr-number> # CI / deploys for the merged PR
gh run watch # follow the next workflow run
6. Verify on staging
- Open https://app-staging.aimabel.ai/ and exercise your feature.
- Walk through the test plan from your PR.
- Watch for anything that might regress in other features.
- For schema or RLS changes, double-check from a non-super-admin account that you can only see what you're supposed to.
- Let it bake at least one working day before promoting (per
deploy.md).
If something is broken on staging, fix it on a new feature branch and PR back to staging — don't push a fix directly to staging to "save time".
For risky features, ship behind a flag and roll out gradually:
- Account-level flags live in
basejump.accounts.public_metadata.feature_flagsas a string array. - Read them via the same loader pattern used in other guarded routes (grep for
feature_flagsinapp/). - Default off, opt-in for testing accounts first.
7. Promote to production
When you're satisfied staging is healthy:
gh pr create --base production --head staging \
--title "Promote staging → production (<date>)" \
--body "Includes: <list of PRs since last promotion>"
Merge that PR. The merge triggers:
| Workflow | What it does |
|---|---|
| Vercel | Deploys frontend to https://app.aimabel.ai/ |
production.yml | supabase db push + supabase functions deploy on the production project |
update-docs.yml | Same as on staging — keeps generated files current |
Verify on https://app.aimabel.ai/ immediately after deploy.
8. After ship
- Mark the Linear ticket done.
- Delete the feature branch (GitHub does this automatically if you ticked the checkbox).
- If anything went wrong, see
deploy.md#rolling-back.
TL;DR
staging ──────────────────────────────►
│ ▲
└─► petter/AIM-NNN-thing ──PR──► staging │ (auto-deploy to app-staging)
│
└──PR──► production (auto-deploy to app)
Direct pushes to staging or production are not part of this flow. Feature branches and PRs are the only path.