feat(docs): OpenAPI 3 spec + Swagger UI — auto-derived from routes, full endpoint coverage, CI drift-gate - #1341
strausmann wants to merge 26 commits into
Conversation
There was a problem hiding this comment.
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) andGET /api/docs/ui(Swagger UI viewer). - Add
@openapiJSDoc 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.
| "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", |
There was a problem hiding this comment.
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.
| "qrcode": "1.5.4", | ||
| "rollup": "4.60.0", | ||
| "svelte-sonner": "1.0.7", | ||
| "swagger-ui-dist": "^5.32.11", |
There was a problem hiding this comment.
Fixed in c8d2bc8: pinned to the exact version (5.32.11) instead of a caret range, matching every other dependency in the file.
| // 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); | ||
| }; |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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).
| // 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); |
There was a problem hiding this comment.
Fixed in c8d2bc8: isDocsPage now matches both /api/docs/ui and /api/docs/ui/ (trailing slash).
…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.
|
@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. |
…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.
044663e to
f583cc3
Compare
…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.
|
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 Preview: https://dockhand-api.strausmann.cloud/ — |
this is nice! thanks @strausmann! Now we should decide which we should go with. Your recommendation? |
|
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 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. |
|
@strausmann this can be closed please, we went with Scalar |
Proposed change
Adds OpenAPI 3 documentation for the REST API, served at
GET /api/docs(JSON spec) andGET /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):@openapiJSDoc block written directly above each handler. All 336 handlers are annotated.dh_user tokens).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 thesrc/restructure, and this rebuild also switches from a hand-maintained static spec to the auto-generated approach above.Validation:
@redocly/cli lintand@apidevtools/swagger-parserboth report the generated spec as valid (233 paths, 336 operations).Closes #814
Supersedes #816
Type of change