Developer docs
Logs

Branching & release

prod ← dev ← feat/F-###, and the commit format.

docs/BRANCHING.md

main is the only long-lived branch, and merging to it deploys nothing. Work lands on main through pull requests; prod changes only when someone ships a numbered release through nonprod first (deploy/README.md → Shipping a release). The old dev / prod branches and the Kubernetes targets no longer exist.

BranchHoldsDeploys to
mainEverything merged and checked. Every merge also builds signed release candidates.Nothing by itself
feat/*, fix/*, chore/*, docs/*One change, until its pull request merges (the branch is then deleted)—
EnvironmentRunsChanges when
nonprod — https://nonprod.omnichan.studioThe newest releaseThe promoter deploys a new release there automatically, or someone dispatches deploy nonprod
prod — https://studio.lightningleap.storeA release that ran on nonprodSomeone on PROD_DEPLOYERS dispatches deploy prod

The loop

git switch main && git pull --ff-only
git switch -c feat/F-020-projects        # one branch per change

# … build the slice: prisma model → api module → contract → ui → tests …

npm run verify                            # typecheck → lint → test → build
git commit                                # conventional commits, see below
gh pr create                              # CI runs; a reviewer approves; squash-merge

Rules:

  1. One branch per change, named for it: feat/F-020-projects, not feat/stuff. A feature id ties the branch to a row in FEATURES.md and data/dashboard/features.json.
  2. A branch is a vertical slice, not a layer: Prisma model → API module → contract → UI → tests, all in one branch.
  3. npm run verify passes before the PR, and CI passes before the merge. A pushed commit clears the PR's approval, so finish the change before asking for review.
  4. Squash-merge. One change, one commit on main.
  5. Every PR carries its own notes, so concurrent PRs never collide on a shared file:
    • a release note in NEXT/ (NEXT/README.md), which the next release turns into CHANGELOG/vX.Y.Z.md. Mark a feature impact: minor;
    • its CHANGELOG.md / VERIFICATION.md rows in docs/changes/<branch>.md (docs/changes/README.md), never in the tables themselves;
    • the board (features.json, the FEATURES.md row) moved in the same commit as the code.
  6. No direct commits to main. A fix to something on prod is a PR, then a release.

Commit format

Conventional commits, scoped by workspace:

feat(api): projects module with org scoping
feat(web): project list and detail
feat(contracts): project + budget schemas
fix(api): agency users could read unassigned projects
docs: record D-009 (Stripe over Paddle)
chore(deps): add stripe

Types: feat · fix · refactor · docs · chore · perf · test · breaking. Scopes: api · web · contracts · infra · none for repo-wide changes.

Release

A release is a signed, numbered copy of one main build — the same bytes run on nonprod and then prod. Cutting one, soaking it on nonprod, promoting it, holding it and rolling back are in deploy/README.md → Shipping a release.