This document defines how the Stellar Micro-Donation API is versioned, how releases are published, and how contributors should reason about breaking vs. non-breaking changes.
- Semantic Versioning Overview
- Version Number Rules
- Breaking vs. Non-Breaking Changes
- API Endpoint Versioning
- Release Flow
- Hotfix Releases
- Deprecation Policy
- Changelog Requirements
- Pre-release Labels
This project follows Semantic Versioning 2.0.0 (SemVer). Every released version is represented as:
MAJOR.MINOR.PATCH
| Segment | When it increments |
|---|---|
MAJOR |
Incompatible / breaking API changes |
MINOR |
New backwards-compatible functionality |
PATCH |
Backwards-compatible bug fixes |
Example progression:
1.0.0 → Initial stable release
1.1.0 → New /wallets/batch endpoint added
1.1.1 → Fix edge case in idempotency key validation
2.0.0 → Donation payload field renamed (breaking)
The current version is always reflected in package.json under the "version" field.
- Remove or rename an existing API endpoint
- Remove or rename a required or optional request field
- Change the meaning or type of an existing response field
- Change authentication behaviour in a way that invalidates existing API keys
- Drop support for a previously supported Node.js major version
- Alter database schema in a way that is not backwards-compatible
- Add a new endpoint
- Add new optional request fields (old requests still work)
- Add new fields to existing responses (consumers must be tolerant of unknown fields)
- Add a new feature flag or configuration option
- Add new npm scripts that do not affect runtime behaviour
- Expand rate-limit allowances
- Fix a bug without changing the public interface
- Improve performance without altering observable behaviour
- Update documentation only (prefer
docs:commit prefix instead of a release) - Update dependency patch/minor versions (security patches, etc.)
- Fix a typo in an error message that does not affect parsing
A change is breaking if a consumer that worked correctly with version N can fail or behave differently after upgrading to version N+1 without any code changes on their side.
Common examples for this project:
| Area | Breaking example |
|---|---|
| Donations API | Renaming amount → donation_amount in POST /donations |
| Wallets API | Removing GET /wallets/:id/balance |
| Auth | Requiring a new mandatory header (X-Api-Version) |
| Response shape | Changing { "id": "..." } to { "donationId": "..." } |
| Errors | Changing HTTP status codes for existing error conditions |
| Scheduler | Removing a recurring-donation frequency type (e.g. weekly) |
Breaking changes must:
- Increment
MAJORversion - Be documented in
CHANGELOG.mdunder a### Breaking Changessub-heading - Trigger an API path version bump (see API Endpoint Versioning) if the change affects a public route
- Be announced with a minimum 4-week deprecation notice before the old behaviour is removed (see Deprecation Policy)
A change is non-breaking (backwards-compatible) if existing consumers can upgrade without any modification.
Common examples:
| Area | Non-breaking example |
|---|---|
| Donations API | Adding an optional note field to POST /donations |
| Wallets API | Adding a new GET /wallets/:id/stats endpoint |
| Response | Adding a new createdAt field to existing responses |
| Config | Adding a new optional environment variable |
| Docs | Updating README, guides, or inline comments |
Non-breaking additions increment MINOR; fixes increment PATCH.
URL-based versioning is used to isolate breaking change surfaces:
/v1/donations
/v1/wallets
/v2/donations ← introduced with breaking change in MAJOR v2
Rules:
- All routes are prefixed with
/v{MAJOR}(e.g./v1,/v2). - A new URL version is introduced only on a MAJOR bump.
- The previous URL version remains available for the deprecation window (minimum 4 weeks after the new MAJOR release).
MINORandPATCHreleases never introduce a new URL prefix — they are additive to the existing prefix.
When a new URL version is introduced:
- Create a new route file (e.g.
src/routes/v2/donations.js). - Mount both old and new versions in
app.jsduring the deprecation window. - Add a
Deprecationresponse header to the old version:Deprecation: version="v1", sunset="2026-06-30"
feature/fix branch → main (develop) → release tag → GitHub Release
-
All work merges into
mainvia pull request (see Branch Protection). -
Determine the version bump using the rules above. When in doubt, discuss in the related issue or pull request before releasing.
-
Update
CHANGELOG.mdwith all changes since the last release (see Changelog Requirements). -
Bump the version in
package.json:# Patch fix npm version patch --no-git-tag-version # New feature npm version minor --no-git-tag-version # Breaking change npm version major --no-git-tag-version
--no-git-tag-versionis used so the tag is created separately after review. -
Commit the version bump:
git add package.json pnpm-lock.yaml CHANGELOG.md git commit -m "chore: release v$(node -p "require('./package.json').version")" -
Create and push a signed tag:
VERSION=$(node -p "require('./package.json').version") git tag -a "v$VERSION" -m "Release v$VERSION" git push origin main --follow-tags
-
Create a GitHub Release from the tag:
- Title:
v{VERSION} - Body: copy the relevant section from
CHANGELOG.md - Mark as pre-release if the label is
alphaorbeta
- Title:
-
CI pipeline runs automatically on the new tag. All required checks (tests, coverage, lint) must pass — see CI Pipeline.
For critical production bugs that cannot wait for the normal release cycle:
-
Branch off the latest release tag:
git checkout -b hotfix/v1.2.1 v1.2.0
-
Apply the minimal fix, add a test covering the regression.
-
Follow steps 3–8 of the Release Flow directly on the hotfix branch.
-
Merge the hotfix branch back into
main:git checkout main git merge --no-ff hotfix/v1.2.1 git branch -d hotfix/v1.2.1
Hotfixes always produce a PATCH increment unless the fix itself introduces a breaking change (rare; if so, treat as a MAJOR).
When a feature, endpoint, or behaviour is scheduled for removal:
-
Announce the deprecation in the GitHub issue tracker with the label
deprecationat least 4 weeks before the MAJOR release that removes it. -
Log a deprecation warning server-side when the deprecated path is exercised:
console.warn('[DEPRECATED] GET /v1/wallets/:id/balance — use GET /v2/wallets/:id/balance instead. Removal scheduled for v2.0.0.');
-
Add a
Deprecationresponse header on affected endpoints:Deprecation: version="v1" Sunset: Mon, 30 Jun 2026 00:00:00 GMT -
Document the migration path in
CHANGELOG.mdand the relevantdocs/guide. -
Remove the deprecated code only after the sunset date has passed and the MAJOR version has been released.
Every release must include a CHANGELOG.md update. Use Keep a Changelog format:
## [1.2.0] - 2026-03-15
### Added
- `GET /v1/wallets/:id/stats` endpoint for donation analytics (#185)
- Optional `note` field on `POST /v1/donations`
### Changed
- Rate limit window for donation endpoints increased from 15 min to 30 min
### Deprecated
- `GET /v1/wallets/:id/balance` — use `GET /v1/wallets/:id/stats` instead (removal in v2.0.0)
### Fixed
- Idempotency key not persisted on Stellar network timeout (#201)
### Security
- Upgraded `stellar-sdk` to patch CVE-XXXX-XXXXRules:
- Entries are written for humans, not machines — describe the impact, not the diff.
- Every entry links to the relevant GitHub issue or PR number.
### Breaking Changesis a required sub-section under any MAJOR release entry.- Do not leave an
[Unreleased]section in the file at release time — rename it to the version and date.
For early testing of MAJOR changes, pre-release versions may be published:
| Label | Format | Meaning |
|---|---|---|
| Alpha | 2.0.0-alpha.1 |
Internal testing only; API may change |
| Beta | 2.0.0-beta.1 |
External testing; API is stabilising |
| Release Candidate | 2.0.0-rc.1 |
Feature-complete; only critical fixes accepted |
Pre-releases:
- Are tagged in Git with the full label (e.g.
v2.0.0-alpha.1). - Are marked as pre-release in GitHub Releases.
- Are never the default installation target.
- Must still pass CI (tests, coverage, lint) before tagging.
| Change type | Version bump | New URL prefix? |
|---|---|---|
| Remove or rename endpoint | MAJOR | Yes |
| Remove or rename request/response field | MAJOR | Yes |
| Add new optional field | MINOR | No |
| Add new endpoint | MINOR | No |
| Bug fix | PATCH | No |
| Docs only | No release needed | No |
| Security patch (no API change) | PATCH | No |
Related documents: