ADR-008: Conventional Commits Standard

Date: 2026-01-23 Status: Accepted Deciders: Founder

Context

We need standardized commit messages for:

  • Clear history
  • Automated changelog generation
  • Semantic versioning automation
  • Easy navigation of Git history
  • Understanding impact of changes

Without standards, commits become:

  • "fixed bug"
  • "updated stuff"
  • "WIP"
  • Useless for understanding changes

Decision

Adopt Conventional Commits specification and enforce it with tooling.

Format

<type>(<scope>): <subject>

<body> (optional)

<footer> (optional)

Types

Type Purpose Example
feat New feature feat(auth): add 2FA support
fix Bug fix fix(api): resolve null pointer
docs Documentation docs(readme): update setup
style Code formatting style(ui): format components
refactor Code refactoring refactor(db): optimize queries
perf Performance perf(api): cache OAuth tokens
test Tests test(auth): add login tests
chore Maintenance chore(deps): upgrade next
ci CI/CD ci(actions): add build step
revert Revert commit revert: "feat(auth): add 2FA"

Scopes

Define areas of codebase:

  • auth: Authentication/authorization
  • verification: ID verification
  • email: Email aliases
  • phone: Phone masking
  • cards: Virtual cards
  • oauth: OAuth provider
  • api: API routes
  • db: Database
  • ui: UI components
  • config: Configuration

Subject Rules

  • Lowercase
  • No period at end
  • Imperative mood ("add" not "added")
  • Max 72 characters
  • Complete sentence

Body Rules (optional)

  • Explain "why", not "what"
  • Wrap at 72 characters
  • Separate from subject with blank line

Footer Rules (optional)

  • Reference issues: Closes #123
  • Breaking changes: BREAKING CHANGE: API format changed

Examples

Simple Commit

feat(auth): add email verification flow

With Body

feat(auth): add two-factor authentication

Implements TOTP-based 2FA using otpauth library.
Users can enable 2FA in account settings.
Recovery codes are provided during setup.

Closes #45

Breaking Change

feat(api): change OAuth token format

BREAKING CHANGE: OAuth tokens now use JWT format instead of opaque tokens.
Existing tokens will be invalidated. Clients must update token parsing logic.

Closes #78

Bug Fix

fix(verification): handle expired IDs correctly

Previously, expired IDs were approved if face match passed.
Now checks expiration date and rejects if expired.

Fixes #123

Enforcement

Commitlint

Validates commit messages:

// commitlint.config.js
module.exports = {
  extends: ["@commitlint/config-conventional"],
};

Husky

Runs commitlint on commit:

# .husky/commit-msg
npx --no -- commitlint --edit $1

GitHub Actions

Validates PR commits:

# .github/workflows/commitlint.yml
- run: npx commitlint --from ${{ base }} --to ${{ head }}

Consequences

Positive

  • Readable history: git log --oneline is meaningful
  • Automated changelogs: Can generate from commits
  • Semantic versioning: Can determine version bumps automatically
  • Easy navigation: Find all features, all fixes, etc.
  • Code review: Reviewer understands intent immediately
  • Debugging: Easy to find when bug was introduced

Negative

  • Learning curve: Developers must learn format
  • Commit overhead: Takes a few extra seconds per commit
  • Rejected commits: Bad messages are rejected, must rewrite
  • Discipline required: Easy to get wrong at first

Neutral

  • Requires tooling (Husky, Commitlint)
  • Works best with English language

Alternatives Considered

1. No Standard

Pros:

  • No overhead
  • Freedom to write anything

Cons:

  • Useless history
  • Can't generate changelogs
  • Hard to review
  • Impossible to navigate

Why rejected: History becomes garbage quickly.

2. Free-Form with Guidelines

Pros:

  • Some structure
  • Less rigid

Cons:

  • Not enforced
  • People forget guidelines
  • Inconsistent results

Why rejected: Guidelines without enforcement don't work.

3. Custom Format

Pros:

  • Tailored to our needs
  • No external dependencies

Cons:

  • Reinventing wheel
  • No tooling support
  • Team must learn custom format

Why rejected: Conventional Commits is industry standard with great tooling.

Migration Strategy

Existing Commits

Don't rewrite history. Old commits stay as-is.

New Commits

All new commits must follow format (enforced by hooks).

Team Onboarding

  1. Read this ADR
  2. Review examples
  3. First commit will fail (by design)
  4. Learn from error message
  5. Rewrite commit with correct format
  6. After 5-10 commits, becomes natural

Tools

References