Skip to content

feat(docs): OpenAPI 3 spec + Swagger UI — auto-derived from routes, full endpoint coverage, CI drift-gate - #1341

Closed
strausmann wants to merge 26 commits into
Finsys:mainfrom
strausmann:feat/openapi-refresh
Closed

strausmann wants to merge 26 commits into
Finsys:mainfrom
strausmann:feat/openapi-refresh

Conversation

@strausmann

Copy link
Copy Markdown
Contributor

Proposed change

Adds OpenAPI 3 documentation for the REST API, served at GET /api/docs (JSON spec) and GET /api/docs/ui (self-hosted Swagger UI — no external CDN).

Unlike a hand-written spec, this one is generated from the route tree (src/routes/api/**/+server.ts):

  • Paths, methods, tags, and both security schemes are auto-derived from the routes themselves.
  • Static analysis of each handler auto-populates query params, path params, status codes, and request-body fields — so the spec's structure stays in sync with the code with zero per-endpoint maintenance.
  • Rich per-endpoint docs (summary, params, request/response schemas, examples) come from a compact @openapi JSDoc block written directly above each handler. All 336 handlers are annotated.
  • Two security schemes documented: cookie session auth and Bearer API token (dh_ user tokens).
  • A CI drift-gate (bun run generate:openapi:check, wired into .github/workflows/openapi.yml) fails the pipeline on drift — an undocumented endpoint, or a query-param/status-code/path-param mismatch between a handler's JSDoc and its actual code. The docs can't silently go stale.

This is a clean refresh of #816 against current main — the old branch had diverged badly after the src/ restructure, and this rebuild also switches from a hand-maintained static spec to the auto-generated approach above.

Validation: @redocly/cli lint and @apidevtools/swagger-parser both report the generated spec as valid (233 paths, 336 operations).

Closes #814
Supersedes #816

Type of change

  • Bug fix: non-breaking change which fixes an issue.
  • New feature / Enhancement: non-breaking change which adds functionality.
  • Breaking change: fix or feature that would cause existing functionality to not work as expected.
  • Other. Please explain:

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class OpenAPI 3 documentation to Dockhand, including a JSON spec endpoint and a self-hosted Swagger UI, and annotates existing route handlers with @openapi blocks so the spec can be generated/validated from the route tree and handler analysis (with CI drift gating).

Changes:

  • Add GET /api/docs (generated OpenAPI JSON) and GET /api/docs/ui (Swagger UI viewer).
  • Add @openapi JSDoc annotations across a large set of existing endpoints (including SSE/streaming endpoints).
  • Add a CI workflow to fail on OpenAPI drift/validation issues and wire generation into the build pipeline.

Reviewed changes

Copilot reviewed 243 out of 248 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/routes/metrics/+server.ts Add @openapi annotation for Prometheus metrics endpoint.
src/routes/audit/+server.ts Add @openapi annotation for audit log listing endpoint.
src/routes/audit/users/+server.ts Add @openapi annotation for audit-user filter list endpoint.
src/routes/api/vulnerabilities/+server.ts Add @openapi annotation for vulnerability findings listing endpoint.
src/routes/api/vulnerabilities/count/+server.ts Add @openapi annotation for vulnerability dashboard metadata endpoint.
src/routes/api/vulnerabilities/export/+server.ts Add @openapi annotation for vulnerability export endpoint.
src/routes/api/vulnerabilities/scan-all/+server.ts Add @openapi annotation for SSE “scan all images” endpoint.
src/routes/api/volumes/+server.ts Add @openapi annotations for volume list/create endpoints.
src/routes/api/volumes/[name]/+server.ts Add @openapi annotations for volume inspect/delete endpoints.
src/routes/api/volumes/[name]/inspect/+server.ts Add @openapi annotation for raw Docker volume inspect endpoint.
src/routes/api/volumes/[name]/export/+server.ts Add @openapi annotation for streaming volume export endpoint.
src/routes/api/volumes/[name]/clone/+server.ts Add @openapi annotation for volume clone endpoint.
src/routes/api/volumes/[name]/browse/+server.ts Add @openapi annotation for volume browse endpoint.
src/routes/api/volumes/[name]/browse/content/+server.ts Add @openapi annotation for volume file-content endpoint.
src/routes/api/volumes/[name]/browse/release/+server.ts Add @openapi annotation and tweak comment formatting.
src/routes/api/users/+server.ts Add @openapi annotations for users list/create endpoints.
src/routes/api/users/[id]/mfa/+server.ts Add @openapi annotations for MFA setup/disable endpoints.
src/routes/api/templates/+server.ts Add @openapi annotation for templates list endpoint.
src/routes/api/templates/compose/+server.ts Add @openapi annotation for template compose generation endpoint.
src/routes/api/system/+server.ts Add @openapi annotation for system info aggregation endpoint.
src/routes/api/system/disk/+server.ts Add @openapi annotation for disk-usage endpoint.
src/routes/api/system/files/+server.ts Add @openapi annotations for filesystem browse/create-dir endpoints.
src/routes/api/system/files/content/+server.ts Add @openapi annotation for file-content endpoint.
src/routes/api/stacks/+server.ts Add @openapi annotations for stacks list/create endpoints.
src/routes/api/stacks/adopt/+server.ts Add @openapi annotation for stack adoption endpoint.
src/routes/api/stacks/base-path/+server.ts Add @openapi annotation for stacks base-path endpoint.
src/routes/api/stacks/default-path/+server.ts Add @openapi annotation and clarify existing comment.
src/routes/api/stacks/path-hints/+server.ts Add @openapi annotation for path-hints endpoint.
src/routes/api/stacks/scan/+server.ts Add @openapi annotation for external stack scan endpoint.
src/routes/api/stacks/sources/+server.ts Add @openapi annotation for stack source metadata endpoint.
src/routes/api/stacks/validate-path/+server.ts Add @openapi annotation for external stack path validation endpoint.
src/routes/api/stacks/[name]/+server.ts Add @openapi annotation for stack removal endpoint.
src/routes/api/stacks/[name]/check-path-change/+server.ts Add @openapi annotation for stack path-change check endpoint.
src/routes/api/stacks/[name]/deploy/+server.ts Add @openapi annotation for SSE deploy endpoint.
src/routes/api/stacks/[name]/down/+server.ts Add @openapi annotation for async down endpoint.
src/routes/api/stacks/[name]/env/raw/+server.ts Add @openapi annotations for env raw get/put endpoints.
src/routes/api/stacks/[name]/env/validate/+server.ts Add @openapi annotation for env var validation endpoint.
src/routes/api/stacks/[name]/relocate/+server.ts Add @openapi annotation for stack relocate endpoint.
src/routes/api/stacks/[name]/restart/+server.ts Add @openapi annotation for SSE restart/recreate endpoint.
src/routes/api/stacks/[name]/start/+server.ts Add @openapi annotation for async start endpoint.
src/routes/api/stacks/[name]/stop/+server.ts Add @openapi annotation for async stop endpoint.
src/routes/api/settings/theme/+server.ts Add @openapi annotation for public theme settings endpoint.
src/routes/api/settings/scanner/cache/+server.ts Add @openapi annotation for scanner cache clear endpoint.
src/routes/api/self-update/+server.ts Add @openapi annotation for self-update trigger endpoint.
src/routes/api/self-update/check/+server.ts Add @openapi annotation for update availability check endpoint.
src/routes/api/self-update/progress/+server.ts Add @openapi annotation for updater progress polling endpoint.
src/routes/api/schedules/+server.ts Add @openapi annotation for schedules list endpoint.
src/routes/api/schedules/settings/+server.ts Add @openapi annotations for schedules page preference get/put endpoints.
src/routes/api/schedules/stream/+server.ts Add @openapi annotation for schedules SSE stream endpoint.
src/routes/api/schedules/executions/+server.ts Add @openapi annotation for schedule execution history endpoint.
src/routes/api/schedules/executions/[id]/+server.ts Add @openapi annotations for execution get/delete endpoints.
src/routes/api/schedules/[type]/[id]/+server.ts Add @openapi annotation for schedule delete/disable endpoint.
src/routes/api/schedules/[type]/[id]/run/+server.ts Add @openapi annotation for manual schedule run endpoint.
src/routes/api/schedules/[type]/[id]/toggle/+server.ts Add @openapi annotation for schedule toggle endpoint.
src/routes/api/schedules/system/[id]/toggle/+server.ts Add @openapi annotation for system schedule toggle endpoint.
src/routes/api/roles/+server.ts Add @openapi annotations for role list/create endpoints.
src/routes/api/registry/catalog/+server.ts Add @openapi annotation for registry catalog endpoint.
src/routes/api/registry/image/+server.ts Add @openapi annotation for registry tag deletion endpoint.
src/routes/api/registry/search/+server.ts Add @openapi annotation for registry search endpoint.
src/routes/api/registry/tags/+server.ts Add @openapi annotation for registry tags endpoint.
src/routes/api/registries/+server.ts Add @openapi annotations for registries list/create endpoints.
src/routes/api/registries/test/+server.ts Add @openapi annotation for registry test endpoint.
src/routes/api/registries/[id]/default/+server.ts Add @openapi annotation for “set default registry” endpoint.
src/routes/api/prune/all/+server.ts Add @openapi annotation for prune-all endpoint.
src/routes/api/prune/containers/+server.ts Add @openapi annotation for container prune endpoint.
src/routes/api/prune/images/+server.ts Add @openapi annotation for image prune SSE endpoint.
src/routes/api/prune/networks/+server.ts Add @openapi annotation for network prune endpoint.
src/routes/api/prune/volumes/+server.ts Add @openapi annotation for volume prune endpoint.
src/routes/api/profile/+server.ts Add @openapi annotations for profile get/update endpoints.
src/routes/api/profile/avatar/+server.ts Add @openapi annotations for avatar upload/delete endpoints.
src/routes/api/profile/preferences/+server.ts Add @openapi annotations for theme preferences get/put endpoints.
src/routes/api/preferences/sidebar/+server.ts Add @openapi annotations for sidebar prefs get/post/delete endpoints.
src/routes/api/preferences/grid/+server.ts Add @openapi annotations for grid prefs get/post/delete endpoints.
src/routes/api/preferences/favorites/+server.ts Add @openapi annotations for log favorites get/post endpoints.
src/routes/api/preferences/favorite-groups/+server.ts Add @openapi annotations for log favorite-groups get/post endpoints.
src/routes/api/notifications/+server.ts Add @openapi annotations for notifications list/create endpoints.
src/routes/api/notifications/test/+server.ts Add @openapi annotation for ad-hoc notification test endpoint.
src/routes/api/notifications/trigger-test/+server.ts Add @openapi annotations for trigger-test and event-types list endpoints.
src/routes/api/notifications/[id]/test/+server.ts Add @openapi annotation for saved-notification test endpoint.
src/routes/api/networks/+server.ts Add @openapi annotations for networks list/create endpoints.
src/routes/api/networks/[id]/+server.ts Add @openapi annotations for network inspect/delete endpoints.
src/routes/api/networks/[id]/inspect/+server.ts Add @openapi annotation for network inspect endpoint.
src/routes/api/networks/[id]/connect/+server.ts Add @openapi annotation for network connect endpoint.
src/routes/api/networks/[id]/disconnect/+server.ts Add @openapi annotation for network disconnect endpoint.
src/routes/api/logs/merged/+server.ts Add @openapi annotation for merged logs SSE endpoint.
src/routes/api/license/+server.ts Add @openapi annotations for license get/activate/deactivate endpoints.
src/routes/api/legal/license/+server.ts Add @openapi annotation for LICENSE.txt endpoint.
src/routes/api/legal/privacy/+server.ts Add @openapi annotation for PRIVACY.txt endpoint.
src/routes/api/jobs/[id]/+server.ts Add @openapi annotations for job polling/cancel endpoints.
src/routes/api/images/+server.ts Add @openapi annotation for image list endpoint.
src/routes/api/images/pull/+server.ts Add @openapi annotation for pull SSE endpoint.
src/routes/api/images/push/+server.ts Add @openapi annotation for push endpoint.
src/routes/api/images/scan/+server.ts Add @openapi annotations for scan start and cached-result endpoints.
src/routes/api/images/scan/export/+server.ts Add @openapi annotation for scan export endpoint.
src/routes/api/images/[id]/+server.ts Add @openapi annotation for image delete endpoint.
src/routes/api/images/[id]/export/+server.ts Add @openapi annotation for image export endpoint.
src/routes/api/images/[id]/history/+server.ts Add @openapi annotation for image history endpoint.
src/routes/api/images/[id]/tag/+server.ts Add @openapi annotation for image tagging endpoint.
src/routes/api/host/+server.ts Add @openapi annotation for host info endpoint.
src/routes/api/health/+server.ts Add @openapi annotation for liveness endpoint.
src/routes/api/health/database/+server.ts Add @openapi annotation for DB schema health endpoint.
src/routes/api/hawser/connect/+server.ts Add @openapi annotations for Hawser connect status and non-WS fallback.
src/routes/api/git/credentials/+server.ts Add @openapi annotations for git credentials list/create endpoints.
src/routes/api/git/preview-env/+server.ts Add @openapi annotation for env preview endpoint.
src/routes/api/git/repositories/+server.ts Add @openapi annotations for repositories list/create endpoints.
src/routes/api/git/repositories/test/+server.ts Add @openapi annotation for unsaved repo test endpoint.
src/routes/api/git/repositories/[id]/deploy/+server.ts Add @openapi annotation for repository deploy endpoint.
src/routes/api/git/repositories/[id]/sync/+server.ts Add @openapi annotations for repo sync and update-check endpoints.
src/routes/api/git/repositories/[id]/test/+server.ts Add @openapi annotation for saved repo test endpoint.
src/routes/api/git/stacks/[id]/deploy/+server.ts Add @openapi annotation for git stack deploy endpoint.
src/routes/api/git/stacks/[id]/deploy-stream/+server.ts Add @openapi annotation for git stack deploy-stream endpoint.
src/routes/api/git/stacks/[id]/env-files/+server.ts Add @openapi annotations for git stack env-files list/read endpoints.
src/routes/api/git/stacks/[id]/sync/+server.ts Add @openapi annotation for git stack sync endpoint.
src/routes/api/git/stacks/[id]/test/+server.ts Add @openapi annotation for git stack test endpoint.
src/routes/api/git/stacks/[id]/webhook/+server.ts Add @openapi annotations for git stack webhook POST/GET endpoints.
src/routes/api/git/webhook/[id]/+server.ts Add @openapi annotations for repository webhook POST/GET endpoints.
src/routes/api/events/+server.ts Add @openapi annotation for Docker events SSE endpoint.
src/routes/api/environments/+server.ts Add @openapi annotations for environments list/create endpoints.
src/routes/api/environments/test/+server.ts Add @openapi annotation for connection test (unsaved) endpoint.
src/routes/api/environments/detect-socket/+server.ts Add @openapi annotation for socket detection endpoint.
src/routes/api/environments/[id]/disk-warning/+server.ts Add @openapi annotations for disk-warning get/set endpoints.
src/routes/api/environments/[id]/notifications/+server.ts Add @openapi annotations for env notification list/attach endpoints.
src/routes/api/environments/[id]/test/+server.ts Add @openapi annotation for saved environment test endpoint.
src/routes/api/environments/[id]/timezone/+server.ts Add @openapi annotations for timezone get/set endpoints.
src/routes/api/environments/[id]/update-check/+server.ts Add @openapi annotations for update-check settings get/save endpoints.
src/routes/api/dashboard/preferences/+server.ts Add @openapi annotations for dashboard prefs get/update endpoints.
src/routes/api/dashboard/stats/+server.ts Add @openapi annotation for dashboard stats endpoint.
src/routes/api/dashboard/stats/stream/+server.ts Add @openapi annotation for dashboard stats SSE endpoint.
src/routes/api/debug/memory/+server.ts Add @openapi annotation for memory diagnostics endpoint.
src/routes/api/dependencies/+server.ts Add @openapi annotation for dependency inventory endpoint.
src/routes/api/docs/+server.ts Add OpenAPI spec JSON endpoint implementation and annotation.
src/routes/api/docs/ui/+page.server.ts Add server load stub for Swagger UI page lifecycle/auth bypass.
src/routes/api/changelog/+server.ts Add @openapi annotation for changelog endpoint.
src/routes/api/containers/+server.ts Add @openapi annotations for containers list/create endpoints.
src/routes/api/containers/[id]/+server.ts Add @openapi annotations for container inspect/remove endpoints.
src/routes/api/containers/[id]/exec/+server.ts Add @openapi annotation for exec creation endpoint.
src/routes/api/containers/[id]/inspect/+server.ts Add @openapi annotation for inspect endpoint.
src/routes/api/containers/[id]/logs/+server.ts Add @openapi annotation for non-streaming logs endpoint.
src/routes/api/containers/[id]/logs/stream/+server.ts Add @openapi annotation for streaming logs SSE endpoint.
src/routes/api/containers/[id]/pause/+server.ts Add @openapi annotation for pause endpoint.
src/routes/api/containers/[id]/unpause/+server.ts Add @openapi annotation for unpause endpoint.
src/routes/api/containers/[id]/rename/+server.ts Add @openapi annotation for rename endpoint.
src/routes/api/containers/[id]/restart/+server.ts Add @openapi annotation for restart endpoint.
src/routes/api/containers/[id]/start/+server.ts Add @openapi annotation for start endpoint.
src/routes/api/containers/[id]/stop/+server.ts Add @openapi annotation for stop endpoint.
src/routes/api/containers/[id]/stats/+server.ts Add @openapi annotation for per-container stats endpoint.
src/routes/api/containers/[id]/top/+server.ts Add @openapi annotation for top/ps endpoint.
src/routes/api/containers/[id]/update/+server.ts Add @openapi annotation for container recreate/update endpoint.
src/routes/api/containers/[id]/update-runtime/+server.ts Add @openapi annotation for in-place runtime update endpoint.
src/routes/api/containers/[id]/shells/+server.ts Add @openapi annotation for shell-probe endpoint.
src/routes/api/containers/[id]/files/+server.ts Add @openapi annotation for container file listing endpoint.
src/routes/api/containers/[id]/files/chmod/+server.ts Add @openapi annotation for chmod endpoint.
src/routes/api/containers/[id]/files/create/+server.ts Add @openapi annotation for file/dir create endpoint.
src/routes/api/containers/[id]/files/delete/+server.ts Add @openapi annotation for delete endpoint.
src/routes/api/containers/[id]/files/download/+server.ts Add @openapi annotation for download endpoint.
src/routes/api/containers/[id]/files/rename/+server.ts Add @openapi annotation for rename/move endpoint.
src/routes/api/containers/[id]/files/upload/+server.ts Add @openapi annotation for multipart upload endpoint.
src/routes/api/containers/batch-update/+server.ts Add @openapi annotation for batch update endpoint.
src/routes/api/containers/batch-update-stream/+server.ts Add @openapi annotation for batch update SSE endpoint.
src/routes/api/containers/check-updates/+server.ts Add @openapi annotations for cached read and fresh-check trigger endpoints.
src/routes/api/containers/pending-updates/+server.ts Add @openapi annotations for pending updates list/clear endpoints.
src/routes/api/containers/sizes/+server.ts Add @openapi annotation for container size listing endpoint.
src/routes/api/containers/stats/+server.ts Add @openapi annotation for stats snapshot endpoint.
src/routes/api/containers/stats/stream/+server.ts Add @openapi annotation for stats SSE stream endpoint.
src/routes/api/backup/destinations/+server.ts Add @openapi annotations for backup destinations list/create endpoints.
src/routes/api/backup/destinations/test/+server.ts Add @openapi annotation for inline/saved destination test endpoint.
src/routes/api/backup/destinations/[id]/init/+server.ts Add @openapi annotation for destination init endpoint.
src/routes/api/backup/destinations/[id]/rotate-key/+server.ts Add @openapi annotation for password rotation endpoint.
src/routes/api/backup/destinations/[id]/task/+server.ts Add @openapi annotation for repo maintenance task endpoint.
src/routes/api/backup/destinations/[id]/test/+server.ts Add @openapi annotation for saved destination test endpoint.
src/routes/api/backup/destinations/[id]/verify/+server.ts Add @openapi annotation for verify SSE endpoint.
src/routes/api/backup/configs/+server.ts Add @openapi annotations for backup config list/create endpoints.
src/routes/api/backup/configs/[id]/run/+server.ts Add @openapi annotation for manual backup run SSE endpoint.
src/routes/api/backup/configs/[id]/stop/+server.ts Add @openapi annotation for cancel backup endpoint.
src/routes/api/backup/restore/+server.ts Add @openapi annotation for restore SSE endpoint.
src/routes/api/backup/restore/preview/+server.ts Add @openapi annotation for restore preview endpoint.
src/routes/api/backup/restore/stop/+server.ts Add @openapi annotation for restore cancel endpoint.
src/routes/api/backup/snapshots/+server.ts Add @openapi annotation for snapshot listing endpoint.
src/routes/api/backup/snapshots/diff/+server.ts Add @openapi annotation for snapshot diff endpoint.
src/routes/api/backup/snapshots/[id]/+server.ts Add @openapi annotation for snapshot forget/prune endpoint.
src/routes/api/backup/snapshots/[id]/browse/+server.ts Add @openapi annotation for snapshot browse endpoint.
src/routes/api/backup/snapshots/[id]/dump/+server.ts Add @openapi annotation for snapshot dump/download endpoint.
src/routes/api/backup/snapshots/[id]/metadata/+server.ts Add @openapi annotation for snapshot metadata endpoint.
src/routes/api/batch/+server.ts Add @openapi annotation and clarify comment formatting for batch operations endpoint.
src/routes/api/auth/login/+server.ts Add @openapi annotation for login endpoint.
src/routes/api/auth/logout/+server.ts Add @openapi annotation for logout endpoint.
src/routes/api/auth/session/+server.ts Add @openapi annotation for session bootstrap endpoint.
src/routes/api/auth/settings/+server.ts Add @openapi annotations for auth settings get/put endpoints.
src/routes/api/auth/providers/+server.ts Add @openapi annotation for auth providers list endpoint.
src/routes/api/auth/oidc/+server.ts Add @openapi annotations for OIDC list/create endpoints.
src/routes/api/auth/oidc/callback/+server.ts Add @openapi annotation for OIDC callback endpoint.
src/routes/api/auth/oidc/[id]/initiate/+server.ts Add @openapi annotations for OIDC initiate endpoints.
src/routes/api/auth/oidc/[id]/test/+server.ts Add @openapi annotation for OIDC connection test endpoint.
src/routes/api/auth/ldap/+server.ts Add @openapi annotations for LDAP list/create endpoints.
src/routes/api/auth/ldap/[id]/test/+server.ts Add @openapi annotation for LDAP connection test endpoint.
src/routes/api/auth/tokens/+server.ts Add @openapi annotations for token list/create endpoints.
src/routes/api/auth/tokens/[id]/+server.ts Add @openapi annotation for token revoke endpoint.
src/routes/api/auto-update/+server.ts Add @openapi annotation for auto-update settings batch endpoint.
src/routes/api/activity/+server.ts Add @openapi annotations for activity query and clear endpoints.
src/routes/api/activity/containers/+server.ts Add @openapi annotation for distinct container-name listing endpoint.
src/routes/api/activity/events/+server.ts Add @openapi annotation for activity SSE stream endpoint.
src/routes/api/activity/stats/+server.ts Add @openapi annotation for activity stats endpoint.
src/routes/api/audit/+server.ts Add @openapi annotation for audit log query endpoint (enterprise).
src/routes/api/audit/events/+server.ts Add @openapi annotation for audit SSE stream endpoint (enterprise).
src/routes/api/audit/export/+server.ts Add @openapi annotation for audit export endpoint (enterprise).
src/routes/api/audit/users/+server.ts Add @openapi annotation for audit usernames endpoint (enterprise).
src/routes/api/docs/ui/+page.server.ts Add server load stub for Swagger UI route integration.
src/routes/+layout.svelte Hide app chrome for Swagger UI route.
src/routes/+layout.server.ts Allow /api/docs (and children) through auth guard for page loads.
src/hooks.server.ts Allow /api/docs (and children) through global auth hook.
package.json Run OpenAPI generation during prebuild; add OpenAPI scripts and Swagger UI dependency.
.github/workflows/openapi.yml Add CI job to generate and validate the OpenAPI spec and upload it as an artifact.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread package.json Outdated
"scripts": {
"dev": "npx vite dev",
"prebuild": "npx license-checker --json --production | jq 'to_entries | map({name: (.key | split(\"@\")[0:-1] | join(\"@\")), version: (.key | split(\"@\")[-1]), license: .value.licenses, repository: .value.repository}) | sort_by(.name)' > src/lib/data/dependencies.json.tmp && mv src/lib/data/dependencies.json.tmp src/lib/data/dependencies.json || true",
"prebuild": "npx license-checker --json --production | jq 'to_entries | map({name: (.key | split(\"@\")[0:-1] | join(\"@\")), version: (.key | split(\"@\")[-1]), license: .value.licenses, repository: .value.repository}) | sort_by(.name)' > src/lib/data/dependencies.json.tmp && mv src/lib/data/dependencies.json.tmp src/lib/data/dependencies.json || true && bun run generate:openapi",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c8d2bc8: switched generate:openapi/generate:openapi:check (and the prebuild hook that calls them) from bun to npx tsx, pinned tsx as an exact devDependency, and dropped the Bun setup step from the CI workflow (no longer needed). Also fixed a latent Bun-only import.meta.dir in the generator itself that would have thrown under plain Node even after switching the invocation. Verified npm run build's prebuild step runs clean under Node.

Comment thread package.json Outdated
"qrcode": "1.5.4",
"rollup": "4.60.0",
"svelte-sonner": "1.0.7",
"swagger-ui-dist": "^5.32.11",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c8d2bc8: pinned to the exact version (5.32.11) instead of a caret range, matching every other dependency in the file.

Comment on lines +6 to +25
// Written by `npm run generate:openapi` (scripts/generate-openapi.ts), which
// runs as part of the regular build (see package.json "prebuild:openapi").
// Served straight off disk rather than imported, so a re-generated spec is
// picked up on the next request without a server restart in dev.
const SPEC_PATH = join(process.cwd(), 'static', 'openapi.json');

/**
* @openapi
* summary: The full OpenAPI 3.0 specification for the Dockhand REST API (unauthenticated)
* resp-200: object
* resp-200-desc: The generated OpenAPI document — see GET /api/docs/ui for an interactive viewer
* resp-404: Spec not generated yet — run `npm run generate:openapi`
*/
export const GET: RequestHandler = async () => {
if (!existsSync(SPEC_PATH)) {
throw error(404, 'OpenAPI spec not generated yet — run `npm run generate:openapi`');
}
const spec = JSON.parse(readFileSync(SPEC_PATH, 'utf-8'));
return json(spec);
};

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c8d2bc8: the spec is now written to an importable module (src/lib/openapi.generated.json) by the generator, and GET /api/docs imports it (import spec from '$lib/openapi.generated.json') instead of reading static/openapi.json off disk at request time. Vite bundles it straight into the built server output, so it's available regardless of whether static/ ships alongside build/ in the runtime image. The Swagger UI assets under static/swagger-ui/ were unaffected by this bug — those load via HTTP from build/client/, which SvelteKit does copy — but I re-verified that path too while I was in there.

* query: state:string Opaque state value used to correlate the request and carry the post-login redirect
* query: error:string Error code returned by the IdP when authentication failed
* query: error_description:string Human-readable error detail returned by the IdP
* resp-200: On success a session cookie is set and the caller is 302-redirected to the original destination; on any error the caller is 302-redirected to /login with an error query param

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c8d2bc8: corrected the annotation to resp-302 (this handler always redirects — success and error paths alike). Also grepped every handler for redirect(3xx, ...) usage and found one more spot with the same gap (GET /api/auth/oidc/{id}/initiate was missing its 302 documentation entirely) — added it there too. Since the static analyzer didn't recognize redirect() as a status-code source at all, I taught it to (so the drift gate can actually validate these two handlers going forward instead of silently ignoring them).

Comment thread src/routes/+layout.svelte Outdated
Comment on lines +26 to +28
// Same for the OpenAPI docs viewer — Swagger UI brings its own full-page chrome
const isDocsPage = $derived($page.url.pathname === '/api/docs/ui');
const noSidebar = $derived(isLoginPage || isDocsPage);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c8d2bc8: isDocsPage now matches both /api/docs/ui and /api/docs/ui/ (trailing slash).

strausmann added a commit to strausmann/dockhand that referenced this pull request Jul 31, 2026
…ect redirect status codes

Addresses Copilot review findings on PR Finsys#1341:

- Switch generate:openapi/:check (and the prebuild hook that calls them)
  from bun to npx tsx, so the build no longer depends on Bun being
  installed. Pin tsx as an exact devDependency and drop the now-unused
  Bun setup step from the CI workflow. Also fixes a latent Bun-only API
  (import.meta.dir) in the generator itself, which would have thrown
  under Node even after switching the invocation.
- Pin swagger-ui-dist to an exact version instead of a caret range, matching
  every other dependency in the file.
- Serve the OpenAPI spec from an importable module
  (src/lib/openapi.generated.json, written by the generator alongside the
  existing static/openapi.json) instead of reading static/openapi.json
  off disk at request time. The production image only copies build/, not
  static/, so the disk-read path always 404'd in the container even
  though the spec existed in the repo and in the built client assets.
- Fix two handlers where the OpenAPI annotation said resp-200 but the
  code always throws a 302 redirect (success and error paths alike);
  also teach the static analyzer to recognize redirect(3xx, ...) as a
  real status-code source, so the drift gate doesn't flag correctly
  documented redirects as stale.
- Extend the Swagger UI page's isDocsPage check to match both
  /api/docs/ui and /api/docs/ui/ (trailing slash), so the full app
  chrome doesn't render around the embedded Swagger UI.

Regenerated static/openapi.json and src/lib/openapi.generated.json;
--check still reports 0 hard failures across all 6 gates, and the spec
validates clean under both @redocly/cli lint and
@apidevtools/swagger-parser.
@strausmann

Copy link
Copy Markdown
Contributor Author

@jotka take a look for this feature

@jotka

jotka commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@jotka take a look for this feature

yes, this is nice, thanks - we were also working on the same, not to rely on the manual sync from now. Let me review, please.

@strausmann

Copy link
Copy Markdown
Contributor Author

Opened an alternative rendering with Scalar in #1342 for comparison (#814).

…hand

Adds scripts/openapi/{lib,build-spec}.ts and scripts/generate-openapi.ts,
which derive path, HTTP method, tag, and auth requirement for every
src/routes/**/+server.ts handler automatically from the SvelteKit
filesystem-routing convention and hooks.server.ts PUBLIC_PATHS. Adding a
new endpoint therefore requires zero manual spec edits for those fields.

Both authentication mechanisms are modeled as securitySchemes: the
dockhand_session cookie and the dh_-prefixed Bearer API token
(src/lib/server/api-tokens.ts), matching how hooks.server.ts actually
resolves a request's identity.

Request/response schemas and examples come from an optional, additive
`@openapi` JSDoc block on a handler (compact typed mini-DSL for
query/path params, request body, and per-status-code responses — see
scripts/openapi/lib.ts for the grammar). A handler without one stays a
fully functional generic stub.

`npm run generate:openapi` writes static/openapi.json (336 operations
across 233 routes, verified valid against both @redocly/cli lint and
@apidevtools/swagger-parser) and self-hosts the swagger-ui-dist assets
under static/swagger-ui/ (no CDN dependency). Wired into "prebuild" so
the spec is always regenerated before a production build.

`--check` runs six gates and exits non-zero on real drift: annotation
coverage (warning-only by default, `--strict-coverage` makes it a hard
gate), path-param consistency, query-param drift (annotated vs. actually
used in code), status-code drift (same), orphan JSDoc blocks that never
attached to an export, and spec validity. `--scaffold <file>` prints a
code-grounded starting annotation for every un-annotated handler in a
file (static analysis of query params via url.searchParams, status
codes via status:/error(), and request body fields via destructuring —
never written in bulk, purely a dev helper).

This replaces the hand-maintained 4,000+ line static TypeScript object
from the original OpenAPI PR, which covered ~130 of today's 336
endpoints and had no mechanism to catch drift as the API grew.
…r UI

GET /api/docs reads static/openapi.json off disk and returns it as JSON
(unauthenticated). GET /api/docs/ui renders Swagger UI against it, using
only the self-hosted assets copied into static/swagger-ui/ (no CDN).

Both routes are added to PUBLIC_PATHS in hooks.server.ts (API-level auth
bypass) and src/routes/+layout.server.ts (page-level auth bypass, same
pattern already used for /login). The root +layout.svelte now also
suppresses the sidebar/header chrome for /api/docs/ui, reusing the exact
mechanism already in place for the login page rather than introducing a
new layout-reset convention.
…ontainers endpoints

Adds a code-grounded @openapi block to 26 handlers across 17 route
files, covering the endpoints most likely to be used by API clients and
CI/CD scripts: health, login/session/logout, API tokens (create/list/
revoke), environments (list/create), the full stack lifecycle (list/
create/delete/start/stop/down/env vars), git stacks (list/create/get/
update/delete), users (list/create), and container listing.

Each annotation was written by reading the actual handler and checked
against `generate-openapi.ts --check`, which caught several real
mismatches during authoring: POST /api/users and POST /api/auth/tokens
both actually return 201 (not 200) on success, and three handlers were
missing documented error responses (404 on the tokens endpoint, 500 on
two others) that the status-code-drift gate flagged from the real
status()/error() calls in the code.

The remaining ~310 handlers stay auto-generated stubs — full path,
method, tag, and auth requirement, generic response — same as before
this commit. Annotating them further is incremental, optional, and
never blocks anything (see the coverage gate in --check).
Runs `npm run generate:openapi:check` on any push/PR touching
src/routes/**, hooks.server.ts, +layout.server.ts, or the generator
itself. Fails the build on the same hard gates as running --check
locally (path-param consistency, query/status drift, orphan JSDoc,
spec validity) while leaving annotation coverage a warning, matching
the rationale in scripts/generate-openapi.ts.
…t annotated ones

Previously the static-analysis engine (query params, status codes, body
fields) was only used by `--check` to catch drift in hand-written
`@openapi` annotations — un-annotated handlers stayed bare stubs with no
parameters, a single generic 200, and no requestBody, even though the
same analysis had already found real data for them.

build-spec.ts now builds every operation auto-base-first: path params
(type inferred from parseInt(params.x)/Number(params.x), else string),
query params found via url.searchParams.get/getAll (type inferred from
parseInt/Number on the same variable or key, or a === 'true'/!== 'false'
comparison, else string), every status code seen via status:/error(),
and for POST/PUT/PATCH a requestBody built from destructured body
fields. An `@openapi` annotation still overrides/extends this per field
by name — auto-detected query params or response codes that already
have a matching annotation entry are skipped in favor of it.

Type inference stays conservative on purpose: no pattern match means
'string', never a guessed type from the field name alone.

`--check`'s Gate 3/4 (query-param and status-code drift) are unaffected
in scope — they still only compare annotated handlers' JSDoc against
their code, since auto-derived values for un-annotated handlers can't
drift (they're recomputed from source on every run, never hand-copied).

Result on the current route tree: operations with parameters beyond
bare path segments went from a handful (only the 26 annotated handlers)
to 139/336; operations with more than one response from a handful to
318/336; operations with a requestBody from a handful to 38/336.
Add @openapi JSDoc blocks to every handler under /api/backup/* and
/api/prune/*, grounded in the actual handler code: query/path params,
request bodies (secrets shown as "***"), and only the status codes each
handler really emits. Streamed (SSE) and guard-delegated responses are
described rather than mis-attributed as literal status codes.

generate-openapi.ts --check passes with 0 hard failures (query-param and
status-code drift both clean).
…openapi blocks

Add code-grounded @openapi JSDoc blocks to every handler under
api/git, api/registry, api/registries, and api/hawser (42 handlers
across 26 route files). Summaries, path/query parameters, request
bodies, and response status codes are all read from the handler
source, so the generator's query-param and status-code drift gates
stay green. Secrets in examples are shown as "***".
…ts endpoints

Add @openapi JSDoc blocks to every handler in the stacks (compose, deploy,
env, relocate, restart, adopt, path helpers, scan, sources), volumes
(list/create/inspect/delete, browse, browse content/release, clone, export),
labels, batch, and config-sets routes.

Each block is grounded in the handler source: query params from
url.searchParams, path params from the route, request bodies from the
destructured/read fields, and responses limited to the status codes actually
emitted. Verified with generate-openapi.ts --check (no hard failures).
…d misc endpoints

Add code-grounded @openapi JSDoc blocks to the images, vulnerabilities,
system, templates, host, debug, changelog, dependencies and health
endpoints. Summaries, params, request bodies and responses are derived
from the handler source so the generator's query-param and status-code
drift gates stay green.
…activity, dashboard, logs and auto-update endpoints

Add code-grounded @openapi JSDoc blocks to every exported handler across the
observability and preferences route groups (44 handlers in 28 files). Each block
documents the summary, path/query parameters, request body and the status codes
actually emitted by the handler, verified against the source so the generator's
query-param and status-code drift gates stay green.
Add code-grounded @openapi JSDoc blocks to every handler across the
container API surface (lifecycle actions, file browser, logs/stats,
exec/shells, and batch/pending update endpoints). Summaries, query and
path parameters, request bodies, and response codes are derived from the
handler source so the generated spec matches the implementation and the
--check drift gates stay green.
…e endpoints with @openapi blocks

Add code-grounded @openapi JSDoc blocks to every handler across the
auth (LDAP/OIDC providers, provider list, auth settings), users
(user CRUD, MFA, role assignments), roles, profile (profile, avatar,
theme preferences), settings (general, scanner, theme) and license /
legal (license, privacy) API surface. Summaries, path/query parameters,
request bodies and response codes are derived from each handler's own
source so the generated spec matches the implementation and the --check
drift gates (path-param, query-param, status-code, orphan) stay green.
…and regenerate spec

Add the 404 and since/until fields the container endpoints actually emit or
read, which the earlier container annotations (written against an older route
tree) omitted, then regenerate the aggregated spec covering all batches.

- containers/[id] GET/DELETE, files GET, start/stop/restart/rename/update POST:
  document the 404 'Container not found' response
- containers/[id]/logs GET and logs/stream GET: document the since/until query
  params

Drift check: 0 hard failures. redocly lint and swagger-parser both validate.
… container and audit endpoints

Closes the last coverage gap left after the batch-annotation pass: every
handler now carries a hand-written @openapi block grounded in its own
source, bringing documented coverage to 336/336 (100%) operations.

Covers: environments/[id] CRUD plus sub-resources (icon, timezone,
disk-warning, image-prune, notifications, update-check, test,
detect-socket), the full schedules API (list, executions, settings,
stream, per-type run/toggle/delete, system job toggle), self-update
(trigger, check, progress), containers (create, check-updates trigger,
stats stream, in-place runtime update), events stream, job polling,
scanner cache cleanup, audit log, audit log users, and the Prometheus
metrics endpoint.

Response codes are limited to what each handler's own body literally
returns; codes delegated to shared auth guards are intentionally left
undocumented rather than guessed. SSE/job endpoints that support a
synchronous JSON fallback document that dual-mode behavior in prose.

Regenerated static/openapi.json; --check reports 0 hard failures across
all 6 gates, and the spec validates clean under both @redocly/cli lint
and @apidevtools/swagger-parser.
… params

Addresses independent review findings on the annotation pass:

- Drop the internal governance-rule filename from the stacks env-save
  summary; describe the DB-secret/on-disk-.env split in neutral terms
  instead.
- Correct several "env" query params from required to optional where
  the handler's own code has no literal 400 for a missing value and
  instead falls back gracefully (empty array/list, basic local info,
  or null Docker fields): stacks list, containers list, system info,
  host info, image list/delete/tag/history/export, image scan
  (get+trigger), scan-all, container stats stream, image pull, and
  image push. The last two diverge from the initial review suggestion
  after re-checking their source: neither has a literal 400 for a
  missing env, only for the image/registry body fields.
- Fix the job-line schema to match JobLine ({event?, data}), not a
  bare string array, and confirm the audit-log listing already
  documents limit/offset.

Regenerated static/openapi.json; --check still reports 0 hard failures
across all 6 gates, and the spec validates clean under both
@redocly/cli lint and @apidevtools/swagger-parser.
…ect redirect status codes

Addresses Copilot review findings on PR Finsys#1341:

- Switch generate:openapi/:check (and the prebuild hook that calls them)
  from bun to npx tsx, so the build no longer depends on Bun being
  installed. Pin tsx as an exact devDependency and drop the now-unused
  Bun setup step from the CI workflow. Also fixes a latent Bun-only API
  (import.meta.dir) in the generator itself, which would have thrown
  under Node even after switching the invocation.
- Pin swagger-ui-dist to an exact version instead of a caret range, matching
  every other dependency in the file.
- Serve the OpenAPI spec from an importable module
  (src/lib/openapi.generated.json, written by the generator alongside the
  existing static/openapi.json) instead of reading static/openapi.json
  off disk at request time. The production image only copies build/, not
  static/, so the disk-read path always 404'd in the container even
  though the spec existed in the repo and in the built client assets.
- Fix two handlers where the OpenAPI annotation said resp-200 but the
  code always throws a 302 redirect (success and error paths alike);
  also teach the static analyzer to recognize redirect(3xx, ...) as a
  real status-code source, so the drift gate doesn't flag correctly
  documented redirects as stale.
- Extend the Swagger UI page's isDocsPage check to match both
  /api/docs/ui and /api/docs/ui/ (trailing slash), so the full app
  chrome doesn't render around the embedded Swagger UI.

Regenerated static/openapi.json and src/lib/openapi.generated.json;
--check still reports 0 hard failures across all 6 gates, and the spec
validates clean under both @redocly/cli lint and
@apidevtools/swagger-parser.
…orkflow

Adds an "API documentation" section explaining that the REST API docs
(GET /api/docs, GET /api/docs/ui) are generated from the route tree and
must not be hand-edited: path/method/tags/security and much of the param
and status-code detail come from static analysis, while a @openapi JSDoc
block above each handler supplies the human-written summary, descriptions
and examples. Points contributors at npm run generate:openapi to
regenerate the spec after touching an endpoint, and at
npm run generate:openapi:check (the same check CI runs) before opening a
PR, so contributions can't silently drift the docs out of sync.
…kflow

npm ci requires a committed package-lock.json, but this repo doesn't
track one (dependencies are installed with Bun locally, and no lockfile
is checked in for either package manager). The workflow's install step
was failing outright before the generator ever ran. npm install works
fine without a lockfile and is the correct choice here.
Add @openapi JSDoc blocks for the 8 operations introduced since the last
annotation pass, grounded in the real handler code (query/path params,
request bodies, and only the status codes each handler actually emits):

- GET /api/stacks/{name}/delete-preview
- GET+POST /api/environments/{id}/remote-stacks-dir
- GET /api/registry/tag-info
- GET+PUT /api/settings/navigation
- GET /api/backup/stack-dir-listing
- GET /api/backup/stack-path

generate-openapi.ts reports 344/344 handlers annotated (100%).
…uard refactor

--check flagged 16 drift findings after the backup guards moved into shared
route-guards.ts helpers (requireBackups/guardSnapshotEnvAccess) — the 403 no
longer appears as a literal status in the per-handler code the checker scans:

- 14 endpoints: drop the now-unverifiable resp-403 line and add a
  `description:` note attributing the guard-derived 403 to the shared
  requireBackups/guardSnapshotEnvAccess helper (kept literal 403s, e.g. the
  destination/{id}/task env-scope check and the snapshots dump metadata.json
  guard, documented as-is).
- destinations/{id}/task: the documented resp-500 was stale — createJobResponse
  never emits an HTTP 500, task failures come back as a 200 with a failed
  job result. Reworded resp-200 to cover both outcomes and dropped resp-500.
- snapshots/{id}/dump: added the resp-404 the handler already emits for an
  unparseable metadata.json preview.
- DELETE /api/stacks/{name}: added the undocumented `files` query param.

generate-openapi.ts --check now reports 0 drift across all 6 gates.
@strausmann
strausmann force-pushed the feat/openapi-refresh branch from 044663e to f583cc3 Compare August 10, 2026 11:03
strausmann added a commit to strausmann/dockhand that referenced this pull request Aug 10, 2026
…ect redirect status codes

Addresses Copilot review findings on PR Finsys#1341:

- Switch generate:openapi/:check (and the prebuild hook that calls them)
  from bun to npx tsx, so the build no longer depends on Bun being
  installed. Pin tsx as an exact devDependency and drop the now-unused
  Bun setup step from the CI workflow. Also fixes a latent Bun-only API
  (import.meta.dir) in the generator itself, which would have thrown
  under Node even after switching the invocation.
- Pin swagger-ui-dist to an exact version instead of a caret range, matching
  every other dependency in the file.
- Serve the OpenAPI spec from an importable module
  (src/lib/openapi.generated.json, written by the generator alongside the
  existing static/openapi.json) instead of reading static/openapi.json
  off disk at request time. The production image only copies build/, not
  static/, so the disk-read path always 404'd in the container even
  though the spec existed in the repo and in the built client assets.
- Fix two handlers where the OpenAPI annotation said resp-200 but the
  code always throws a 302 redirect (success and error paths alike);
  also teach the static analyzer to recognize redirect(3xx, ...) as a
  real status-code source, so the drift gate doesn't flag correctly
  documented redirects as stale.
- Extend the Swagger UI page's isDocsPage check to match both
  /api/docs/ui and /api/docs/ui/ (trailing slash), so the full app
  chrome doesn't render around the embedded Swagger UI.

Regenerated static/openapi.json and src/lib/openapi.generated.json;
--check still reports 0 hard failures across all 6 gates, and the spec
validates clean under both @redocly/cli lint and
@apidevtools/swagger-parser.
Add an optional `description:` field to the @openapi annotation grammar
(alongside the existing `summary:`), mapped to OpenAPI operation.description.

Use it on GET/POST /api/git/stacks/{id}/env-files to spell out that both are
read-only discovery/inspection endpoints with no write counterpart — env is
set via PUT /api/git/stacks/{id} envFilePath or the stack env endpoints. The
short summary alone invited the wrong assumption that these accept writes.
Latent bug, exposed by the new description: key: ANNOTATION_BLOCK_RE used
[\s\S]*? on both sides of @openapi, so a handler preceded by an unrelated
file-header /** */ comment let the lazy match skip past that comment's own
*/ and swallow the CODE in between as if it were annotation body. Any
`key: value,` object-literal line in that span matching a recognized key
(summary/description/query/path/body/…) got parsed as if hand-written.

Confirmed one live casualty: GET /api/schedules/stream picked up
description: "sys.description," from an unrelated object literal 200+
lines above its real @openapi block, because `description` is a common
field name in this codebase's schedule/backup objects and just became a
recognized annotation key. Real JSDoc comments can never contain a literal
*/, so confining both lazy segments with a negated-lookahead scan
((?:(?!\*\/)[\s\S])*?) can't reject a legitimate block — audited via a
raw-span-length probe: 13 handlers had spans >2000 chars before the fix
(cross-comment matches), 0 after; --check stays green at 344/344.
@strausmann

Copy link
Copy Markdown
Contributor Author

Live side-by-side dev preview + context. This Swagger UI renderer next to the Scalar alternative (#1342), plus why the OpenAPI contract matters for downstream consumers (validating our MCP client against the generated openapi.json caught a dozen-plus real request-shape bugs) and a short renderer comparison — write-up in #814: #814 (comment)

Preview: https://dockhand-api.strausmann.cloud//swagger/ is this PR's output, /scalar/ is #1342, /openapi.json the shared spec.

@jotka

jotka commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Live side-by-side dev preview + context. This Swagger UI renderer next to the Scalar alternative (#1342), plus why the OpenAPI contract matters for downstream consumers (validating our MCP client against the generated openapi.json caught a dozen-plus real request-shape bugs) and a short renderer comparison — write-up in #814: #814 (comment)

Preview: https://dockhand-api.strausmann.cloud//swagger/ is this PR's output, /scalar/ is #1342, /openapi.json the shared spec.

this is nice! thanks @strausmann! Now we should decide which we should go with. Your recommendation?

@strausmann

Copy link
Copy Markdown
Contributor Author

Thanks @jotka! Our recommendation is Scalar (#1342).

Both are complete and drift-gated, so either merges cleanly — but for this spec Scalar has the edge on what matters for consumers: it renders the enriched descriptions and the ID cross-references (which endpoint each parameter comes from) as proper Markdown/links, and auto-generates multi-language code samples out of the box. Swagger UI's main advantage is familiarity; Scalar wins on readability, code samples, and rendering exactly the richer content the annotations now carry. (A machine consumer like our MCP reads the raw openapi.json either way, so the renderer choice is purely about the human experience — where Scalar is ahead.)

Full comparison is in the #814 write-up. We'll keep both branches in sync until you decide, and happy to help finalize whichever you pick.

@jotka

jotka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

@strausmann this can be closed please, we went with Scalar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Auto-generated OpenAPI/Swagger documentation for the REST API

3 participants