Skip to content

Development Workflow

Ankit Upadhyay edited this page Aug 13, 2026 · 1 revision

Development workflow

This page covers branches, commit conventions, and the pull request flow. It is for anyone about to make a change, and it is the page to read before your first pull request.

CONTRIBUTING.md in the repository is the authoritative version of this policy. This page adds the detail that helps in practice.

Branch model

Two long-lived branches, recorded in ADR-0003.

main is the default and release branch. It moves only through promotion pull requests from dev and through hotfixes. What is on main is what the project considers releasable.

dev is the integration branch. Every feature, fix, and docs pull request targets dev. Opening one against main is the most common first-time mistake.

feature branch ──PR──> dev ──promotion PR──> main ──tag──> release

Feature branches use a type/short-description shape, matching the branches in use: feat/emr-app, chore/dependency-security-sweep, hotfix/audit-event-timestamps.

Both branches are protected by repository rulesets rather than classic branch protection, because rulesets are auditable, exportable as JSON, and apply consistently to administrators.

Conventional commits

Enforced by commitlint through the commit-msg hook locally and by the PR governance workflow in CI. The single source of truth is commitlint.config.cjs; the CI job reads that file at runtime so the two gates cannot drift apart.

Types

build  chore  ci  docs  feat  fix  perf  refactor  revert  style  test

Scopes

web  api  database  fhir  types  ui  lib  repo  ci  docs

Header maximum length is 100 characters.

feat(api): add Patient read endpoint
fix(database): make AuditEvent actor index case-insensitive
docs(repo): clarify release promotion flow
chore(repo): promote dev to main - patient scheduling MVP

The scope is required in the PR title. Commitlint accepts a scopeless commit locally, but the PR-title check runs with requireScope: true. A title like feat: add patient search passes every local hook and reds the pull request. Always write type(scope): subject in the title.

Note that the comment block in .github/PULL_REQUEST_TEMPLATE.md lists the scopes without ui. commitlint.config.cjs is the authoritative list and does include ui.

Hooks

Installed by the prepare script on pnpm install.

Hook Runs
pre-commit lint-staged: Prettier on staged formattable files, secretlint over a wider set including config, shell, env-shaped, TOML, XML, and plist files
commit-msg commitlint --edit
pre-push pnpm run lint && pnpm run type-check

Do not bypass them. If a hook is wrong, fix the hook in a pull request.

Before opening a pull request

Scoped to what you changed:

pnpm --filter <workspace> lint
pnpm --filter <workspace> type-check
pnpm --filter <workspace> test
pnpm turbo run build --filter=<workspace>   # if the change affects build output

Or the whole gate, which is slower:

pnpm verify

Pull requests

  • Target dev.
  • Title is type(scope): subject with a scope from the list.
  • Fill in the template: the checklist, current behaviour, new behaviour and how you verified it, and the linked issue.
  • Keep it focused. Unrelated cleanups belong in their own pull request.
  • The CI Required aggregate check must be green before merge.

Two rules the template asks you to confirm, because they are the ones that cause real harm:

  • No real patient data anywhere in the diff, screenshots, or logs.
  • No applied Prisma migration was edited. See Upgrades and migrations.

When a change needs an ADR

If your change reverses or significantly extends a recorded architectural decision, include a new ADR in the same pull request. Do not edit the old one; mark it superseded and link forward. See ADR index.

Promotion

When dev is in a state worth releasing, open a pull request from dev to main titled:

chore(repo): promote dev to main - <summary>

Wait for CI Required, then merge without squashing, so the commit history from dev is preserved.

The commit-message validation job skips promotion pull requests, because they replay history that was already linted when it merged to dev. The title check still runs.

Hotfixes

  1. Branch from main.
  2. Open a pull request targeting main with a normal conventional title.
  3. After merge, back-merge main into dev immediately, or the fix will be lost or reintroduced by the next promotion.

Files that must stay identical on both branches

GitHub reads some files from the default branch regardless of which branch you edit. Change them on dev like everything else and let promotion carry them; never patch them on main alone.

File Why
.github/dependabot.yml Dependabot reads only the default branch copy. A dev-only edit does nothing and a divergent copy conflicts on every promotion.
.github/workflows/** Scheduled and default-branch triggers run from main.
.github/CODEOWNERS Review routing should not depend on the target branch.
.github/ISSUE_TEMPLATE/** Issue forms are served from the default branch.
.github/PULL_REQUEST_TEMPLATE.md Served from the default branch.
SECURITY.md The Security tab reads the default branch copy.

Working on several things at once

Use a git worktree per concurrent workstream. The repository is already set up this way, with sibling directories for the branches in flight.

git worktree add ../openrunic-my-feature -b feat/my-feature dev

Two things to watch. Only one git process should touch a worktree at a time. And bare npx tsc or npx eslint can resolve wrongly in a worktree; use the workspace scripts through pnpm instead.

Reporting bugs and requesting features

  • Bugs: use the bug report template and fill in reproduction and environment. If the bug involves real data, reproduce it with synthetic data first and report that.
  • Features: open an issue with the feature template before writing significant code, so scope can be agreed first.
  • Security vulnerabilities: never a public issue. See Security policy.

Contribution licensing

There is no CLA and no sign-off requirement. Submitting a contribution means it is your own work, or you have the right to submit it, and that it is provided under AGPL-3.0-only.

Related pages

Clone this wiki locally