Skip to main content
The project uses a three-branch model with Conventional Commits and semantic-release for automated versioning.

Branch strategy

BranchPurposeProtection
mainProduction releasesPRs only from preview; code owner approval required
previewStaging / integrationPRs only from feature branches; CI must pass
feature/*Your working branchesNo restrictions

Branch protection rules

main

  • Require pull request reviews (code owner approval)
  • Require status checks to pass (enforced by enforce-preview-branch.yml)
  • Only preview branch may open a PR to main — any other source is rejected by the enforce-preview-branch.yml workflow
  • Direct pushes disabled

preview

  • Require CI to pass (unit-tests and lighthouse jobs in ci.yml)
  • PRs from main are blocked by enforce-preview-source.yml (the sync-preview.yml workflow handles that direction automatically)
  • Direct pushes disabled

Commit format

<type>: <description>
Keep the description short and in the imperative mood (“add”, “fix”, “update” — not “added”, “fixed”, “updated”).

Conventional commit types

PrefixRelease?Version bumpCHANGELOG section
feat:YesMinor (0.1.0 → 0.2.0)Features
fix:YesPatch (0.1.0 → 0.1.1)Bug Fixes
feat!:YesMajor (0.1.0 → 1.0.0)Features
perf:YesPatchPerformance
chore:NoMiscellaneous
docs:NoDocumentation
ci:NoCI/CD
test:NoTests
refactor:NoRefactoring
Breaking changes can be indicated two ways:
  • feat!: rename block prop interface
  • feat: rename block prop interface\n\nBREAKING CHANGE: Props renamed from camelCase to snake_case
Both trigger a major version bump.

PR flow

1

Branch from preview

Always start from the latest preview branch:
git checkout preview
git pull
git checkout -b feat/your-feature
2

Commit with conventional format

git commit -m "feat: add sponsor tier badges to cards"
git commit -m "fix: correct hero image aspect ratio on mobile"
Each commit message must start with a recognized type prefix followed by a colon and space.
3

Open PR to preview

gh pr create --base preview --title "feat: add sponsor tier badges"
CI runs automatically:
  • unit-tests job: all Vitest tests must pass
  • lighthouse job: Lighthouse CI runs against the built site
  • enforce-preview-source.yml: confirms the source is not main
4

Merge to preview

After CI passes, merge the PR. The feature branch can be deleted.
5

Open PR to main

When the staging environment looks good:
gh pr create --base main --head preview --title "release: sprint N"
The enforce-preview-branch.yml workflow verifies the source is preview. A code owner review is required.
6

Merge to main → release happens automatically

On merge:
  1. release.yml runs semantic-release → version bump, CHANGELOG, GitHub Release
  2. sync-preview.yml merges main back into preview
  3. Discord notification confirms the sync

Common examples

# New feature (minor bump)
git commit -m "feat: add FAQ accordion block"

# Bug fix (patch bump)
git commit -m "fix: prevent layout shift on hero carousel"

# Breaking change (major bump)
git commit -m "feat!: rename block _type prefix from snake_case to camelCase"

# No release (chore, docs, test, refactor, ci)
git commit -m "chore: update dependency versions"
git commit -m "docs: add onboarding guide for new team members"
git commit -m "test: add E2E test for contact form submission"
git commit -m "ci: pin Node.js to 24.13.1 in release workflow"
git commit -m "refactor: extract GROQ projections to shared module"

Why this workflow

preview as integration buffer

All feature branches merge to preview first. This catches integration issues before they reach production. The preview branch also doubles as the staging environment (SSR + Visual Editing ON).

Automated releases

semantic-release eliminates manual version management. The version number is derived from the commit history, making it impossible to forget a version bump or write inconsistent changelog entries.

CI gate

Unit tests and Lighthouse CI run on every PR to preview. Performance regressions are caught before they land in the staging environment, let alone production.

Discord visibility

The sync notification tells the whole team when preview is safe to branch from again after a release. No need to check the Actions tab.

Troubleshooting

PR from feature branch to main blocked: Open a PR to preview first, not directly to main. The enforce-preview-branch.yml workflow blocks all non-preview sources. PR from main to preview blocked: The enforce-preview-source.yml workflow blocks this direction. It is handled automatically by sync-preview.yml after every release. No manual PR is needed. sync-preview fails with merge conflict: A manual merge is required. Checkout preview, merge origin/main, resolve conflicts, and push. Then manually trigger the Discord notification or post an update to the team. semantic-release creates no release: All commits since the last tag use non-release prefixes (chore:, docs:, ci:, test:, refactor:). Add at least one feat: or fix: commit to trigger a release.