Skip to main content
This page covers everything you need to know about contributing to MDCMS, from branch naming to code conventions and the PR process.

Development Workflow

1

Create a feature branch

Always branch off main before making changes:
git checkout -b feat/my-feature
2

Develop with tests

Write failing tests first, then implement until they pass. Run unit tests during development for fast feedback:
bun run unit
3

Verify everything passes

Before committing, run the full CI gate:
bun run ci:required
This runs format check, typecheck, unit tests, and integration tests sequentially.
4

Commit with conventional commits

git commit -m "feat(studio): add locale switcher to toolbar"

Branch Naming

All branches follow a type/kebab-case-description pattern:
PrefixUse for
feat/New features
fix/Bug fixes
chore/Maintenance, dependency updates, config changes
refactor/Code restructuring without behavior changes
Examples: feat/media-upload-drag-drop, fix/reference-resolution-null, chore/bump-elysia.

Commit Conventions

Commits follow the conventional commits format:
type(scope): brief message
TypeUse for
featNew feature
fixBug fix
choreMaintenance task
refactorCode restructuring
docsDocumentation changes
testTest additions or modifications
The scope is the package name or area of the codebase (e.g., server, studio, cli, shared, sdk, modules). Rules:
  • First line only — no body, no footer
  • Keep the message concise and descriptive
  • Use imperative mood (“add feature” not “added feature”)
git commit -m "feat(server): add webhook retry with exponential backoff"
git commit -m "fix(sdk): handle timeout on large content responses"
git commit -m "chore(deps): bump drizzle-orm to 0.38"

Code Conventions

TypeScript

  • Strict mode is enabled across all packages
  • Prefer type inference when types are obvious from context
  • Use explicit types for function parameters and return values at module boundaries

Formatting

Prettier handles all formatting. Run it before committing:
bun run format

Naming

EntityConventionExample
Fileskebab-casecontent-api.ts
Types / InterfacesPascalCaseContentDocument
Functions / VariablescamelCasegetDocument
ConstantsSCREAMING_SNAKE_CASEMAX_LIMIT
  • No abbreviations except widely known ones (id, url, ctx)
  • Self-documenting names — comments explain “why”, not “what”

General Principles

  • DRY — Extract repeated values to constants, repeated logic to functions
  • No unrelated changes — Keep PRs focused on a single concern
  • No debug artifacts — Never commit console.log, debugger statements, or test artifacts

PR Process

1

Create a pull request

Push your branch and open a PR against main:
git push -u origin feat/my-feature
2

CI runs automatically

GitHub Actions runs the full CI pipeline on every PR. All required checks must pass before merge.
3

Address review feedback

Make changes in new commits (do not force-push during review). Keep the conversation going until the reviewer approves.
4

Merge

Once approved and CI passes, the PR is merged into main.

Pre-push Gate

A git pre-push hook is installed automatically when you run bun install. It executes:
bun run ci:required
This runs the following checks sequentially:
  1. Format check — Verifies code matches Prettier formatting
  2. Typecheck — Runs TypeScript compiler across all packages
  3. Unit tests — Runs all unit tests
  4. Integration tests — Runs integration tests (requires Docker services running)
The pre-push hook blocks the push if any check fails. Fix all failures before pushing. Do not skip the hook with --no-verify unless you have a specific reason.
Run bun run quality (format + typecheck) as a quick sanity check during development. Save the full bun run ci:required for when you are ready to push.