Aller au contenu principal

ADR-026 — API completeness & OpenAPI policy

1. Context

Noxys product narrative includes "API-first" but execution has drifted:

  • noxys-api/internal/docs/openapi.yaml exists but is stale (architecture-debt audit 2026-04-11 §6 flagged it).
  • 9 ADRs filed today (014-024) define ~50 new endpoints across subscriptions, storage, lineage, MFA, token reveal, entitlements, AI cost, devices, compliance reports, agent versions. None have OpenAPI spec entries.
  • No CI gate prevents endpoint additions without spec.
  • noxys-console consumes lib/api.ts with hand-written types — recurring shape-mismatch bugs (PRs #167-#173) trace back partly to this.
  • No SDK (Python / JS) ships. Roadmap row [#184] mentions SDK auto-gen but blocked on stable spec.
  • No public API docs portal — "API-first" claim has no surface to back it.

Without a binding policy, every new sprint will drift further. We must fix the base before ADR-014..024 implementation expands the gap.

2. Decision summary

  • OpenAPI 3.1 is the canonical API specification format.
  • Single source of truth = Go handlers + struct tags (in noxys-api). The openapi.yaml file is GENERATED, never hand-edited.
  • Generation tool: swaggo/swag (Go-native, struct-tag driven, mature). Alternative kin-openapi for parsing/validation only.
  • Hard rule: every PR introducing a new endpoint OR modifying request/response schemas MUST include an updated openapi.yaml. CI gate enforces this.
  • Console typed-client: openapi-typescript generates TS types from openapi.yaml; consumed by noxys-console/src/lib/api.ts to replace hand-written shapes.
  • SDK auto-gen: openapi-generator produces Python + JS clients on each release tag. Lives in noxys-contracts repo (existing).
  • Versioning: API path-versioned /api/v1/.... Breaking changes → /api/v2/... with 6-month deprecation overlap. Non-breaking additions OK in v1.
  • Public docs: Redoc-rendered openapi.yaml deployed at api.noxys.eu (or noxys.eu/api) post-Pro launch (W27-28).
  • Backfill obligation: ADRs 014-024 endpoints inventoried + spec'd before implementation sprints land code.

3. Single source of truth — Go handler annotations

// CreatePolicy creates a new policy for the tenant.
//
// @Summary Create policy
// @Description Create a tenant-scoped policy with conditions, actions, priority.
// @Tags policies
// @Accept json
// @Produce json
// @Param body body CreatePolicyRequest true "Policy spec"
// @Success 201 {object} Policy
// @Failure 400 {object} Error
// @Failure 403 {object} Error
// @Router /api/v1/policies [post]
// @Security BearerAuth
func (h *Handler) CreatePolicy(w http.ResponseWriter, r *http.Request) { ... }

type CreatePolicyRequest struct {
Name string `json:"name" validate:"required" example:"Block PII"`
Description string `json:"description,omitempty"`
Conditions []Condition `json:"conditions" validate:"required"`
Action string `json:"action" validate:"oneof=log redact block" example:"block"`
Priority int `json:"priority" validate:"min=0,max=100"`
Enabled bool `json:"enabled"`
}

make openapi-gen runs swag init -g cmd/api/main.go -o internal/docs/. Output openapi.yaml (and Swagger UI assets) updated atomically.

4. CI gate

# .github/workflows/openapi-validate.yml (noxys-api)
name: OpenAPI integrity
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- run: go install github.com/swaggo/swag/cmd/swag@latest
- run: make openapi-gen
- name: Fail if openapi.yaml drifted
run: |
if ! git diff --exit-code internal/docs/openapi.yaml; then
echo "::error::openapi.yaml is out of date. Run 'make openapi-gen' and commit."
exit 1
fi
- run: npx -y @redocly/cli lint internal/docs/openapi.yaml

Pre-commit hook (developer convenience):

# .githooks/pre-commit
#!/bin/sh
if git diff --cached --name-only | grep -qE '\.go$'; then
make openapi-gen >/dev/null 2>&1
git add internal/docs/openapi.yaml
fi

5. Console typed-client codegen

// noxys-console/package.json
{
"scripts": {
"openapi:fetch": "curl -fsSL https://api-staging.noxys.cloud/api/v1/openapi.yaml -o src/lib/openapi.yaml",
"openapi:gen": "openapi-typescript src/lib/openapi.yaml -o src/lib/openapi.types.ts"
},
"devDependencies": {
"openapi-typescript": "^7"
}
}

src/lib/api.ts becomes a thin wrapper around fetch that imports types from openapi.types.ts — all request/response shapes type-safe across full stack.

CI hook in noxys-console: fail if openapi.types.ts drift (regen + diff check) so frontend types track backend automatically.

6. SDK auto-gen (Python + JS)

noxys-contracts repo:

# .github/workflows/sdk-release.yml
on:
push:
tags: ['v*']
jobs:
python-sdk:
steps:
- uses: openapitools/openapi-generator-cli-action@v1
with:
generator: python
input: openapi.yaml
output: sdks/python
- run: cd sdks/python && python -m build
- run: twine upload dist/* --repository pypi
js-sdk:
steps:
- uses: openapitools/openapi-generator-cli-action@v1
with:
generator: typescript-fetch
input: openapi.yaml
output: sdks/js
- run: cd sdks/js && npm publish

Published as noxys-sdk on PyPI + @noxys/sdk on npm.

7. Public docs portal

Redoc-rendered static site:

<!-- api.noxys.eu/index.html (or noxys.eu/api) -->
<redoc spec-url="https://api.noxys.cloud/api/v1/openapi.yaml"></redoc>

Deployed via Cloudflare Pages with auto-deploy on noxys-contracts main branch (mirrors openapi.yaml from noxys-api).

Tier gating: full spec public Pro+ endpoints; Enterprise-only endpoints documented but flagged x-tier: enterprise in spec; access-controlled at API key level.

8. Versioning policy

  • Path-based: /api/v1/..., /api/v2/....
  • Non-breaking changes (added field, optional param, new endpoint) → stay in v1.
  • Breaking changes (removed field, type change, required-param addition) → bump v2 + 6-month deprecation overlap on v1.
  • Version sunset announced via Trust Center + email to API key holders 90d before.
  • Sunset header on deprecated endpoint responses (RFC 8594).

9. Backfill obligation — ADR 014-024 endpoints

The following endpoints (defined in ADRs but no OpenAPI yet) MUST be added to openapi.yaml before implementation sprints touch code:

  • ADR-014 AI-PLACE-* — /api/v1/copilot/ask, /api/v1/policies/semantic-eval, /api/v1/redaction/preview
  • ADR-018 SUB-* — /api/v1/subscriptions/*, /api/v1/subscriptions/:id/events, /api/v1/tenants/:id/subscription
  • ADR-019 STORE-* — /api/v1/storage/tiers, /api/v1/tenants/:id/region, /api/v1/tenants/:id/export, /api/v1/tenants/:id/erase
  • ADR-020 LINEAGE-* — /api/v1/interactions/:id/lineage, /api/v1/lineage/steps (ingest)
  • ADR-022 USERS-* — /api/v1/users/:id/entitlements, /api/v1/users/:id/cost
  • ADR-024 Auth+MFA — /auth/mfa/totp/setup, /auth/mfa/totp/verify, /auth/mfa/webauthn/begin, /auth/mfa/webauthn/finish, /auth/mfa/backup-codes, /api/v1/tenants/:id/mfa-policy, /api/v1/tenant-tokens (CRUD + reveal)
  • AGENT-VER-1/api/v1/agent/release-info, /api/v1/extension/release-info
  • TENANT-TOKEN-REVEAL-1/api/v1/tenant-tokens/:id/reveal

Sprint API-OPENAPI-4 owns this backfill.

10. Sprint plan — 7 sprints, 9.75 days

IDTitleRepoWindowEffortPriority
API-OPENAPI-1Regen baseline openapi.yaml from current state + swaggo annotations + Makefile targetnoxys-apiW21-221dP0
API-OPENAPI-2CI gate "no endpoint without spec" + pre-commit hooknoxys-apiW23-241dP1
API-OPENAPI-3openapi-typescript codegen in noxys-console; replace hand-written types in api.tsnoxys-consoleW25-261.5dP1
API-OPENAPI-4Backfill ADR 014-024 endpoints in openapi.yaml (subscriptions, storage, lineage, MFA, etc.)noxys-apiW23-242dP0
API-OPENAPI-5SDK Python + JS auto-gen via openapi-generator (closes [#184])noxys-contractsW27-283dP2
API-OPENAPI-6Public Redoc docs at api.noxys.eu + Cloudflare Pages deploynoxys-websiteW29-301dP2
API-OPENAPI-7Memory feedback rule + noxys-api/CLAUDE.md update + commit hook activationnoxys-apiW21-220.25dP0

P0 sprints (1, 4, 7) target W21-22 to fix base immediately. Existing related issues:

  • [#24] OpenAPI 3.1 regeneration → covered by API-OPENAPI-1; comment-ref
  • [#212] API publique REST v1 → covered by API-OPENAPI-1+2+5+6 combined; comment-ref
  • [#184] SDK auto-gen → covered by API-OPENAPI-5; close as duplicate-by-replacement

11. Memory rule (binding for all future ADRs / sprints)

Add to ~/.claude/projects/-home-jeromesoyer-Documents-Github-noxys/memory/:

feedback rule: Every new API endpoint defined in an ADR or sprint MUST include OpenAPI 3.1 spec entries in the same PR. CI gate enforces. Reject any feature proposal that introduces an endpoint without spec. Pre-implementation, the endpoint signature lands in openapi.yaml first; implementation follows.

12. Tier exposure rules

  • Free tier: read-only endpoints + tenant config CRUD.
  • Pro: full read/write + analytics endpoints.
  • Enterprise: + admin endpoints + bulk endpoints + region pin override + raw storage access.
  • Spec carries x-tier: free|pro|enterprise extension on each operation; API gateway enforces at runtime.
  • Public docs render shows tier badge per operation; non-subscribed tier dimmed.

13. Non-goals

  • gRPC public API (kept internal sidecar protocol).
  • GraphQL (REST-only public surface; complexity unjustified at current scale).
  • API throttling beyond per-tier rate limits (deferred to Cloudflare API Gateway integration, separate sprint).
  • Multi-tenant API key federation (Enterprise SSO covers it).

14. Open questions

  • swaggo vs alternative codegen: swaggo is Go-idiomatic but limited expressiveness. If we hit limitations, fallback to manual openapi.yaml authoring + use kin-openapi for runtime validation. Decide if/when blocker hit.
  • Spec hosting cache: openapi.yaml served from API server or static CDN? Recommend CDN for public; serve from API for authenticated tier-aware view (with tenant-specific endpoint visibility).
  • Backwards compat for noxys-extension API calls: extension uses /extension/* non-versioned routes today. Add to spec as v1 with deprecation notice if naming changes needed. Defer rename to V2.

15. Refs

  • noxys-api internal/docs/openapi.yaml (existing, stale)
  • noxys-contracts repo (protobuf + OpenAPI home)
  • Architecture-debt audit 2026-04-11 §6 (OpenAPI stale flag)
  • Roadmap [#24], [#212], [#184], [#510]
  • ADRs 014, 018, 019, 020, 022, 024 — endpoint sources for backfill
  • Future ADR-027 CRM choice (renumbered through ADR-019..ADR-026)