Difficulty: Expert
Type: DevOps
Background
The README defines a strict versioning contract: /v1 routes stay backward-compatible, an x-guildpass-api-version header is returned on all responses, GET /health/live exposes server version, and deprecated routes serve a deprecation: true header with a minimum sunset period before removal — but no /v2 currently exists, and the sunset mechanism appears to be a policy statement rather than enforced tooling.
Problem
Without tooling to enforce it, the deprecation policy depends on manual discipline: nothing currently prevents a maintainer from removing a deprecated route before its sunset period ends, and there's no structured way to run /v1 and a future /v2 side-by-side with shared business logic.
Expected outcome
A /v2 route namespace exists alongside /v1 sharing the same underlying services (not duplicated logic), a machine-readable deprecation registry records each deprecated route/field with its deprecation date and minimum sunset window, and an automated check (runnable locally and intended for CI) fails if a route is removed before its recorded sunset date has passed.
Suggested implementation
- Introduce a version-agnostic service layer (if not already cleanly separated from route handlers, per the README's "business logic lives in services" note) so
/v1 and /v2 route handlers can both call the same underlying functions, differing only in request/response shape where needed.
- Add a
deprecation-registry.json (or similar) recording { route, deprecatedAt, minimumSunsetDays } entries, and update the deprecation: true header logic to read from this registry rather than being set ad hoc per route.
- Add a script (
npm run -w access-api deprecations:check) that fails if any registry entry's sunset window has expired and the route still exists, or conversely flags routes removed from code that are still referenced in the registry without being marked fully removed.
- Pick one real, currently-awkward
/v1 field or route to actually deprecate and migrate to /v2 as a proof of the pattern (e.g., a response field whose shape should change).
- Update
docs/openapi.json generation to emit separate specs (or a combined spec with version-tagged paths) for /v1 and /v2.
- Document the full versioning/deprecation workflow for future contributors in the README's API Versioning section.
Acceptance criteria
Likely affected files/directories
apps/access-api/src/routes/
apps/access-api/src/services/
apps/access-api/src/scripts/ (new deprecation check)
docs/openapi.json
README.md
Difficulty: Expert
Type: DevOps
Background
The README defines a strict versioning contract:
/v1routes stay backward-compatible, anx-guildpass-api-versionheader is returned on all responses,GET /health/liveexposes server version, and deprecated routes serve adeprecation: trueheader with a minimum sunset period before removal — but no/v2currently exists, and the sunset mechanism appears to be a policy statement rather than enforced tooling.Problem
Without tooling to enforce it, the deprecation policy depends on manual discipline: nothing currently prevents a maintainer from removing a deprecated route before its sunset period ends, and there's no structured way to run
/v1and a future/v2side-by-side with shared business logic.Expected outcome
A
/v2route namespace exists alongside/v1sharing the same underlying services (not duplicated logic), a machine-readable deprecation registry records each deprecated route/field with its deprecation date and minimum sunset window, and an automated check (runnable locally and intended for CI) fails if a route is removed before its recorded sunset date has passed.Suggested implementation
/v1and/v2route handlers can both call the same underlying functions, differing only in request/response shape where needed.deprecation-registry.json(or similar) recording{ route, deprecatedAt, minimumSunsetDays }entries, and update thedeprecation: trueheader logic to read from this registry rather than being set ad hoc per route.npm run -w access-api deprecations:check) that fails if any registry entry's sunset window has expired and the route still exists, or conversely flags routes removed from code that are still referenced in the registry without being marked fully removed./v1field or route to actually deprecate and migrate to/v2as a proof of the pattern (e.g., a response field whose shape should change).docs/openapi.jsongeneration to emit separate specs (or a combined spec with version-tagged paths) for/v1and/v2.Acceptance criteria
/v2namespace exists and shares business logic with/v1(no significant duplicated service code)deprecation: trueheader rather than manual per-route logicLikely affected files/directories
apps/access-api/src/routes/apps/access-api/src/services/apps/access-api/src/scripts/(new deprecation check)docs/openapi.jsonREADME.md