Everything the console does should be callable by API, documented and discoverable. Adds: OpenAPI 3.x generated from code (utoipa) + Swagger/Redoc at /api/docs (drift-proof, route<->spec parity test); long-lived revocable scoped API tokens (connect_api_tokens, hashed like agent keys) distinct from the 24h dashboard JWT and agent keys; an API-completeness gap audit (folds in SPEC-004/ 006/007 endpoints); consistent pagination/filtering + versioning policy. Today there is zero API doc tooling and no programmatic token. Depends on SPEC-008 for the documented error envelope; distinct from the ADR-001 integration contract. Large. Parallel guru-rmm SPEC-019. Requested by Mike 2026-05-30. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.4 KiB
SPEC-009: Feature-Rich, Fully-Documented Management API
Status: Proposed Priority: P2 Requested By: Mike (2026-05-30) Estimated Effort: Large
Overview
Make GuruConnect fully operable by API: nearly anything a tech can do in the console should be callable programmatically, against a documented, discoverable, versioned REST API with first-class auth for automation. Today the surface is decent but undocumented (no OpenAPI/Swagger), authable only by a 24h dashboard JWT or agent keys (no automation tokens), and has UI-only gaps. Success = an OpenAPI spec + browsable docs cover every public endpoint, a scripted client can authenticate with a long-lived revocable token and perform every management action the dashboard exposes, and new endpoints are documented by construction.
This is the GuruConnect half of a cross-product request; the GuruRMM side is guru-rmm SPEC-019. Keep auth model, error envelope, pagination, and doc conventions aligned across both Rust/Axum products.
Current state (researched)
- No API documentation tooling — no
utoipa/openapi/Swagger/Redoc anywhere (server/Cargo.toml,server/src/). The contract lives only inmain.rsroute registrations and handler code. - Reasonable but partial surface: auth, users (CRUD + client access), support codes, sessions (list/get/disconnect/viewer-token), machines (list/get/delete/history/keys), releases (CRUD), downloads, version. Several actions are dashboard-only or being added piecemeal (session purge/bulk → SPEC-004, machine search → SPEC-006, installer build → SPEC-007).
- Auth is dashboard/agent-shaped, not automation-shaped: JWT bearer (24h,
server/src/auth/mod.rs:101) for humans + agent/site keys for agents. No long-lived, revocable, scoped API token for external scripts/integrations. - No stable error contract until SPEC-008 lands (two envelopes today).
Scope
Included in v1
- API completeness audit + gap-fill. Enumerate every console action; ensure each has a documented public endpoint. Fill gaps (e.g. anything currently done only via in-memory state or dashboard-special handlers). The in-flight specs (SPEC-004 purge/bulk, SPEC-006 search, SPEC-007 installer build) register under this umbrella.
- OpenAPI 3.x, generated from code. Adopt
utoipa(Axum-native: derive schemas from handler/DTO annotations) → serveGET /api/openapi.json+ interactive docs (Swagger UI or Redoc) at/api/docs. Document auth, every endpoint, request/response schemas, the SPEC-008 error envelope, and examples. Docs generated by construction so they can't drift. - Programmatic API tokens. Long-lived, revocable, scoped user/integration tokens
(PAT-style) distinct from the 24h dashboard JWT and from agent keys: create/list/revoke
in the dashboard, hashed at rest, last-used tracking, optional expiry, scopes
(read-only vs. read-write, resource-scoped). Accepted as
Authorization: Beareron all/api/*like the JWT. - Consistency conventions: uniform pagination (
limit/offsetor cursor) + filtering- sorting on list endpoints; consistent resource naming; documented HTTP status usage (pairs with SPEC-008's structured errors).
- Versioning policy for the public API (header or path), and a documented relationship
to the ADR-001
/api/integration/v1/GuruRMM contract (that narrow, semver'd contract stays authoritative for its surface; this is the broader operator API).
Explicitly out of scope
- GraphQL or gRPC public API — REST + OpenAPI only.
- SDK/client-library generation — OpenAPI enables it later; not built here.
- Webhooks/event subscriptions — separate feature.
- Re-speccing the integration contract — owned by
specs/native-remote-control/.
Architecture
- Relay-server: add
utoipaderives to handler DTOs (server/src/api/*), anApiDocaggregator, and routes foropenapi.json+ docs UI (server/src/main.rs). Newapi_tokensmodule + middleware that accepts either a JWT or a valid API token (server/src/auth/). Gap endpoints added to the relevantapi/*modules. - DB:
connect_api_tokenstable (id, user_id, name, token_hash, scopes, created_at, last_used_at, expires_at, revoked_at) + migration. Mirrors the existingconnect_agent_keys/machine_keyshashing pattern. - Dashboard: a "API Tokens" settings page (create → show-once → list/revoke) and a
link to
/api/docs. - Protobuf: none.
Implementation details
- Files to touch:
server/Cargo.toml(utoipa,utoipa-swagger-ui/utoipa-redoc);server/src/api/*.rs(DTO#[derive(ToSchema)]+#[utoipa::path]annotations);server/src/main.rs(docs routes; token-aware auth layer);server/src/auth/(API-token verification beside JWT,mod.rs:101);server/src/db/api_tokens.rs(new) + migrationconnect_api_tokens; dashboard API-tokens settings page. - Reuse the agent-key hashing/verification approach for token storage; never store plaintext.
Security considerations
- Tokens are credentials: hash at rest, show plaintext once, support revoke + expiry +
scopes; log creation/revocation to
events; rate-limit token auth like login. - Scope enforcement: read-only tokens cannot mutate; resource-scoped tokens limited to their resources; admin-only actions require an admin-scoped token.
- Docs exposure:
/api/docsdescribes the API but must not leak secrets or be a CSRF/SSRF vector; gate write-trying "try it out" behind auth; consider auth-gating the docs UI in production. - No internal leakage in documented error examples (pairs with SPEC-008).
- Auth uniformity: the token path goes through the same guards as JWT so no endpoint is accidentally left token-bypassable.
Testing strategy
- Unit: OpenAPI spec builds and validates; every registered route appears in it (a test that diffs the router against the spec catches undocumented endpoints). Token verify (valid/expired/revoked/wrong-scope).
- Integration: a scripted client authenticates with an API token and performs a full CRUD lifecycle on machines/sessions/users/codes; read-only token is denied writes; the route↔spec parity test fails if a new endpoint lacks annotation.
- Manual: open
/api/docs, exercise representative calls with a created token; confirm examples match real responses.
Effort estimate & dependencies
- Size: Large. Annotating the full surface for OpenAPI + the API-token subsystem + the gap audit is broad, though each handler annotation is mechanical.
- Depends on: SPEC-008 for the documented error envelope (document it once, right). Composes with SPEC-004/006/007 (their new endpoints land documented). Independent of the ADR-001 integration contract but should cross-reference it.
- Unblocks: automation/scripting against GuruConnect, future SDKs, and third-party integrations; a self-documenting API that stays current.
Open questions
- Docs UI in production — public, or auth-gated? Proposed: spec JSON public, "try it out" + UI auth-gated.
- Token scopes granularity — coarse (read/write/admin) for v1 vs. per-resource scopes? Proposed: coarse first, structure for finer later.
- Versioning mechanism — path (
/api/v1) vs. header; and do we retrofit existing/api/*as v1 or leave unversioned with v1 as an alias? - utoipa vs. hand-maintained spec — confirm utoipa (codegen, drift-proof) over a hand-written YAML.