Files
guru-connect/docs/specs/SPEC-009-feature-rich-documented-api.md
Mike Swanson 7ab87384a7
Some checks failed
Build and Test / Build Server (Linux) (push) Failing after 3m42s
Build and Test / Build Agent (Windows) (push) Successful in 7m39s
Build and Test / Security Audit (push) Successful in 4m34s
Build and Test / Build Summary (push) Has been skipped
spec: add SPEC-009 feature-rich documented API
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>
2026-05-30 16:35:57 -07:00

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 in main.rs route 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) → serve GET /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: Bearer on all /api/* like the JWT.
  • Consistency conventions: uniform pagination (limit/offset or 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 utoipa derives to handler DTOs (server/src/api/*), an ApiDoc aggregator, and routes for openapi.json + docs UI (server/src/main.rs). New api_tokens module + middleware that accepts either a JWT or a valid API token (server/src/auth/). Gap endpoints added to the relevant api/* modules.
  • DB: connect_api_tokens table (id, user_id, name, token_hash, scopes, created_at, last_used_at, expires_at, revoked_at) + migration. Mirrors the existing connect_agent_keys/machine_keys hashing 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) + migration connect_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/docs describes 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

  1. Docs UI in production — public, or auth-gated? Proposed: spec JSON public, "try it out" + UI auth-gated.
  2. Token scopes granularity — coarse (read/write/admin) for v1 vs. per-resource scopes? Proposed: coarse first, structure for finer later.
  3. Versioning mechanism — path (/api/v1) vs. header; and do we retrofit existing /api/* as v1 or leave unversioned with v1 as an alias?
  4. utoipa vs. hand-maintained spec — confirm utoipa (codegen, drift-proof) over a hand-written YAML.