diff --git a/ROADMAP.md b/ROADMAP.md index fdc7c66..a2604e1 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -68,10 +68,12 @@ The backend exposes **~90 route registrations**; the frontend consumes roughly - ~~**React Flow edge warnings**~~ — **fixed**: `ServiceNode` now renders invisible `Handle` components (target left, source right), so inferred auto-connections attach without `#008` warnings. -- **OpenAPI drift**: `docs/api/openapi.yaml` documents 29 paths; the router - registers ~90. The generated `api-types.ts` therefore covers a fraction of - the real surface, and `api-client.ts` hand-duplicates entity types on top — - a direct violation of the "never duplicate API types" rule. +- ~~**OpenAPI drift**~~ — **resolved**: spec now covers all 153 mounted + operations (114 path items, 154 operations incl. root probes). Schemas + were corrected against the real Go structs (Service, Git*, NodeAgent, + HostMonitoring, UpgradeStatus, metrics); stale `source`/`build_config` + contract removed. `api-types.ts` regenerated; `api-client.ts` raw types + now alias generated schemas — camelCase normalizers stay by design. - **Two DB access patterns remain**: GORM is gone (agents handler ported to sqlc), but most handlers still hand-write `database/sql` — ~140 call sites across ~14 files. Porting them to `sqlc/queries/` is mechanical but large; @@ -168,9 +170,12 @@ Everything else builds on a truthful API contract and a clean tree. dependency dropped, agent queries in `sqlc/queries/agents.sql`. Remaining hand-written `database/sql` in other handlers (~140 sites) is tracked as a follow-up pass — sqlc is the target for all new code. -- [ ] Bring `docs/api/openapi.yaml` to parity with `routes.go` (all ~90 - paths), then regenerate `api-types.ts` and delete the hand-written - entity types in `api-client.ts`. +- [x] Bring `docs/api/openapi.yaml` to parity with `routes.go`: 114 paths / + 154 operations cover every mounted route (incl. `/live`, `/health`, + `/ready`, `/api/agents/*` token routes with server overrides; Proxmox + handlers are registered nowhere, intentionally undocumented). + `api-types.ts` regenerated; `api-client.ts` contract types deduped to + generated schemas — normalized view models kept. - [x] Fix auto-connection edges — `ServiceNode` lacked `Handle` components; invisible target/source handles added in `nodes.tsx`. - [x] Rerun desloppify; record score. 2026-09-17 scan (`ref/` excluded): diff --git a/app/frontend/src/features/projects/pages/ProjectsPage.tsx b/app/frontend/src/features/projects/pages/ProjectsPage.tsx index 387f796..106a679 100644 --- a/app/frontend/src/features/projects/pages/ProjectsPage.tsx +++ b/app/frontend/src/features/projects/pages/ProjectsPage.tsx @@ -22,7 +22,7 @@ const demoProjects: ProjectEntity[] = [ description: 'Sample project with mock services for UI preview.', createdAt: new Date(Date.now() - 14 * 86_400_000).toISOString(), updatedAt: new Date().toISOString(), - stats: { service_count: 5, deployment_count: 12, running_services: 5 }, + stats: { service_count: 5, deployment_count: 12, running_services: 5, last_deployment: null }, }, { id: 'project-staging', @@ -30,7 +30,7 @@ const demoProjects: ProjectEntity[] = [ description: 'Pre-production environment for testing new releases.', createdAt: new Date(Date.now() - 7 * 86_400_000).toISOString(), updatedAt: new Date(Date.now() - 2 * 86_400_000).toISOString(), - stats: { service_count: 2, deployment_count: 5, running_services: 1 }, + stats: { service_count: 2, deployment_count: 5, running_services: 1, last_deployment: null }, }, ]; diff --git a/app/frontend/src/generated/api-types.ts b/app/frontend/src/generated/api-types.ts index e719ba6..41bec54 100644 --- a/app/frontend/src/generated/api-types.ts +++ b/app/frontend/src/generated/api-types.ts @@ -13,7 +13,7 @@ export interface paths { }; /** * Health check endpoint - * @description Returns the current status of the API service + * @description Served at the root, outside /api/v1. Returns dependency status: {"checks":{"database":"ok","redis":"ok"},"service":"containr-api","status":"ok"} */ get: { parameters: { @@ -436,7 +436,7 @@ export interface paths { patch?: never; trace?: never; }; - "/projects/{project_id}/services": { + "/projects/{id}/services": { parameters: { query?: never; header?: never; @@ -453,7 +453,7 @@ export interface paths { header?: never; path: { /** @description Project ID */ - project_id: string; + id: string; }; cookie?: never; }; @@ -481,7 +481,7 @@ export interface paths { header?: never; path: { /** @description Project ID */ - project_id: string; + id: string; }; cookie?: never; }; @@ -1156,8 +1156,9 @@ export interface paths { get?: never; put?: never; /** - * Create service from template - * @description Create a new service in a project using a selected template + * Create resource from template + * @description Create a new resource in a project using a selected template. + * For `database` templates, this creates a managed database service. */ post: { parameters: { @@ -1293,7 +1294,7 @@ export interface paths { }; /** * List databases - * @description Retrieve all databases + * @description Retrieve all managed databases for the authenticated user */ get: { parameters: { @@ -1310,7 +1311,7 @@ export interface paths { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Database"][]; + "application/json": components["schemas"]["DatabaseListResponse"]; }; }; }; @@ -1318,7 +1319,7 @@ export interface paths { put?: never; /** * Create database - * @description Create a new database + * @description Create a new managed database and start provisioning */ post: { parameters: { @@ -1333,13 +1334,13 @@ export interface paths { }; }; responses: { - /** @description Database created successfully */ + /** @description Database provisioning started */ 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Database"]; + "application/json": components["schemas"]["DatabaseCreateResponse"]; }; }; }; @@ -1384,8 +1385,198 @@ export interface paths { }; }; }; - put?: never; + /** + * Update database + * @description Update mutable database metadata (name or plan) + */ + put: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Database ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateDatabaseRequest"]; + }; + }; + responses: { + /** @description Database updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; post?: never; + /** + * Delete database + * @description Delete managed database and associated runtime + */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Database ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Database deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/databases/{id}/action": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Execute database action + * @description Execute start, stop, or restart action for a managed database + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Database ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DatabaseActionRequest"]; + }; + }; + responses: { + /** @description Action accepted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DatabaseActionResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/databases/{id}/backup": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create backup + * @description Create a managed snapshot backup for a database + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Database ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Backup started */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DatabaseBackupCreateResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/databases/{id}/restore": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Restore backup + * @description Restore a managed database from a completed backup + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Database ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DatabaseRestoreRequest"]; + }; + }; + responses: { + /** @description Restore started */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; delete?: never; options?: never; head?: never; @@ -1500,6 +1691,4487 @@ export interface paths { patch?: never; trace?: never; }; + "/live": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Liveness probe + * @description Process liveness check served at the root, outside /api/v1. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Process is alive */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ready": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Readiness probe + * @description Same handler as /health — reports database and Redis status. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Service is ready */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HealthResponse"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/auth/bootstrap": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Bootstrap status + * @description Reports whether the instance already has a registered user. Drives the first-run setup gate. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Bootstrap state */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description True when no user exists yet */ + needs_setup?: boolean; + user_count?: number; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/users": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create user (manual) + * @description Manually create a user account. Used for internal/admin user creation outside the bootstrap flow. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ManualUserCreateRequest"]; + }; + }; + responses: { + /** @description User created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["User"]; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/services/{id}/metrics": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Service metrics + * @description Live resource usage for the service's containers (CPU, memory, network, block I/O via Docker stats). + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Current service metrics */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + metrics?: components["schemas"]["ServiceMetrics"]; + }; + }; + }; + /** @description Service not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/services/{id}/variables": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List service variables + * @description Environment variables for a service. Secret values are masked. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Variables retrieved */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + variables?: components["schemas"]["ServiceVariable"][]; + }; + }; + }; + /** @description Service not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + /** + * Replace service variables + * @description Replace the full variable set for a service. + */ + put: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateVariablesRequest"]; + }; + }; + responses: { + /** @description Variables updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + variables?: components["schemas"]["ServiceVariable"][]; + }; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/git/github-app/install-url": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * GitHub App install URL + * @description Returns the URL to install the Containr GitHub App, or 404 when no app is configured. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Install URL */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** Format: uri */ + install_url?: string; + }; + }; + }; + /** @description GitHub App not configured */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/git/github-app/connect": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Connect GitHub App installation + * @description Register a completed GitHub App installation as a git provider. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ConnectGitHubAppRequest"]; + }; + }; + responses: { + /** @description Provider created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GitProvider"]; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/git/providers/{providerId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete git provider + * @description Remove a git provider and its stored credentials. + */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + providerId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Provider deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + /** @description Provider not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/git/providers/{providerId}/repositories/{owner}/{repo}/branches": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List repository branches + * @description List branches for a repository through the provider API. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + providerId: string; + owner: string; + repo: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Branches retrieved */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + branches?: components["schemas"]["GitBranch"][]; + }; + }; + }; + /** @description Provider API error */ + 502: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/git/repositories/connect": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Connect repository + * @description Connect a provider repository so it can back services and webhooks. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ConnectGitRepoRequest"]; + }; + }; + responses: { + /** @description Repository connected */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GitRepository"]; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/git/repositories": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List connected repositories + * @description Repositories connected to Containr across all providers. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Connected repositories */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + repositories?: components["schemas"]["GitRepository"][]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/git/webhooks": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create webhook + * @description Register a webhook on a connected repository to trigger deployments on push. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateWebhookRequest"]; + }; + }; + responses: { + /** @description Webhook created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GitWebhook"]; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/builds/plan": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Preview build plan + * @description Resolve how a build would run (detected build type, commands) without executing it. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["BuildRequest"]; + }; + }; + responses: { + /** @description Resolved build plan */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Detected build type, commands, and resolved options */ + plan?: Record; + }; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/builds/detect": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Detect build type + * @description Auto-detect the build strategy (Dockerfile, Railpack, etc.) for a source path. + */ + get: { + parameters: { + query?: { + source_path?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Detected build type */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + build_type?: string; + detected?: boolean; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/system/upgrade/status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Upgrade status + * @description Current version, latest available image, and whether an upgrade is in progress. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Upgrade status */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["UpgradeStatus"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/system/upgrade/pull": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Pull upgrade image + * @description Pull the latest Containr image and restart the stack to self-upgrade. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Upgrade started */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/system/host": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Host monitoring + * @description Host-level telemetry: CPU, memory, disk, network, uptime, and container counts. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Host metrics */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HostMonitoring"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ws": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * WebSocket stream + * @description Upgrades to WebSocket. Streams build status, deployment events, and container log output. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description WebSocket upgrade */ + 101: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/policies": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List scaling policies */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description All scaling policies */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + policies?: components["schemas"]["ScalingPolicy"][]; + count?: number; + }; + }; + }; + }; + }; + put?: never; + /** Create or replace scaling policy */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ScalingPolicy"]; + }; + }; + responses: { + /** @description Policy stored */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + message?: string; + policy?: components["schemas"]["ScalingPolicy"]; + }; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/policies/{serviceId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get scaling policy */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Service ID */ + serviceId: components["parameters"]["ServiceIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Scaling policy */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + policy?: components["schemas"]["ScalingPolicy"]; + }; + }; + }; + /** @description Policy not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + /** Update scaling policy */ + put: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Service ID */ + serviceId: components["parameters"]["ServiceIdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ScalingPolicy"]; + }; + }; + responses: { + /** @description Policy updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + policy?: components["schemas"]["ScalingPolicy"]; + }; + }; + }; + }; + }; + post?: never; + /** Delete scaling policy */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Service ID */ + serviceId: components["parameters"]["ServiceIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Policy deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/services": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List service scaling states */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Per-service scaling state (replicas, last scale, cooldowns) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + services?: Record[]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/services/{serviceId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get service scaling state */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Service ID */ + serviceId: components["parameters"]["ServiceIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Scaling state for one service */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/services/{serviceId}/history": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Scaling history */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Service ID */ + serviceId: components["parameters"]["ServiceIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Scaling events for the service */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + history?: components["schemas"]["ScalingEvent"][]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/services/{serviceId}/scale": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Manual scale + * @description Immediately scale a service to a replica count. + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Service ID */ + serviceId: components["parameters"]["ServiceIdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + replicas: number; + reason?: string; + }; + }; + }; + responses: { + /** @description Scale event recorded */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ScalingEvent"]; + }; + }; + /** @description Invalid replica count or cooldown active */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Autoscaler status */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Whether the autoscaler is enabled plus counts */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/enable": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Enable autoscaler */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Autoscaler enabled */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/disable": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Disable autoscaler */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Autoscaler disabled */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/metrics": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Scaling engine metrics */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Internal autoscaler metrics */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/scaling/events": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Recent scaling events */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description All recent scale up/down events */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + events?: components["schemas"]["ScalingEvent"][]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** HA status */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Overall HA status (enabled, policies, active alerts) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/enable": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Enable HA management */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description HA enabled */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/disable": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Disable HA management */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description HA disabled */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/failover": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Trigger failover + * @description Manually trigger a failover evaluation across services with failover policies. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + reason?: string; + }; + }; + }; + responses: { + /** @description Failover triggered */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/failover/policies": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List failover policies */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description All failover policies */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + policies?: components["schemas"]["FailoverPolicy"][]; + }; + }; + }; + }; + }; + put?: never; + /** Create or replace failover policy */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["FailoverPolicy"]; + }; + }; + responses: { + /** @description Policy stored */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + policy?: components["schemas"]["FailoverPolicy"]; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/failover/policies/{serviceId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get failover policy */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Service ID */ + serviceId: components["parameters"]["ServiceIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Failover policy */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + policy?: components["schemas"]["FailoverPolicy"]; + }; + }; + }; + /** @description Policy not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + /** Update failover policy */ + put: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Service ID */ + serviceId: components["parameters"]["ServiceIdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["FailoverPolicy"]; + }; + }; + responses: { + /** @description Policy updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + policy?: components["schemas"]["FailoverPolicy"]; + }; + }; + }; + }; + }; + post?: never; + /** Delete failover policy */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Service ID */ + serviceId: components["parameters"]["ServiceIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Policy deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/health/checks": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List health checks */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Configured health checks */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + checks?: components["schemas"]["HealthCheck"][]; + }; + }; + }; + }; + }; + put?: never; + /** Add health check */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["HealthCheck"]; + }; + }; + responses: { + /** @description Health check created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + check?: components["schemas"]["HealthCheck"]; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/health/checks/{checkId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get health check */ + get: { + parameters: { + query?: never; + header?: never; + path: { + checkId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Health check */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + check?: components["schemas"]["HealthCheck"]; + }; + }; + }; + /** @description Check not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + /** Update health check */ + put: { + parameters: { + query?: never; + header?: never; + path: { + checkId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["HealthCheck"]; + }; + }; + responses: { + /** @description Health check updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + check?: components["schemas"]["HealthCheck"]; + }; + }; + }; + }; + }; + post?: never; + /** Delete health check */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + checkId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Health check deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/health/results": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Health check results */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Latest result per health check */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/alerts/rules": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List alert rules */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description All alert rules */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + rules?: components["schemas"]["AlertRule"][]; + }; + }; + }; + }; + }; + put?: never; + /** Add alert rule */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["AlertRule"]; + }; + }; + responses: { + /** @description Alert rule created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + rule?: components["schemas"]["AlertRule"]; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/alerts/rules/{ruleId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get alert rule */ + get: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Alert rule */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + rule?: components["schemas"]["AlertRule"]; + }; + }; + }; + /** @description Rule not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + /** Update alert rule */ + put: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["AlertRule"]; + }; + }; + responses: { + /** @description Alert rule updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + rule?: components["schemas"]["AlertRule"]; + }; + }; + }; + }; + }; + post?: never; + /** Delete alert rule */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Alert rule deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/alerts/active": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Active alerts */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Currently firing alerts */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + alerts?: Record[]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/alerts/{alertId}/resolve": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Resolve alert */ + post: { + parameters: { + query?: never; + header?: never; + path: { + alertId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Alert resolved */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/notifiers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List notifiers */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Configured alert notifiers */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + notifiers?: components["schemas"]["Notifier"][]; + }; + }; + }; + }; + }; + put?: never; + /** Add notifier */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["NotifierRequest"]; + }; + }; + responses: { + /** @description Notifier created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + notifier?: components["schemas"]["Notifier"]; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ha/notifiers/{notifierId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get notifier */ + get: { + parameters: { + query?: never; + header?: never; + path: { + notifierId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Notifier */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + notifier?: components["schemas"]["Notifier"]; + }; + }; + }; + /** @description Notifier not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + put?: never; + post?: never; + /** Delete notifier */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + notifierId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Notifier deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List node agents */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description All registered node agents */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + agents?: components["schemas"]["NodeAgent"][]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get node agent */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Agent detail */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + agent?: components["schemas"]["NodeAgent"]; + }; + }; + }; + /** @description Agent not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + /** + * Update node agent + * @description Partial update — accepts any subset of agent fields (name, status, labels, etc.). + */ + put: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": Record; + }; + }; + responses: { + /** @description Agent updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + agent?: components["schemas"]["NodeAgent"]; + }; + }; + }; + }; + }; + post?: never; + /** Deregister node agent */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Agent removed */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/{id}/containers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List agent containers */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Containers running on the agent */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + containers?: components["schemas"]["ContainerInstance"][]; + }; + }; + }; + }; + }; + put?: never; + /** Create container on agent */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateContainerRequest"]; + }; + }; + responses: { + /** @description Container created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + container?: components["schemas"]["ContainerInstance"]; + }; + }; + }; + /** @description Agent not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/{id}/containers/{containerId}/start": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Start container */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + /** @description Container ID */ + containerId: components["parameters"]["ContainerIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Container start dispatched */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/{id}/containers/{containerId}/stop": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Stop container */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + /** @description Container ID */ + containerId: components["parameters"]["ContainerIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Container stop dispatched */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/{id}/containers/{containerId}/restart": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Restart container */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + /** @description Container ID */ + containerId: components["parameters"]["ContainerIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Container restart dispatched */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/{id}/containers/{containerId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Remove container */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + /** @description Container ID */ + containerId: components["parameters"]["ContainerIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Container removal dispatched */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/{id}/metrics": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Agent metrics + * @description Resource telemetry reported by the node agent. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Agent metrics and heartbeat history */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/{id}/commands": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List agent commands */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Command history for the agent */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + commands?: components["schemas"]["AgentCommand"][]; + }; + }; + }; + }; + }; + put?: never; + /** + * Execute command on agent + * @description Queue a command for the agent to pick up on its next poll. + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ExecuteCommandRequest"]; + }; + }; + responses: { + /** @description Command queued */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + command?: components["schemas"]["AgentCommand"]; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/{id}/commands/{commandId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get command status */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Node agent ID */ + id: components["parameters"]["AgentIdParam"]; + commandId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Command status and result */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + command?: components["schemas"]["AgentCommand"]; + }; + }; + }; + /** @description Command not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/agents/register": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Register node agent + * @description Agent self-registration. Requires the agent auth token (body or X-Agent-Token header). + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["RegisterAgentRequest"]; + }; + }; + responses: { + /** @description Agent registered */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + agent?: components["schemas"]["NodeAgent"]; + }; + }; + }; + /** @description Invalid auth token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/agents/heartbeat": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Agent heartbeat + * @description Periodic heartbeat carrying resource usage and container counts. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["AgentHeartbeat"]; + }; + }; + responses: { + /** @description Heartbeat recorded */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + /** @description Invalid auth token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/agents/{id}/commands": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Poll pending commands + * @description Agent pulls its pending command queue. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Pending commands */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + commands?: components["schemas"]["AgentCommand"][]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/agents/{id}/commands/{commandId}/result": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Report command result */ + post: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + commandId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @enum {string} */ + status: "completed" | "failed"; + result?: string; + error?: string; + }; + }; + }; + responses: { + /** @description Result recorded */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + /** @description Invalid auth token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/projects/{id}/preview-environments": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List preview environments */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Preview environments for the project */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + preview_environments?: components["schemas"]["PreviewEnvironment"][]; + }; + }; + }; + }; + }; + put?: never; + /** + * Create preview environment + * @description Spin up a preview deployment for a branch or PR. + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectIdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreatePreviewEnvironmentRequest"]; + }; + }; + responses: { + /** @description Preview environment created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PreviewEnvironment"]; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/preview-environments/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get preview environment */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Preview environment */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PreviewEnvironment"]; + }; + }; + /** @description Not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + /** Update preview environment */ + put: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdatePreviewEnvironmentRequest"]; + }; + }; + responses: { + /** @description Preview environment updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PreviewEnvironment"]; + }; + }; + }; + }; + post?: never; + /** Delete preview environment */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Preview environment deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/preview-environments/{id}/promote": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Promote preview to production */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["PromotePreviewEnvironmentRequest"]; + }; + }; + responses: { + /** @description Preview promoted; returns the target deployment */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/preview-environments/cleanup-expired": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Cleanup expired previews + * @description Tear down preview environments past their TTL. Normally run by the scheduler; exposed for manual runs. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Cleanup completed */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + cleaned?: number; + }; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/security/scans": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Start security scan */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["StartSecurityScanRequest"]; + }; + }; + responses: { + /** @description Scan started */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SecurityScan"]; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/security/scans/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get security scan */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Scan status and results */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SecurityScan"]; + }; + }; + /** @description Scan not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/projects/{id}/security/history": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Project scan history */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Security scans for the project */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + scans?: components["schemas"]["SecurityScan"][]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/projects/{id}/vulnerabilities": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Project vulnerabilities */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Vulnerability findings for the project */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + vulnerabilities?: components["schemas"]["Vulnerability"][]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/vulnerabilities/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** + * Update vulnerability + * @description Mark a finding open/resolved/ignored with optional notes. + */ + put: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @enum {string} */ + status: "open" | "resolved" | "ignored"; + notes?: string; + }; + }; + }; + responses: { + /** @description Vulnerability updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + status?: string; + }; + }; + }; + }; + }; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/security/compliance/assess": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Start compliance assessment */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["StartComplianceAssessmentRequest"]; + }; + }; + responses: { + /** @description Assessment started */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/security/compliance/reports/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get compliance report */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Compliance report with per-control results */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + /** @description Report not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/security/compliance/frameworks": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List compliance frameworks */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Available compliance frameworks (SOC2, GDPR, ...) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + frameworks?: Record[]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/security/compliance/gdpr/init": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Initialize GDPR framework + * @description Seed the GDPR control set for compliance assessments. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description GDPR framework initialized */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/projects/{id}/security/metrics": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Project security metrics + * @description Aggregate score: open findings by severity, latest scan, compliance status. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Security metrics */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/projects/{id}/security/audit-logs": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Security audit logs + * @description Audit events scoped to a project (security-relevant actions). + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectIdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Audit events */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + audit_logs?: components["schemas"]["AuditLog"][]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/cron-jobs": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List cron jobs */ + get: { + parameters: { + query?: { + project_id?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Cron jobs */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + cron_jobs?: components["schemas"]["CronJob"][]; + }; + }; + }; + }; + }; + put?: never; + /** Create cron job */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateCronJobRequest"]; + }; + }; + responses: { + /** @description Cron job created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CronJob"]; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/cron-jobs/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get cron job */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Cron job */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CronJob"]; + }; + }; + /** @description Not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + /** Update cron job */ + put: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateCronJobRequest"]; + }; + }; + responses: { + /** @description Cron job updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CronJob"]; + }; + }; + }; + }; + post?: never; + /** Delete cron job */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Cron job deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageResponse"]; + }; + }; + }; + }; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/cron-jobs/{id}/executions": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Cron execution history */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Executions for the cron job */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + executions?: components["schemas"]["CronExecution"][]; + }; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/cron-jobs/{id}/trigger": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Trigger cron job now */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Execution started */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CronExecution"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/gateway/services": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List gateway services + * @description Upstream services registered for key-gated proxying. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Gateway services */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GatewayResponse"]; + }; + }; + }; + }; + put?: never; + /** Register gateway service */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["GatewayServiceRequest"]; + }; + }; + responses: { + /** @description Service registered */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GatewayResponse"]; + }; + }; + /** @description Invalid input */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Name or route prefix already registered */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/gateway/services/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** Enable/disable gateway service */ + patch: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + enabled?: boolean; + }; + }; + }; + responses: { + /** @description Service updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GatewayResponse"]; + }; + }; + }; + }; + trace?: never; + }; + "/gateway/services/{id}/validate": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Validate upstream reachability + * @description Probes the service's upstream health path and records the result. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Validation result (reachable flag + status) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GatewayResponse"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/gateway/keys": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List API keys */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description API keys (hashes never returned) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GatewayResponse"]; + }; + }; + }; + }; + put?: never; + /** + * Issue API key + * @description The plaintext key is returned exactly once in this response. + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["GatewayAPIKeyRequest"]; + }; + }; + responses: { + /** @description Key issued — `key` field holds the plaintext token */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GatewayResponse"]; + }; + }; + /** @description Invalid input or unknown plan */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/gateway/keys/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** Enable/disable API key */ + patch: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Resource ID */ + id: components["parameters"]["IdParam"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + enabled?: boolean; + }; + }; + }; + responses: { + /** @description Key updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GatewayResponse"]; + }; + }; + }; + }; + trace?: never; + }; + "/gateway/analytics/ops": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Operations analytics + * @description Error rates, incident counts, and uptime per gateway service. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Ops analytics */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GatewayResponse"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/gateway/analytics/traffic": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Traffic analytics + * @description Request volume timeseries per gateway service. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Traffic analytics */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GatewayResponse"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; } export type webhooks = Record; export interface components { @@ -1604,8 +6276,14 @@ export interface components { * @description Last update timestamp */ updated_at?: string; - /** @description Number of services in the project */ - services_count?: number; + stats?: components["schemas"]["ProjectStats"]; + }; + ProjectStats: { + service_count: number; + deployment_count: number; + running_services: number; + /** @description Timestamp of the most recent deployment */ + last_deployment: string | null; }; CreateProjectRequest: { /** @description Project name */ @@ -1634,9 +6312,15 @@ export interface components { total_pages?: number; }; Service: { - /** @description Service ID */ + /** + * Format: uuid + * @description Service ID + */ id?: string; - /** @description Project ID */ + /** + * Format: uuid + * @description Project ID + */ project_id?: string; /** @description Service name */ name?: string; @@ -1650,9 +6334,25 @@ export interface components { * @enum {string} */ status?: "running" | "stopped" | "building" | "failed"; - source?: components["schemas"]["ServiceSource"]; - build_config?: components["schemas"]["BuildConfig"]; - resources?: components["schemas"]["ResourceConfig"]; + /** @description Container image */ + image?: string; + /** @description Start command */ + command?: string; + /** + * @description Deployment environment + * @enum {string} + */ + environment?: "production" | "preview" | "development"; + /** @description Connected git repository */ + git_repo?: string; + /** @description Connected git branch */ + git_branch?: string; + /** @description Build context path */ + build_path?: string; + /** @description CPU allocation */ + cpu?: string; + /** @description Memory allocation */ + memory?: string; /** * Format: date-time * @description Service creation timestamp @@ -1665,6 +6365,11 @@ export interface components { updated_at?: string; }; CreateServiceRequest: { + /** + * Format: uuid + * @description Defaults to the project in the URL; must match when set + */ + project_id?: string; /** @description Service name */ name: string; /** @@ -1672,55 +6377,53 @@ export interface components { * @enum {string} */ type: "web" | "worker" | "database" | "cron"; - source?: components["schemas"]["ServiceSource"]; - build_config?: components["schemas"]["BuildConfig"]; - resources?: components["schemas"]["ResourceConfig"]; - }; - UpdateServiceRequest: { - /** @description Service name */ - name?: string; - build_config?: components["schemas"]["BuildConfig"]; - resources?: components["schemas"]["ResourceConfig"]; - }; - ServiceSource: { - /** - * @description Source type - * @enum {string} - */ - type?: "git" | "dockerfile" | "image"; - /** @description Git repository URL */ - repository?: string; - /** @description Git branch */ - branch?: string; - /** @description Root directory for build */ - root_directory?: string; - /** @description Dockerfile path */ - dockerfile?: string; - /** @description Docker image name */ + /** @description Container image */ image?: string; - }; - BuildConfig: { + /** @description Start command */ + command?: string; /** - * @description Build system type + * @description Deployment environment * @enum {string} */ - builder_type?: "nixpacks" | "dockerfile" | "image"; - /** @description Custom build command */ - build_command?: string; - /** @description Custom start command */ - start_command?: string; - /** @description Build environment variables */ - environment_variables?: { - [key: string]: string; - }; + environment: "production" | "preview" | "development"; + /** @description Git repository URL */ + git_repo?: string; + /** @description Git branch */ + git_branch?: string; + /** @description Build context path */ + build_path?: string; + /** @description CPU allocation */ + cpu?: string; + /** @description Memory allocation */ + memory?: string; }; - ResourceConfig: { + UpdateServiceRequest: { + /** @description Service name */ + name?: string; + /** + * @description Service type + * @enum {string} + */ + type?: "web" | "worker" | "database" | "cron"; + /** @description Container image */ + image?: string; + /** @description Start command */ + command?: string; + /** + * @description Deployment environment + * @enum {string} + */ + environment?: "production" | "preview" | "development"; + /** @description Git repository URL */ + git_repo?: string; + /** @description Git branch */ + git_branch?: string; + /** @description Build context path */ + build_path?: string; /** @description CPU allocation */ cpu?: string; /** @description Memory allocation */ memory?: string; - /** @description Storage allocation */ - storage?: string; }; Deployment: { /** @description Deployment ID */ @@ -2006,14 +6709,28 @@ export interface components { project_id: string; /** @description Name for the created service */ name: string; + /** + * @description Optional managed database plan for database templates + * @enum {string} + */ + plan?: "hobby" | "starter" | "standard" | "business"; + /** @description Optional managed database region for database templates */ + region?: string; /** @description Variable overrides for template deployment */ variables?: { [key: string]: string; }; }; DeployTemplateResponse: { - /** @description Newly created service ID */ + /** + * @description Type of resource created by template deployment + * @enum {string} + */ + resource?: "service" | "database"; + /** @description Newly created service ID (set for non-database templates) */ service_id?: string; + /** @description Newly created managed database ID (set for database templates) */ + database_id?: string; /** @description Deployment result message */ message?: string; }; @@ -2048,8 +6765,6 @@ export interface components { Database: { /** @description Database ID */ id?: string; - /** @description Project ID */ - project_id?: string; /** @description Database name */ name?: string; /** @@ -2061,13 +6776,21 @@ export interface components { * @description Database status * @enum {string} */ - status?: "running" | "stopped" | "building" | "error" | "failed"; + status?: "running" | "stopped" | "building" | "error"; /** @description Database connection URL */ connection_url?: string; /** @description Database version */ version?: string; - /** @description Database size */ - size?: string; + /** + * @description Provisioning plan + * @enum {string} + */ + plan?: "hobby" | "starter" | "standard" | "business"; + /** @description Provisioning region */ + region?: string; + metrics?: components["schemas"]["DatabaseMetrics"]; + backups?: components["schemas"]["DatabaseBackupConfig"]; + settings?: components["schemas"]["DatabaseSettings"]; /** * Format: date-time * @description Database creation timestamp @@ -2087,61 +6810,777 @@ export interface components { * @enum {string} */ type: "postgresql" | "redis" | "mysql" | "mariadb" | "mongodb" | "clickhouse" | "dragonfly"; - /** @description Database version */ - version?: string; - /** @description Database size */ - size?: string; - }; - GitProvider: { - /** @description Provider ID */ - id?: string; /** - * @description Provider type + * @description Database plan * @enum {string} */ - type?: "github" | "gitlab" | "bitbucket"; - /** @description Provider display name */ + plan: "hobby" | "starter" | "standard" | "business"; + /** @description Database region */ + region: string; + }; + UpdateDatabaseRequest: { + /** @description Updated database name */ name?: string; - /** @description Encrypted access token */ - access_token?: string; /** - * Format: date-time - * @description Provider creation timestamp + * @description Updated database plan + * @enum {string} */ + plan?: "hobby" | "starter" | "standard" | "business"; + }; + DatabaseActionRequest: { + /** + * @description Action to execute + * @enum {string} + */ + action: "start" | "stop" | "restart"; + }; + DatabaseRestoreRequest: { + /** @description Backup identifier to restore */ + backup_id: string; + }; + DatabaseCreateResponse: { + /** @description Database ID */ + id?: string; + message?: string; + /** @enum {string} */ + status?: "building"; + }; + DatabaseActionResponse: { + message?: string; + /** @enum {string} */ + status?: "running" | "stopped" | "building" | "error"; + }; + DatabaseBackupCreateResponse: { + backup_id?: string; + message?: string; + /** @enum {string} */ + status?: "in_progress"; + }; + DatabaseListResponse: { + databases?: components["schemas"]["Database"][]; + }; + DatabaseMetrics: { + cpu?: number; + memory?: number; + storage?: number; + connections?: number; + read_iops?: number; + write_iops?: number; + network_in?: number; + network_out?: number; + }; + DatabaseBackup: { + id?: string; + /** Format: date-time */ created_at?: string; + size?: string; + /** @enum {string} */ + status?: "completed" | "failed" | "in_progress"; + }; + DatabaseBackupConfig: { + enabled?: boolean; + /** Format: date-time */ + last_backup?: string; + retention?: number; + /** Format: date-time */ + next_backup?: string; + backups?: components["schemas"]["DatabaseBackup"][]; + }; + DatabaseSettings: { + max_connections?: number; + timeout?: number; + ssl?: boolean; + logging?: boolean; + }; + MessageResponse: { + message?: string; + }; + /** @description Access tokens are never serialized in responses. */ + GitProvider: { + /** @description Provider ID */ + id: string; + /** + * @description Provider type identifier + * @enum {string} + */ + name: "github" | "gitlab" | "bitbucket" | "gitea" | "github_app"; + /** @description Provider display name */ + display_name: string; + /** @description Custom API base URL (self-hosted providers) */ + api_url: string; + /** @description Webhook callback URL registered on the provider */ + webhook_url: string; + user_id: string; + /** Format: date-time */ + created_at: string; + /** Format: date-time */ + updated_at: string; }; CreateGitProviderRequest: { /** - * @description Provider type + * @description Provider type identifier * @enum {string} */ - type: "github" | "gitlab" | "bitbucket"; + name: "github" | "gitlab" | "bitbucket" | "gitea" | "github_app"; /** @description Provider display name */ - name?: string; - /** @description Access token */ + display_name: string; + /** @description Personal access token (stored encrypted, never returned) */ access_token: string; + /** @description Custom API base URL for self-hosted providers */ + api_url?: string; + }; + GitBranch: { + name: string; + protected: boolean; }; GitRepository: { /** @description Repository ID */ - id?: string; + id: string; + provider_id: string; /** @description Repository name */ - name?: string; - /** @description Repository full name */ - full_name?: string; + name: string; + /** @description Repository full name (owner/repo) */ + full_name: string; /** @description Repository description */ - description?: string; - /** @description Whether repository is private */ - private?: boolean; - /** @description Default branch */ - default_branch?: string; + description: string; /** @description Clone URL */ - clone_url?: string; - /** @description Web URL */ - web_url?: string; + clone_url: string; + webhook_url: string; + /** @description Default branch */ + default_branch: string; + /** @description Whether repository is private */ + is_private: boolean; + user_id: string; + /** Format: date-time */ + created_at: string; + /** Format: date-time */ + updated_at: string; + }; + ManualUserCreateRequest: { + /** Format: email */ + email: string; + /** Format: password */ + password: string; + name: string; + }; + ServiceVariable: { + /** Format: uuid */ + id?: string; + /** Format: uuid */ + service_id?: string; + key?: string; + /** @description Masked as ******** when is_secret is true */ + value?: string; + is_secret?: boolean; + /** Format: date-time */ + created_at?: string; + /** Format: date-time */ + updated_at?: string; + }; + VariableInput: { + key: string; + value?: string; + is_secret?: boolean; + }; + UpdateVariablesRequest: { + variables: components["schemas"]["VariableInput"][]; + }; + ConnectGitHubAppRequest: { + /** + * Format: int64 + * @description GitHub App installation ID from the install callback + */ + installation_id: number; + display_name?: string; + }; + ConnectGitRepoRequest: { + provider_id: string; + /** @description owner/repo */ + repo_full_name: string; + }; + CreateWebhookRequest: { + repo_id: string; + /** + * @example [ + * "push", + * "pull_request" + * ] + */ + events: string[]; + branch?: string; + }; + /** @description Webhook secrets are never serialized in responses. */ + GitWebhook: { + id?: string; + repo_id?: string; + provider_id?: string; + /** @description JSON-encoded array of subscribed events */ + events?: string; + active?: boolean; + /** Format: date-time */ + created_at?: string; + /** Format: date-time */ + updated_at?: string; + }; + BuildRequest: { + /** @description dockerfile | railpack | prebuilt — auto-detected when empty */ + build_type?: string; + source_path?: string; + prebuilt_image?: string; + image_name: string; + image_tag: string; + registry_url?: string; + build_command?: string; + start_command?: string; + environment?: { + [key: string]: string; + }; + build_args?: { + [key: string]: string; + }; + labels?: { + [key: string]: string; + }; + project_id?: string; + service_id?: string; + branch?: string; + commit?: string; + }; + UpgradeStatus: { + image_ref?: string; + registry?: string; + docker_available?: boolean; + installed?: boolean; + digest?: string; + /** Format: int64 */ + size?: number; + auth_configured?: boolean; + message?: string; + }; + HostMonitoring: { + hostname?: string; + os?: string; + architecture?: string; + cpu?: { + cores?: number; + }; + memory?: { + /** Format: int64 */ + total?: number; + /** Format: int64 */ + used?: number; + /** Format: int64 */ + available?: number; + usage_percent?: number; + }; + storage?: { + path?: string; + /** Format: int64 */ + total?: number; + /** Format: int64 */ + used?: number; + /** Format: int64 */ + available?: number; + usage_percent?: number; + }; + load?: { + load_1m?: number; + load_5m?: number; + load_15m?: number; + }; + /** Format: int64 */ + uptime_seconds?: number; + docker_available?: boolean; + /** @description Docker daemon details when available */ + docker?: { + containers?: number; + images?: number; + driver?: string; + server?: string; + }; + /** Format: date-time */ + collected_at?: string; + }; + ServiceInstanceMetrics: { + container_id: string; + name: string; + state: string; + cpu_percent: number; + /** Format: int64 */ + memory_usage_bytes: number; + /** Format: int64 */ + memory_limit_bytes: number; + /** Format: int64 */ + network_rx_bytes: number; + /** Format: int64 */ + network_tx_bytes: number; + /** Format: date-time */ + started_at: string; + }; + ServiceMetrics: { + service_id: string; + /** @enum {string} */ + status: "ok" | "no_containers" | "docker_unavailable"; + instances: components["schemas"]["ServiceInstanceMetrics"][]; + cpu_percent: number; + /** Format: int64 */ + memory_usage_bytes: number; + /** Format: int64 */ + memory_limit_bytes: number; + /** Format: int64 */ + network_rx_bytes: number; + /** Format: int64 */ + network_tx_bytes: number; + /** Format: date-time */ + collected_at: string; + }; + ScalingPolicy: { + service_id: string; + min_replicas: number; + max_replicas: number; + /** @description Target CPU utilization percent */ + target_cpu?: number; + /** @description Target memory utilization percent */ + target_memory?: number; + /** @description Nanoseconds (Go duration serialized as integer) */ + scale_up_cooldown?: number; + scale_down_cooldown?: number; + scale_up_step?: number; + scale_down_step?: number; + metrics?: string[]; + thresholds?: { + [key: string]: number; + }; + enabled?: boolean; + cost_optimization?: Record; + }; + ScalingEvent: { + id?: string; + service_id?: string; + from_replicas?: number; + to_replicas?: number; + reason?: string; + /** @description auto | manual */ + trigger?: string; + /** Format: date-time */ + created_at?: string; + }; + FailoverPolicy: { + service_id: string; + enabled?: boolean; + min_healthy_nodes?: number; + max_failures?: number; + /** @description Nanoseconds */ + failover_timeout?: number; + /** @description Nanoseconds */ + recovery_timeout?: number; + failover_strategy?: string; + backup_nodes?: string[]; + health_check_config?: Record; + }; + HealthCheck: { + id?: string; + service_id?: string; + node_id?: string; + /** @description http | tcp | exec */ + type?: string; + config?: Record; + /** Format: date-time */ + last_check?: string; + status?: string; + }; + AlertRule: { + id?: string; + name?: string; + description?: string; + enabled?: boolean; + /** @description metric, operator, threshold, duration */ + condition?: Record; + /** @enum {string} */ + severity?: "info" | "warning" | "critical"; + labels?: { + [key: string]: string; + }; + annotations?: { + [key: string]: string; + }; + notifiers?: string[]; + /** @description Nanoseconds */ + cooldown?: number; + }; + Notifier: { + id?: string; + /** @description webhook | slack | email | discord */ + type?: string; + config?: Record; + }; + NotifierRequest: { + id?: string; + type: string; + config: Record; + }; + NodeAgent: { + id?: string; + name?: string; + hostname?: string; + ip_address?: string; + port?: number; + /** @description online | offline | connecting | error */ + status?: string; + version?: string; + capabilities?: components["schemas"]["AgentCapabilities"]; + resources?: components["schemas"]["NodeResources"]; + metadata?: { + [key: string]: unknown; + }; + /** Format: date-time */ + last_heartbeat?: string; + /** Format: date-time */ + created_at?: string; + /** Format: date-time */ + updated_at?: string; + }; + AgentCapabilities: { + container_runtimes?: string[]; + supported_architectures?: string[]; + max_containers?: number; + storage_driver?: string; + network_plugins?: string[]; + features?: string[]; + }; + NodeResources: { + cpu?: { + cores?: number; + /** @description Allocated CPU percentage */ + allocation?: number; + /** @description Current usage percentage */ + usage?: number; + }; + memory?: { + /** Format: int64 */ + total?: number; + /** Format: int64 */ + allocated?: number; + /** Format: int64 */ + used?: number; + /** Format: int64 */ + available?: number; + }; + storage?: { + /** Format: int64 */ + total?: number; + /** Format: int64 */ + allocated?: number; + /** Format: int64 */ + used?: number; + /** Format: int64 */ + available?: number; + }; + network?: { + interfaces?: { + name?: string; + ip_address?: string; + mac_address?: string; + speed?: number; + status?: string; + }[]; + bandwidth?: { + /** + * Format: int64 + * @description Bytes per second + */ + inbound?: number; + /** + * Format: int64 + * @description Bytes per second + */ + outbound?: number; + }; + }; + }; + RegisterAgentRequest: { + name: string; + hostname: string; + ip_address: string; + port: number; + capabilities: components["schemas"]["AgentCapabilities"]; + /** @description May also be sent via the X-Agent-Token header */ + auth_token?: string; + }; + AgentHeartbeat: { + agent_id?: string; + status?: string; + resources?: components["schemas"]["NodeResources"]; + container_count?: number; + system_load?: Record; + uptime?: number; + version?: string; + }; + AgentCommand: { + id?: string; + node_agent_id?: string; + type?: string; + payload?: Record; + /** @description pending | running | completed | failed */ + status?: string; + result?: string; + error?: string; + /** Format: date-time */ + created_at?: string; + /** Format: date-time */ + completed_at?: string; + }; + ExecuteCommandRequest: { + type: string; + payload?: Record; + }; + ContainerInstance: { + id?: string; + agent_id?: string; + project_id?: string; + service_id?: string; + name?: string; + image?: string; + status?: string; + resources?: Record; + ports?: Record[]; + /** Format: date-time */ + created_at?: string; + }; + CreateContainerRequest: { + name: string; + image: string; + project_id: string; + service_id: string; + /** @description cpu/memory limits */ + resources: Record; + ports?: { + host_port?: number; + container_port?: number; + protocol?: string; + }[]; + environment?: { + [key: string]: string; + }; + volumes?: Record[]; + networks?: string[]; + restart_policy?: Record; + health_check?: Record; + }; + PreviewEnvironment: { + /** Format: uuid */ + id?: string; + /** Format: uuid */ + project_id?: string; + /** Format: uuid */ + service_id?: string; + branch_name?: string; + pr_number?: number; + /** @description Generated name, e.g. preview-{branch}-{ts} */ + environment?: string; + /** @enum {string} */ + status?: "building" | "running" | "failed" | "stopped" | "expired"; + url?: string; + /** Format: date-time */ + expires_at?: string; + /** Format: uuid */ + deployment_id?: string; + /** Format: date-time */ + created_at?: string; + /** Format: date-time */ + updated_at?: string; + }; + CreatePreviewEnvironmentRequest: { + /** Format: uuid */ + project_id?: string; + /** Format: uuid */ + service_id: string; + branch_name: string; + pr_number?: number; + ttl_hours?: number; + }; + UpdatePreviewEnvironmentRequest: { + /** @enum {string} */ + status?: "building" | "running" | "failed" | "stopped" | "expired"; + url?: string; + /** Format: date-time */ + expires_at?: string; + ttl_hours?: number; + }; + PromotePreviewEnvironmentRequest: { + /** @enum {string} */ + target_environment: "production" | "development"; + create_backup?: boolean; + }; + StartSecurityScanRequest: { + project_id: string; + service_id?: string; + /** @enum {string} */ + scan_type: "dependency" | "configuration" | "comprehensive"; + }; + SecurityScan: { + id?: string; + project_id?: string; + service_id?: string; + scan_type?: string; + /** @description pending | running | completed | failed */ + status?: string; + findings_count?: number; + /** Format: date-time */ + started_at?: string; + /** Format: date-time */ + completed_at?: string; + }; + Vulnerability: { + id?: string; + type?: string; + /** @enum {string} */ + severity?: "low" | "medium" | "high" | "critical"; + title?: string; + description?: string; + service_id?: string; + project_id?: string; + /** @enum {string} */ + status?: "open" | "resolved" | "ignored"; + /** Format: date-time */ + found_at?: string; + /** Format: date-time */ + resolved_at?: string; + }; + StartComplianceAssessmentRequest: { + project_id: string; + framework_id: string; + }; + CronJob: { + id?: string; + project_id?: string; + service_id?: string; + name?: string; + /** @description Cron expression */ + schedule?: string; + command?: string; + timezone?: string; + enabled?: boolean; + /** Format: date-time */ + last_run_at?: string; + /** Format: date-time */ + next_run_at?: string; + last_status?: string; + last_output?: string; + retention?: number; + /** Format: date-time */ + created_at?: string; + /** Format: date-time */ + updated_at?: string; + }; + CronExecution: { + id?: string; + cron_job_id?: string; + /** Format: date-time */ + started_at?: string; + /** Format: date-time */ + finished_at?: string; + status?: string; + output?: string; + error?: string; + }; + CreateCronJobRequest: { + project_id: string; + service_id: string; + name: string; + schedule: string; + command: string; + timezone?: string; + enabled?: boolean; + retention?: number; + }; + UpdateCronJobRequest: { + name?: string; + schedule?: string; + command?: string; + timezone?: string; + enabled?: boolean; + retention?: number; + }; + GatewayService: { + /** Format: uuid */ + id?: string; + name?: string; + upstream_url?: string; + route_prefix?: string; + enabled?: boolean; + rpm_limit?: number; + monthly_quota?: number; + health_path?: string; + /** Format: date-time */ + last_validated_at?: string; + last_validation_status?: string; + /** Format: date-time */ + created_at?: string; + }; + GatewayServiceRequest: { + name: string; + /** Format: uri */ + upstreamUrl: string; + routePrefix: string; + enabled?: boolean; + rpmLimit?: number; + monthlyQuota?: number; + }; + GatewayAPIKeyRequest: { + name: string; + /** + * @default free + * @enum {string} + */ + plan: "free" | "pro" | "business" | "enterprise"; + enabled?: boolean; + rpmLimit?: number; + monthlyQuota?: number; + }; + GatewayAPIKey: { + /** Format: uuid */ + id?: string; + name?: string; + plan?: string; + enabled?: boolean; + rpm_limit?: number; + monthly_quota?: number; + key_prefix?: string; + /** Format: date-time */ + created_at?: string; + }; + /** @description Standard gateway management envelope — `data` carries the payload, `error` carries {code, message, details}, `meta` carries pagination. */ + GatewayResponse: { + success?: boolean; + /** @description Endpoint-specific payload (GatewayService, GatewayAPIKey, arrays, or analytics objects) */ + data?: unknown; + error?: { + code?: string; + message?: string; + details?: unknown; + }; + meta?: { + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; }; }; responses: never; - parameters: never; + parameters: { + /** @description Resource ID */ + IdParam: string; + /** @description Project ID */ + ProjectIdParam: string; + /** @description Service ID */ + ServiceIdParam: string; + /** @description Node agent ID */ + AgentIdParam: string; + /** @description Container ID */ + ContainerIdParam: string; + }; requestBodies: never; headers: never; pathItems: never; diff --git a/app/frontend/src/lib/api-client.ts b/app/frontend/src/lib/api-client.ts index f415821..b0269b6 100644 --- a/app/frontend/src/lib/api-client.ts +++ b/app/frontend/src/lib/api-client.ts @@ -2,12 +2,7 @@ import type { components, paths } from '@/generated/api-types'; export type ServiceStatus = 'running' | 'stopped' | 'building' | 'failed' | 'unknown'; -export type ProjectStats = { - service_count: number; - deployment_count: number; - running_services: number; - last_deployment?: string; -}; +export type ProjectStats = components['schemas']['ProjectStats']; export type ProjectEntity = { id: string; @@ -148,11 +143,7 @@ export type UpdateUserProfileInput = { avatarUrl?: string; }; -export type CreateUserInput = { - name: string; - email: string; - password: string; -}; +export type CreateUserInput = components['schemas']['ManualUserCreateRequest']; export type UpgradeStatus = { imageRef: string; @@ -310,34 +301,11 @@ export type GetDeploymentLogsInput = { type?: 'all' | 'build' | 'runtime'; }; -type RawProject = components['schemas']['Project'] & { - stats?: Partial; -}; +type RawProject = components['schemas']['Project']; +type RawService = components['schemas']['Service']; +type RawUserProfile = components['schemas']['User']; -type RawService = components['schemas']['Service'] & { - image?: string; - command?: string; - environment?: string; - git_repo?: string; - git_branch?: string; - build_path?: string; - cpu?: string; - memory?: string; -}; - -type RawUserProfile = components['schemas']['User'] & { - avatar_url?: string; -}; - -type RawServiceVariable = { - id?: string; - service_id?: string; - key?: string; - value?: string; - is_secret?: boolean; - created_at?: string; - updated_at?: string; -}; +type RawServiceVariable = components['schemas']['ServiceVariable']; type RawBuildStatus = components['schemas']['BuildStatus']; type RawBuildListResponse = components['schemas']['BuildListResponse']; @@ -355,104 +323,13 @@ type RawServiceLog = components['schemas']['ServiceLogEntry']; type RawServiceLogsResponse = components['schemas']['ServiceLogsResponse']; type RawDeploymentLogsResponse = components['schemas']['DeploymentLogsResponse']; type RawRollbackDeploymentResponse = components['schemas']['RollbackDeploymentResponse']; -type RawUpgradeStatus = { - image_ref?: string; - registry?: string; - docker_available?: boolean; - installed?: boolean; - digest?: string; - size?: number; - auth_configured?: boolean; - message?: string; -}; -type RawSystemLoad = { - load_1m?: number; - load_5m?: number; - load_15m?: number; -}; -type RawHostMonitoring = { - hostname?: string; - os?: string; - architecture?: string; - cpu?: { - cores?: number; - }; - memory?: { - total?: number; - used?: number; - available?: number; - usage_percent?: number; - }; - storage?: { - path?: string; - total?: number; - used?: number; - available?: number; - usage_percent?: number; - }; - load?: RawSystemLoad; - uptime_seconds?: number; - docker_available?: boolean; - docker?: { - containers?: number; - images?: number; - driver?: string; - server?: string; - }; - collected_at?: string; -}; -type RawNodeAgent = { - id?: string; - name?: string; - hostname?: string; - ip_address?: string; - port?: number; - status?: string; - version?: string; - capabilities?: { - container_runtimes?: string[]; - supported_architectures?: string[]; - max_containers?: number; - storage_driver?: string; - network_plugins?: string[]; - features?: string[]; - }; - resources?: { - cpu?: { - cores?: number; - allocation?: number; - usage?: number; - }; - memory?: { - total?: number; - allocated?: number; - used?: number; - available?: number; - }; - storage?: { - total?: number; - allocated?: number; - used?: number; - available?: number; - }; - }; - last_heartbeat?: string; - created_at?: string; - updated_at?: string; -}; +type RawUpgradeStatus = components['schemas']['UpgradeStatus']; +type RawHostMonitoring = components['schemas']['HostMonitoring']; +type RawSystemLoad = NonNullable; +type RawNodeAgent = components['schemas']['NodeAgent']; export type CreateProjectInput = components['schemas']['CreateProjectRequest']; -export type CreateServiceInput = components['schemas']['CreateServiceRequest'] & { - environment?: 'production' | 'preview' | 'development'; - project_id?: string; - image?: string; - command?: string; - git_repo?: string; - git_branch?: string; - build_path?: string; - cpu?: string; - memory?: string; -}; +export type CreateServiceInput = components['schemas']['CreateServiceRequest']; export class ApiError extends Error { readonly status: number; @@ -543,10 +420,10 @@ function normalizeProject(project: RawProject): ProjectEntity | null { createdAt: project.created_at, updatedAt: project.updated_at, stats: { - service_count: project.stats?.service_count ?? project.services_count ?? 0, + service_count: project.stats?.service_count ?? 0, deployment_count: project.stats?.deployment_count ?? 0, running_services: project.stats?.running_services ?? 0, - last_deployment: project.stats?.last_deployment ?? undefined, + last_deployment: project.stats?.last_deployment ?? null, }, }; } @@ -1293,29 +1170,8 @@ export function serviceStatusClass(status: ServiceStatus): string { } } -export type ServiceInstanceMetrics = { - container_id: string; - name: string; - state: string; - cpu_percent: number; - memory_usage_bytes: number; - memory_limit_bytes: number; - network_rx_bytes: number; - network_tx_bytes: number; - started_at?: string; -}; - -export type ServiceMetrics = { - service_id: string; - status: 'ok' | 'no_containers' | 'docker_unavailable'; - instances: ServiceInstanceMetrics[]; - cpu_percent: number; - memory_usage_bytes: number; - memory_limit_bytes: number; - network_rx_bytes: number; - network_tx_bytes: number; - collected_at: string; -}; +export type ServiceInstanceMetrics = components['schemas']['ServiceInstanceMetrics']; +export type ServiceMetrics = components['schemas']['ServiceMetrics']; export async function getServiceMetrics(serviceId: string): Promise { const payload = await requestJson<{ metrics?: ServiceMetrics }>(`/services/${serviceId}/metrics`); @@ -1325,41 +1181,17 @@ export async function getServiceMetrics(serviceId: string): Promise { const payload = await requestJson<{ providers?: GitProviderEntity[] }>('/git/providers'); return payload.providers ?? []; } -export async function createGitProvider(input: { - name: 'github' | 'gitlab' | 'bitbucket' | 'gitea'; - display_name: string; - access_token: string; - api_url?: string; -}): Promise { +export async function createGitProvider(input: CreateGitProviderInput): Promise { const payload = await requestJson('/git/providers', { method: 'POST', body: JSON.stringify(input), diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index f8bfc42..87beba3 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -34,11 +34,13 @@ servers: paths: # Health Check /health: + servers: + - url: http://localhost:8080 get: tags: - Health summary: Health check endpoint - description: Returns the current status of the API service + description: 'Served at the root, outside /api/v1. Returns dependency status: {"checks":{"database":"ok","redis":"ok"},"service":"containr-api","status":"ok"}' responses: '200': description: Service is healthy @@ -300,7 +302,7 @@ paths: $ref: '#/components/schemas/Error' # Services - /projects/{project_id}/services: + /projects/{id}/services: get: tags: - Services @@ -309,7 +311,7 @@ paths: security: - bearerAuth: [] parameters: - - name: project_id + - name: id in: path required: true description: Project ID @@ -333,7 +335,7 @@ paths: security: - bearerAuth: [] parameters: - - name: project_id + - name: id in: path required: true description: Project ID @@ -1150,6 +1152,2571 @@ paths: items: $ref: '#/components/schemas/GitRepository' + # Top-level probes (served outside /api/v1) + /live: + servers: + - url: http://localhost:8080 + get: + tags: + - Health + summary: Liveness probe + description: Process liveness check served at the root, outside /api/v1. + responses: + '200': + description: Process is alive + + /ready: + servers: + - url: http://localhost:8080 + get: + tags: + - Health + summary: Readiness probe + description: Same handler as /health — reports database and Redis status. + responses: + '200': + description: Service is ready + content: + application/json: + schema: + $ref: '#/components/schemas/HealthResponse' + + # Authentication + /auth/bootstrap: + get: + tags: + - Authentication + summary: Bootstrap status + description: Reports whether the instance already has a registered user. Drives the first-run setup gate. + responses: + '200': + description: Bootstrap state + content: + application/json: + schema: + type: object + properties: + needs_setup: + type: boolean + description: True when no user exists yet + user_count: + type: integer + + # User Management + /users: + post: + tags: + - User + summary: Create user (manual) + description: Manually create a user account. Used for internal/admin user creation outside the bootstrap flow. + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ManualUserCreateRequest' + responses: + '201': + description: User created + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + # Services + /services/{id}/metrics: + get: + tags: + - Services + summary: Service metrics + description: Live resource usage for the service's containers (CPU, memory, network, block I/O via Docker stats). + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Current service metrics + content: + application/json: + schema: + type: object + properties: + metrics: + $ref: '#/components/schemas/ServiceMetrics' + '404': + description: Service not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /services/{id}/variables: + get: + tags: + - Services + summary: List service variables + description: Environment variables for a service. Secret values are masked. + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Variables retrieved + content: + application/json: + schema: + type: object + properties: + variables: + type: array + items: + $ref: '#/components/schemas/ServiceVariable' + '404': + description: Service not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + tags: + - Services + summary: Replace service variables + description: Replace the full variable set for a service. + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateVariablesRequest' + responses: + '200': + description: Variables updated + content: + application/json: + schema: + type: object + properties: + variables: + type: array + items: + $ref: '#/components/schemas/ServiceVariable' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + # Git integration + /git/github-app/install-url: + get: + tags: + - Git + summary: GitHub App install URL + description: Returns the URL to install the Containr GitHub App, or 404 when no app is configured. + security: + - bearerAuth: [] + responses: + '200': + description: Install URL + content: + application/json: + schema: + type: object + properties: + install_url: + type: string + format: uri + '404': + description: GitHub App not configured + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /git/github-app/connect: + post: + tags: + - Git + summary: Connect GitHub App installation + description: Register a completed GitHub App installation as a git provider. + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConnectGitHubAppRequest' + responses: + '201': + description: Provider created + content: + application/json: + schema: + $ref: '#/components/schemas/GitProvider' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /git/providers/{providerId}: + delete: + tags: + - Git + summary: Delete git provider + description: Remove a git provider and its stored credentials. + security: + - bearerAuth: [] + parameters: + - name: providerId + in: path + required: true + schema: + type: string + responses: + '200': + description: Provider deleted + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + '404': + description: Provider not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /git/providers/{providerId}/repositories/{owner}/{repo}/branches: + get: + tags: + - Git + summary: List repository branches + description: List branches for a repository through the provider API. + security: + - bearerAuth: [] + parameters: + - name: providerId + in: path + required: true + schema: + type: string + - name: owner + in: path + required: true + schema: + type: string + - name: repo + in: path + required: true + schema: + type: string + responses: + '200': + description: Branches retrieved + content: + application/json: + schema: + type: object + properties: + branches: + type: array + items: + $ref: '#/components/schemas/GitBranch' + '502': + description: Provider API error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /git/repositories/connect: + post: + tags: + - Git + summary: Connect repository + description: Connect a provider repository so it can back services and webhooks. + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConnectGitRepoRequest' + responses: + '201': + description: Repository connected + content: + application/json: + schema: + $ref: '#/components/schemas/GitRepository' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /git/repositories: + get: + tags: + - Git + summary: List connected repositories + description: Repositories connected to Containr across all providers. + security: + - bearerAuth: [] + responses: + '200': + description: Connected repositories + content: + application/json: + schema: + type: object + properties: + repositories: + type: array + items: + $ref: '#/components/schemas/GitRepository' + + /git/webhooks: + post: + tags: + - Git + summary: Create webhook + description: Register a webhook on a connected repository to trigger deployments on push. + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateWebhookRequest' + responses: + '201': + description: Webhook created + content: + application/json: + schema: + $ref: '#/components/schemas/GitWebhook' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + # Builds + /builds/plan: + post: + tags: + - Builds + summary: Preview build plan + description: Resolve how a build would run (detected build type, commands) without executing it. + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BuildRequest' + responses: + '200': + description: Resolved build plan + content: + application/json: + schema: + type: object + properties: + plan: + type: object + description: Detected build type, commands, and resolved options + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /builds/detect: + get: + tags: + - Builds + summary: Detect build type + description: Auto-detect the build strategy (Dockerfile, Railpack, etc.) for a source path. + security: + - bearerAuth: [] + parameters: + - name: source_path + in: query + schema: + type: string + responses: + '200': + description: Detected build type + content: + application/json: + schema: + type: object + properties: + build_type: + type: string + detected: + type: boolean + + # System + /system/upgrade/status: + get: + tags: + - System + summary: Upgrade status + description: Current version, latest available image, and whether an upgrade is in progress. + security: + - bearerAuth: [] + responses: + '200': + description: Upgrade status + content: + application/json: + schema: + $ref: '#/components/schemas/UpgradeStatus' + + /system/upgrade/pull: + post: + tags: + - System + summary: Pull upgrade image + description: Pull the latest Containr image and restart the stack to self-upgrade. + security: + - bearerAuth: [] + responses: + '200': + description: Upgrade started + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /system/host: + get: + tags: + - System + summary: Host monitoring + description: 'Host-level telemetry: CPU, memory, disk, network, uptime, and container counts.' + security: + - bearerAuth: [] + responses: + '200': + description: Host metrics + content: + application/json: + schema: + $ref: '#/components/schemas/HostMonitoring' + + # WebSocket + /ws: + get: + tags: + - Realtime + summary: WebSocket stream + description: Upgrades to WebSocket. Streams build status, deployment events, and container log output. + security: + - bearerAuth: [] + responses: + '101': + description: WebSocket upgrade + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + # Autoscaling + /scaling/policies: + get: + tags: + - Scaling + summary: List scaling policies + security: + - bearerAuth: [] + responses: + '200': + description: All scaling policies + content: + application/json: + schema: + type: object + properties: + policies: + type: array + items: + $ref: '#/components/schemas/ScalingPolicy' + count: + type: integer + post: + tags: + - Scaling + summary: Create or replace scaling policy + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ScalingPolicy' + responses: + '201': + description: Policy stored + content: + application/json: + schema: + type: object + properties: + message: + type: string + policy: + $ref: '#/components/schemas/ScalingPolicy' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /scaling/policies/{serviceId}: + get: + tags: + - Scaling + summary: Get scaling policy + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ServiceIdParam' + responses: + '200': + description: Scaling policy + content: + application/json: + schema: + type: object + properties: + policy: + $ref: '#/components/schemas/ScalingPolicy' + '404': + description: Policy not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + tags: + - Scaling + summary: Update scaling policy + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ServiceIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ScalingPolicy' + responses: + '200': + description: Policy updated + content: + application/json: + schema: + type: object + properties: + policy: + $ref: '#/components/schemas/ScalingPolicy' + delete: + tags: + - Scaling + summary: Delete scaling policy + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ServiceIdParam' + responses: + '200': + description: Policy deleted + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /scaling/services: + get: + tags: + - Scaling + summary: List service scaling states + security: + - bearerAuth: [] + responses: + '200': + description: Per-service scaling state (replicas, last scale, cooldowns) + content: + application/json: + schema: + type: object + properties: + services: + type: array + items: + type: object + + /scaling/services/{serviceId}: + get: + tags: + - Scaling + summary: Get service scaling state + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ServiceIdParam' + responses: + '200': + description: Scaling state for one service + content: + application/json: + schema: + type: object + + /scaling/services/{serviceId}/history: + get: + tags: + - Scaling + summary: Scaling history + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ServiceIdParam' + responses: + '200': + description: Scaling events for the service + content: + application/json: + schema: + type: object + properties: + history: + type: array + items: + $ref: '#/components/schemas/ScalingEvent' + + /scaling/services/{serviceId}/scale: + post: + tags: + - Scaling + summary: Manual scale + description: Immediately scale a service to a replica count. + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ServiceIdParam' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - replicas + properties: + replicas: + type: integer + minimum: 1 + maximum: 20 + reason: + type: string + responses: + '200': + description: Scale event recorded + content: + application/json: + schema: + $ref: '#/components/schemas/ScalingEvent' + '400': + description: Invalid replica count or cooldown active + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /scaling/status: + get: + tags: + - Scaling + summary: Autoscaler status + security: + - bearerAuth: [] + responses: + '200': + description: Whether the autoscaler is enabled plus counts + content: + application/json: + schema: + type: object + + /scaling/enable: + post: + tags: + - Scaling + summary: Enable autoscaler + security: + - bearerAuth: [] + responses: + '200': + description: Autoscaler enabled + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /scaling/disable: + post: + tags: + - Scaling + summary: Disable autoscaler + security: + - bearerAuth: [] + responses: + '200': + description: Autoscaler disabled + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /scaling/metrics: + get: + tags: + - Scaling + summary: Scaling engine metrics + security: + - bearerAuth: [] + responses: + '200': + description: Internal autoscaler metrics + content: + application/json: + schema: + type: object + + /scaling/events: + get: + tags: + - Scaling + summary: Recent scaling events + security: + - bearerAuth: [] + responses: + '200': + description: All recent scale up/down events + content: + application/json: + schema: + type: object + properties: + events: + type: array + items: + $ref: '#/components/schemas/ScalingEvent' + + # High availability + /ha/status: + get: + tags: + - HA + summary: HA status + security: + - bearerAuth: [] + responses: + '200': + description: Overall HA status (enabled, policies, active alerts) + content: + application/json: + schema: + type: object + + /ha/enable: + post: + tags: + - HA + summary: Enable HA management + security: + - bearerAuth: [] + responses: + '200': + description: HA enabled + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /ha/disable: + post: + tags: + - HA + summary: Disable HA management + security: + - bearerAuth: [] + responses: + '200': + description: HA disabled + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /ha/failover: + post: + tags: + - HA + summary: Trigger failover + description: Manually trigger a failover evaluation across services with failover policies. + security: + - bearerAuth: [] + requestBody: + content: + application/json: + schema: + type: object + properties: + reason: + type: string + responses: + '200': + description: Failover triggered + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /ha/failover/policies: + get: + tags: + - HA + summary: List failover policies + security: + - bearerAuth: [] + responses: + '200': + description: All failover policies + content: + application/json: + schema: + type: object + properties: + policies: + type: array + items: + $ref: '#/components/schemas/FailoverPolicy' + post: + tags: + - HA + summary: Create or replace failover policy + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FailoverPolicy' + responses: + '201': + description: Policy stored + content: + application/json: + schema: + type: object + properties: + policy: + $ref: '#/components/schemas/FailoverPolicy' + + /ha/failover/policies/{serviceId}: + get: + tags: + - HA + summary: Get failover policy + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ServiceIdParam' + responses: + '200': + description: Failover policy + content: + application/json: + schema: + type: object + properties: + policy: + $ref: '#/components/schemas/FailoverPolicy' + '404': + description: Policy not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + tags: + - HA + summary: Update failover policy + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ServiceIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FailoverPolicy' + responses: + '200': + description: Policy updated + content: + application/json: + schema: + type: object + properties: + policy: + $ref: '#/components/schemas/FailoverPolicy' + delete: + tags: + - HA + summary: Delete failover policy + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ServiceIdParam' + responses: + '200': + description: Policy deleted + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /ha/health/checks: + get: + tags: + - HA + summary: List health checks + security: + - bearerAuth: [] + responses: + '200': + description: Configured health checks + content: + application/json: + schema: + type: object + properties: + checks: + type: array + items: + $ref: '#/components/schemas/HealthCheck' + post: + tags: + - HA + summary: Add health check + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/HealthCheck' + responses: + '201': + description: Health check created + content: + application/json: + schema: + type: object + properties: + check: + $ref: '#/components/schemas/HealthCheck' + + /ha/health/checks/{checkId}: + get: + tags: + - HA + summary: Get health check + security: + - bearerAuth: [] + parameters: + - name: checkId + in: path + required: true + schema: + type: string + responses: + '200': + description: Health check + content: + application/json: + schema: + type: object + properties: + check: + $ref: '#/components/schemas/HealthCheck' + '404': + description: Check not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + tags: + - HA + summary: Update health check + security: + - bearerAuth: [] + parameters: + - name: checkId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/HealthCheck' + responses: + '200': + description: Health check updated + content: + application/json: + schema: + type: object + properties: + check: + $ref: '#/components/schemas/HealthCheck' + delete: + tags: + - HA + summary: Delete health check + security: + - bearerAuth: [] + parameters: + - name: checkId + in: path + required: true + schema: + type: string + responses: + '200': + description: Health check deleted + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /ha/health/results: + get: + tags: + - HA + summary: Health check results + security: + - bearerAuth: [] + responses: + '200': + description: Latest result per health check + content: + application/json: + schema: + type: object + + /ha/alerts/rules: + get: + tags: + - HA + summary: List alert rules + security: + - bearerAuth: [] + responses: + '200': + description: All alert rules + content: + application/json: + schema: + type: object + properties: + rules: + type: array + items: + $ref: '#/components/schemas/AlertRule' + post: + tags: + - HA + summary: Add alert rule + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AlertRule' + responses: + '201': + description: Alert rule created + content: + application/json: + schema: + type: object + properties: + rule: + $ref: '#/components/schemas/AlertRule' + + /ha/alerts/rules/{ruleId}: + get: + tags: + - HA + summary: Get alert rule + security: + - bearerAuth: [] + parameters: + - name: ruleId + in: path + required: true + schema: + type: string + responses: + '200': + description: Alert rule + content: + application/json: + schema: + type: object + properties: + rule: + $ref: '#/components/schemas/AlertRule' + '404': + description: Rule not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + tags: + - HA + summary: Update alert rule + security: + - bearerAuth: [] + parameters: + - name: ruleId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AlertRule' + responses: + '200': + description: Alert rule updated + content: + application/json: + schema: + type: object + properties: + rule: + $ref: '#/components/schemas/AlertRule' + delete: + tags: + - HA + summary: Delete alert rule + security: + - bearerAuth: [] + parameters: + - name: ruleId + in: path + required: true + schema: + type: string + responses: + '200': + description: Alert rule deleted + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /ha/alerts/active: + get: + tags: + - HA + summary: Active alerts + security: + - bearerAuth: [] + responses: + '200': + description: Currently firing alerts + content: + application/json: + schema: + type: object + properties: + alerts: + type: array + items: + type: object + + /ha/alerts/{alertId}/resolve: + post: + tags: + - HA + summary: Resolve alert + security: + - bearerAuth: [] + parameters: + - name: alertId + in: path + required: true + schema: + type: string + responses: + '200': + description: Alert resolved + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /ha/notifiers: + get: + tags: + - HA + summary: List notifiers + security: + - bearerAuth: [] + responses: + '200': + description: Configured alert notifiers + content: + application/json: + schema: + type: object + properties: + notifiers: + type: array + items: + $ref: '#/components/schemas/Notifier' + post: + tags: + - HA + summary: Add notifier + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NotifierRequest' + responses: + '201': + description: Notifier created + content: + application/json: + schema: + type: object + properties: + notifier: + $ref: '#/components/schemas/Notifier' + + /ha/notifiers/{notifierId}: + get: + tags: + - HA + summary: Get notifier + security: + - bearerAuth: [] + parameters: + - name: notifierId + in: path + required: true + schema: + type: string + responses: + '200': + description: Notifier + content: + application/json: + schema: + type: object + properties: + notifier: + $ref: '#/components/schemas/Notifier' + '404': + description: Notifier not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + tags: + - HA + summary: Delete notifier + security: + - bearerAuth: [] + parameters: + - name: notifierId + in: path + required: true + schema: + type: string + responses: + '200': + description: Notifier deleted + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + # Node agents — management (JWT-authenticated) + /agents: + get: + tags: + - Agents + summary: List node agents + security: + - bearerAuth: [] + responses: + '200': + description: All registered node agents + content: + application/json: + schema: + type: object + properties: + agents: + type: array + items: + $ref: '#/components/schemas/NodeAgent' + + /agents/{id}: + get: + tags: + - Agents + summary: Get node agent + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + responses: + '200': + description: Agent detail + content: + application/json: + schema: + type: object + properties: + agent: + $ref: '#/components/schemas/NodeAgent' + '404': + description: Agent not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + tags: + - Agents + summary: Update node agent + description: Partial update — accepts any subset of agent fields (name, status, labels, etc.). + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + requestBody: + required: true + content: + application/json: + schema: + type: object + description: Subset of NodeAgent fields to update + responses: + '200': + description: Agent updated + content: + application/json: + schema: + type: object + properties: + agent: + $ref: '#/components/schemas/NodeAgent' + delete: + tags: + - Agents + summary: Deregister node agent + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + responses: + '200': + description: Agent removed + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /agents/{id}/containers: + get: + tags: + - Agents + summary: List agent containers + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + responses: + '200': + description: Containers running on the agent + content: + application/json: + schema: + type: object + properties: + containers: + type: array + items: + $ref: '#/components/schemas/ContainerInstance' + post: + tags: + - Agents + summary: Create container on agent + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateContainerRequest' + responses: + '201': + description: Container created + content: + application/json: + schema: + type: object + properties: + container: + $ref: '#/components/schemas/ContainerInstance' + '404': + description: Agent not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /agents/{id}/containers/{containerId}/start: + post: + tags: + - Agents + summary: Start container + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + - $ref: '#/components/parameters/ContainerIdParam' + responses: + '200': + description: Container start dispatched + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /agents/{id}/containers/{containerId}/stop: + post: + tags: + - Agents + summary: Stop container + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + - $ref: '#/components/parameters/ContainerIdParam' + responses: + '200': + description: Container stop dispatched + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /agents/{id}/containers/{containerId}/restart: + post: + tags: + - Agents + summary: Restart container + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + - $ref: '#/components/parameters/ContainerIdParam' + responses: + '200': + description: Container restart dispatched + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /agents/{id}/containers/{containerId}: + delete: + tags: + - Agents + summary: Remove container + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + - $ref: '#/components/parameters/ContainerIdParam' + responses: + '200': + description: Container removal dispatched + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /agents/{id}/metrics: + get: + tags: + - Agents + summary: Agent metrics + description: Resource telemetry reported by the node agent. + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + responses: + '200': + description: Agent metrics and heartbeat history + content: + application/json: + schema: + type: object + + /agents/{id}/commands: + get: + tags: + - Agents + summary: List agent commands + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + responses: + '200': + description: Command history for the agent + content: + application/json: + schema: + type: object + properties: + commands: + type: array + items: + $ref: '#/components/schemas/AgentCommand' + post: + tags: + - Agents + summary: Execute command on agent + description: Queue a command for the agent to pick up on its next poll. + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ExecuteCommandRequest' + responses: + '201': + description: Command queued + content: + application/json: + schema: + type: object + properties: + command: + $ref: '#/components/schemas/AgentCommand' + + /agents/{id}/commands/{commandId}: + get: + tags: + - Agents + summary: Get command status + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/AgentIdParam' + - name: commandId + in: path + required: true + schema: + type: string + responses: + '200': + description: Command status and result + content: + application/json: + schema: + type: object + properties: + command: + $ref: '#/components/schemas/AgentCommand' + '404': + description: Command not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + # Node agents — ingestion (token-authenticated, served under /api not /api/v1) + /api/agents/register: + servers: + - url: http://localhost:8080 + post: + tags: + - Agents + summary: Register node agent + description: Agent self-registration. Requires the agent auth token (body or X-Agent-Token header). + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RegisterAgentRequest' + responses: + '201': + description: Agent registered + content: + application/json: + schema: + type: object + properties: + agent: + $ref: '#/components/schemas/NodeAgent' + '401': + description: Invalid auth token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /api/agents/heartbeat: + servers: + - url: http://localhost:8080 + post: + tags: + - Agents + summary: Agent heartbeat + description: Periodic heartbeat carrying resource usage and container counts. + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AgentHeartbeat' + responses: + '200': + description: Heartbeat recorded + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + '401': + description: Invalid auth token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /api/agents/{id}/commands: + servers: + - url: http://localhost:8080 + get: + tags: + - Agents + summary: Poll pending commands + description: Agent pulls its pending command queue. + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: Pending commands + content: + application/json: + schema: + type: object + properties: + commands: + type: array + items: + $ref: '#/components/schemas/AgentCommand' + + /api/agents/{id}/commands/{commandId}/result: + servers: + - url: http://localhost:8080 + post: + tags: + - Agents + summary: Report command result + parameters: + - name: id + in: path + required: true + schema: + type: string + - name: commandId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - status + properties: + status: + type: string + enum: [completed, failed] + result: + type: string + error: + type: string + responses: + '200': + description: Result recorded + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + '401': + description: Invalid auth token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + # Preview environments + /projects/{id}/preview-environments: + get: + tags: + - Preview Environments + summary: List preview environments + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ProjectIdParam' + responses: + '200': + description: Preview environments for the project + content: + application/json: + schema: + type: object + properties: + preview_environments: + type: array + items: + $ref: '#/components/schemas/PreviewEnvironment' + post: + tags: + - Preview Environments + summary: Create preview environment + description: Spin up a preview deployment for a branch or PR. + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ProjectIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreatePreviewEnvironmentRequest' + responses: + '201': + description: Preview environment created + content: + application/json: + schema: + $ref: '#/components/schemas/PreviewEnvironment' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /preview-environments/{id}: + get: + tags: + - Preview Environments + summary: Get preview environment + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + responses: + '200': + description: Preview environment + content: + application/json: + schema: + $ref: '#/components/schemas/PreviewEnvironment' + '404': + description: Not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + tags: + - Preview Environments + summary: Update preview environment + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdatePreviewEnvironmentRequest' + responses: + '200': + description: Preview environment updated + content: + application/json: + schema: + $ref: '#/components/schemas/PreviewEnvironment' + delete: + tags: + - Preview Environments + summary: Delete preview environment + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + responses: + '200': + description: Preview environment deleted + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /preview-environments/{id}/promote: + post: + tags: + - Preview Environments + summary: Promote preview to production + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PromotePreviewEnvironmentRequest' + responses: + '200': + description: Preview promoted; returns the target deployment + content: + application/json: + schema: + type: object + + /preview-environments/cleanup-expired: + post: + tags: + - Preview Environments + summary: Cleanup expired previews + description: Tear down preview environments past their TTL. Normally run by the scheduler; exposed for manual runs. + security: + - bearerAuth: [] + responses: + '200': + description: Cleanup completed + content: + application/json: + schema: + type: object + properties: + cleaned: + type: integer + + # Security + /security/scans: + post: + tags: + - Security + summary: Start security scan + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/StartSecurityScanRequest' + responses: + '201': + description: Scan started + content: + application/json: + schema: + $ref: '#/components/schemas/SecurityScan' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /security/scans/{id}: + get: + tags: + - Security + summary: Get security scan + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + responses: + '200': + description: Scan status and results + content: + application/json: + schema: + $ref: '#/components/schemas/SecurityScan' + '404': + description: Scan not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /projects/{id}/security/history: + get: + tags: + - Security + summary: Project scan history + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ProjectIdParam' + responses: + '200': + description: Security scans for the project + content: + application/json: + schema: + type: object + properties: + scans: + type: array + items: + $ref: '#/components/schemas/SecurityScan' + + /projects/{id}/vulnerabilities: + get: + tags: + - Security + summary: Project vulnerabilities + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ProjectIdParam' + responses: + '200': + description: Vulnerability findings for the project + content: + application/json: + schema: + type: object + properties: + vulnerabilities: + type: array + items: + $ref: '#/components/schemas/Vulnerability' + + /vulnerabilities/{id}: + put: + tags: + - Security + summary: Update vulnerability + description: Mark a finding open/resolved/ignored with optional notes. + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - status + properties: + status: + type: string + enum: [open, resolved, ignored] + notes: + type: string + responses: + '200': + description: Vulnerability updated + content: + application/json: + schema: + type: object + properties: + status: + type: string + + /security/compliance/assess: + post: + tags: + - Security + summary: Start compliance assessment + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/StartComplianceAssessmentRequest' + responses: + '201': + description: Assessment started + content: + application/json: + schema: + type: object + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /security/compliance/reports/{id}: + get: + tags: + - Security + summary: Get compliance report + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + responses: + '200': + description: Compliance report with per-control results + content: + application/json: + schema: + type: object + '404': + description: Report not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /security/compliance/frameworks: + get: + tags: + - Security + summary: List compliance frameworks + security: + - bearerAuth: [] + responses: + '200': + description: Available compliance frameworks (SOC2, GDPR, ...) + content: + application/json: + schema: + type: object + properties: + frameworks: + type: array + items: + type: object + + /security/compliance/gdpr/init: + post: + tags: + - Security + summary: Initialize GDPR framework + description: Seed the GDPR control set for compliance assessments. + security: + - bearerAuth: [] + responses: + '200': + description: GDPR framework initialized + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /projects/{id}/security/metrics: + get: + tags: + - Security + summary: Project security metrics + description: 'Aggregate score: open findings by severity, latest scan, compliance status.' + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ProjectIdParam' + responses: + '200': + description: Security metrics + content: + application/json: + schema: + type: object + + /projects/{id}/security/audit-logs: + get: + tags: + - Security + summary: Security audit logs + description: Audit events scoped to a project (security-relevant actions). + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/ProjectIdParam' + responses: + '200': + description: Audit events + content: + application/json: + schema: + type: object + properties: + audit_logs: + type: array + items: + $ref: '#/components/schemas/AuditLog' + + # Cron jobs + /cron-jobs: + get: + tags: + - Cron + summary: List cron jobs + parameters: + - name: project_id + in: query + schema: + type: string + format: uuid + security: + - bearerAuth: [] + responses: + '200': + description: Cron jobs + content: + application/json: + schema: + type: object + properties: + cron_jobs: + type: array + items: + $ref: '#/components/schemas/CronJob' + post: + tags: + - Cron + summary: Create cron job + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateCronJobRequest' + responses: + '201': + description: Cron job created + content: + application/json: + schema: + $ref: '#/components/schemas/CronJob' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /cron-jobs/{id}: + get: + tags: + - Cron + summary: Get cron job + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + responses: + '200': + description: Cron job + content: + application/json: + schema: + $ref: '#/components/schemas/CronJob' + '404': + description: Not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + tags: + - Cron + summary: Update cron job + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateCronJobRequest' + responses: + '200': + description: Cron job updated + content: + application/json: + schema: + $ref: '#/components/schemas/CronJob' + delete: + tags: + - Cron + summary: Delete cron job + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + responses: + '200': + description: Cron job deleted + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResponse' + + /cron-jobs/{id}/executions: + get: + tags: + - Cron + summary: Cron execution history + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + responses: + '200': + description: Executions for the cron job + content: + application/json: + schema: + type: object + properties: + executions: + type: array + items: + $ref: '#/components/schemas/CronExecution' + + /cron-jobs/{id}/trigger: + post: + tags: + - Cron + summary: Trigger cron job now + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + responses: + '200': + description: Execution started + content: + application/json: + schema: + $ref: '#/components/schemas/CronExecution' + + # API Gateway (merged APwhy management surface) + /gateway/services: + get: + tags: + - Gateway + summary: List gateway services + description: Upstream services registered for key-gated proxying. + security: + - bearerAuth: [] + responses: + '200': + description: Gateway services + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayResponse' + post: + tags: + - Gateway + summary: Register gateway service + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayServiceRequest' + responses: + '201': + description: Service registered + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayResponse' + '400': + description: Invalid input + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: Name or route prefix already registered + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /gateway/services/{id}: + patch: + tags: + - Gateway + summary: Enable/disable gateway service + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + responses: + '200': + description: Service updated + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayResponse' + + /gateway/services/{id}/validate: + get: + tags: + - Gateway + summary: Validate upstream reachability + description: Probes the service's upstream health path and records the result. + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + responses: + '200': + description: Validation result (reachable flag + status) + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayResponse' + + /gateway/keys: + get: + tags: + - Gateway + summary: List API keys + security: + - bearerAuth: [] + responses: + '200': + description: API keys (hashes never returned) + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayResponse' + post: + tags: + - Gateway + summary: Issue API key + description: The plaintext key is returned exactly once in this response. + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayAPIKeyRequest' + responses: + '201': + description: Key issued — `key` field holds the plaintext token + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayResponse' + '400': + description: Invalid input or unknown plan + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + /gateway/keys/{id}: + patch: + tags: + - Gateway + summary: Enable/disable API key + security: + - bearerAuth: [] + parameters: + - $ref: '#/components/parameters/IdParam' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + responses: + '200': + description: Key updated + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayResponse' + + /gateway/analytics/ops: + get: + tags: + - Gateway + summary: Operations analytics + description: Error rates, incident counts, and uptime per gateway service. + security: + - bearerAuth: [] + responses: + '200': + description: Ops analytics + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayResponse' + + /gateway/analytics/traffic: + get: + tags: + - Gateway + summary: Traffic analytics + description: Request volume timeseries per gateway service. + security: + - bearerAuth: [] + responses: + '200': + description: Traffic analytics + content: + application/json: + schema: + $ref: '#/components/schemas/GatewayResponse' + components: securitySchemes: bearerAuth: @@ -1289,9 +3856,27 @@ components: type: string format: date-time description: Last update timestamp - services_count: + stats: + $ref: '#/components/schemas/ProjectStats' + + ProjectStats: + type: object + required: + - service_count + - deployment_count + - running_services + - last_deployment + properties: + service_count: type: integer - description: Number of services in the project + deployment_count: + type: integer + running_services: + type: integer + last_deployment: + type: string + nullable: true + description: Timestamp of the most recent deployment CreateProjectRequest: type: object @@ -1346,9 +3931,11 @@ components: properties: id: type: string + format: uuid description: Service ID project_id: type: string + format: uuid description: Project ID name: type: string @@ -1361,12 +3948,31 @@ components: type: string enum: [running, stopped, building, failed] description: Service status - source: - $ref: '#/components/schemas/ServiceSource' - build_config: - $ref: '#/components/schemas/BuildConfig' - resources: - $ref: '#/components/schemas/ResourceConfig' + image: + type: string + description: Container image + command: + type: string + description: Start command + environment: + type: string + enum: [production, preview, development] + description: Deployment environment + git_repo: + type: string + description: Connected git repository + git_branch: + type: string + description: Connected git branch + build_path: + type: string + description: Build context path + cpu: + type: string + description: CPU allocation + memory: + type: string + description: Memory allocation created_at: type: string format: date-time @@ -1381,6 +3987,47 @@ components: required: - name - type + - environment + properties: + project_id: + type: string + format: uuid + description: Defaults to the project in the URL; must match when set + name: + type: string + description: Service name + type: + type: string + enum: [web, worker, database, cron] + description: Service type + image: + type: string + description: Container image + command: + type: string + description: Start command + environment: + type: string + enum: [production, preview, development] + description: Deployment environment + git_repo: + type: string + description: Git repository URL + git_branch: + type: string + description: Git branch + build_path: + type: string + description: Build context path + cpu: + type: string + description: CPU allocation + memory: + type: string + description: Memory allocation + + UpdateServiceRequest: + type: object properties: name: type: string @@ -1389,78 +4036,31 @@ components: type: string enum: [web, worker, database, cron] description: Service type - source: - $ref: '#/components/schemas/ServiceSource' - build_config: - $ref: '#/components/schemas/BuildConfig' - resources: - $ref: '#/components/schemas/ResourceConfig' - - UpdateServiceRequest: - type: object - properties: - name: - type: string - description: Service name - build_config: - $ref: '#/components/schemas/BuildConfig' - resources: - $ref: '#/components/schemas/ResourceConfig' - - ServiceSource: - type: object - properties: - type: - type: string - enum: [git, dockerfile, image] - description: Source type - repository: - type: string - description: Git repository URL - branch: - type: string - description: Git branch - root_directory: - type: string - description: Root directory for build - dockerfile: - type: string - description: Dockerfile path image: type: string - description: Docker image name - - BuildConfig: - type: object - properties: - builder_type: + description: Container image + command: type: string - enum: [nixpacks, dockerfile, image] - description: Build system type - build_command: + description: Start command + environment: type: string - description: Custom build command - start_command: + enum: [production, preview, development] + description: Deployment environment + git_repo: type: string - description: Custom start command - environment_variables: - type: object - additionalProperties: - type: string - description: Build environment variables - - ResourceConfig: - type: object - properties: + description: Git repository URL + git_branch: + type: string + description: Git branch + build_path: + type: string + description: Build context path cpu: type: string description: CPU allocation memory: type: string description: Memory allocation - storage: - type: string - description: Storage allocation Deployment: type: object @@ -2151,69 +4751,1347 @@ components: GitProvider: type: object + required: + - id + - name + - display_name + - api_url + - webhook_url + - user_id + - created_at + - updated_at properties: id: type: string description: Provider ID - type: - type: string - enum: [github, gitlab, bitbucket] - description: Provider type name: type: string + enum: [github, gitlab, bitbucket, gitea, github_app] + description: Provider type identifier + display_name: + type: string description: Provider display name - access_token: + api_url: + type: string + description: Custom API base URL (self-hosted providers) + webhook_url: + type: string + description: Webhook callback URL registered on the provider + user_id: type: string - description: Encrypted access token created_at: type: string format: date-time - description: Provider creation timestamp + updated_at: + type: string + format: date-time + description: Access tokens are never serialized in responses. CreateGitProviderRequest: type: object required: - - type + - name + - display_name - access_token properties: - type: - type: string - enum: [github, gitlab, bitbucket] - description: Provider type name: + type: string + enum: [github, gitlab, bitbucket, gitea, github_app] + description: Provider type identifier + display_name: type: string description: Provider display name access_token: type: string - description: Access token + description: Personal access token (stored encrypted, never returned) + api_url: + type: string + description: Custom API base URL for self-hosted providers + + GitBranch: + type: object + required: + - name + - protected + properties: + name: + type: string + protected: + type: boolean GitRepository: type: object + required: + - id + - provider_id + - name + - full_name + - description + - clone_url + - webhook_url + - default_branch + - is_private + - user_id + - created_at + - updated_at properties: id: type: string description: Repository ID + provider_id: + type: string name: type: string description: Repository name full_name: type: string - description: Repository full name + description: Repository full name (owner/repo) description: type: string description: Repository description - private: - type: boolean - description: Whether repository is private - default_branch: - type: string - description: Default branch clone_url: type: string description: Clone URL - web_url: + webhook_url: type: string - description: Web URL + default_branch: + type: string + description: Default branch + is_private: + type: boolean + description: Whether repository is private + user_id: + type: string + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + ManualUserCreateRequest: + type: object + required: + - email + - password + - name + properties: + email: + type: string + format: email + password: + type: string + format: password + minLength: 8 + maxLength: 128 + name: + type: string + minLength: 2 + maxLength: 255 + + ServiceVariable: + type: object + properties: + id: + type: string + format: uuid + service_id: + type: string + format: uuid + key: + type: string + value: + type: string + description: Masked as ******** when is_secret is true + is_secret: + type: boolean + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + VariableInput: + type: object + required: + - key + properties: + key: + type: string + value: + type: string + is_secret: + type: boolean + + UpdateVariablesRequest: + type: object + required: + - variables + properties: + variables: + type: array + items: + $ref: '#/components/schemas/VariableInput' + + ConnectGitHubAppRequest: + type: object + required: + - installation_id + properties: + installation_id: + type: integer + format: int64 + description: GitHub App installation ID from the install callback + display_name: + type: string + + ConnectGitRepoRequest: + type: object + required: + - provider_id + - repo_full_name + properties: + provider_id: + type: string + repo_full_name: + type: string + description: owner/repo + + CreateWebhookRequest: + type: object + required: + - repo_id + - events + properties: + repo_id: + type: string + events: + type: array + items: + type: string + example: [push, pull_request] + branch: + type: string + + GitWebhook: + type: object + properties: + id: + type: string + repo_id: + type: string + provider_id: + type: string + events: + type: string + description: JSON-encoded array of subscribed events + active: + type: boolean + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + description: Webhook secrets are never serialized in responses. + + BuildRequest: + type: object + required: + - image_name + - image_tag + properties: + build_type: + type: string + description: dockerfile | railpack | prebuilt — auto-detected when empty + source_path: + type: string + prebuilt_image: + type: string + image_name: + type: string + image_tag: + type: string + registry_url: + type: string + build_command: + type: string + start_command: + type: string + environment: + type: object + additionalProperties: + type: string + build_args: + type: object + additionalProperties: + type: string + labels: + type: object + additionalProperties: + type: string + project_id: + type: string + service_id: + type: string + branch: + type: string + commit: + type: string + + UpgradeStatus: + type: object + properties: + image_ref: + type: string + registry: + type: string + docker_available: + type: boolean + installed: + type: boolean + digest: + type: string + size: + type: integer + format: int64 + auth_configured: + type: boolean + message: + type: string + + HostMonitoring: + type: object + properties: + hostname: + type: string + os: + type: string + architecture: + type: string + cpu: + type: object + properties: + cores: + type: integer + memory: + type: object + properties: + total: + type: integer + format: int64 + used: + type: integer + format: int64 + available: + type: integer + format: int64 + usage_percent: + type: number + storage: + type: object + properties: + path: + type: string + total: + type: integer + format: int64 + used: + type: integer + format: int64 + available: + type: integer + format: int64 + usage_percent: + type: number + load: + type: object + properties: + load_1m: + type: number + load_5m: + type: number + load_15m: + type: number + uptime_seconds: + type: integer + format: int64 + docker_available: + type: boolean + docker: + type: object + description: Docker daemon details when available + properties: + containers: + type: integer + images: + type: integer + driver: + type: string + server: + type: string + collected_at: + type: string + format: date-time + + ServiceInstanceMetrics: + type: object + required: + - container_id + - name + - state + - cpu_percent + - memory_usage_bytes + - memory_limit_bytes + - network_rx_bytes + - network_tx_bytes + - started_at + properties: + container_id: + type: string + name: + type: string + state: + type: string + cpu_percent: + type: number + memory_usage_bytes: + type: integer + format: int64 + memory_limit_bytes: + type: integer + format: int64 + network_rx_bytes: + type: integer + format: int64 + network_tx_bytes: + type: integer + format: int64 + started_at: + type: string + format: date-time + + ServiceMetrics: + type: object + required: + - service_id + - status + - instances + - cpu_percent + - memory_usage_bytes + - memory_limit_bytes + - network_rx_bytes + - network_tx_bytes + - collected_at + properties: + service_id: + type: string + status: + type: string + enum: [ok, no_containers, docker_unavailable] + instances: + type: array + items: + $ref: '#/components/schemas/ServiceInstanceMetrics' + cpu_percent: + type: number + memory_usage_bytes: + type: integer + format: int64 + memory_limit_bytes: + type: integer + format: int64 + network_rx_bytes: + type: integer + format: int64 + network_tx_bytes: + type: integer + format: int64 + collected_at: + type: string + format: date-time + + ScalingPolicy: + type: object + required: + - service_id + - min_replicas + - max_replicas + properties: + service_id: + type: string + min_replicas: + type: integer + minimum: 1 + max_replicas: + type: integer + minimum: 1 + target_cpu: + type: number + description: Target CPU utilization percent + target_memory: + type: number + description: Target memory utilization percent + scale_up_cooldown: + type: integer + description: Nanoseconds (Go duration serialized as integer) + scale_down_cooldown: + type: integer + scale_up_step: + type: integer + scale_down_step: + type: integer + metrics: + type: array + items: + type: string + thresholds: + type: object + additionalProperties: + type: number + enabled: + type: boolean + cost_optimization: + type: object + + ScalingEvent: + type: object + properties: + id: + type: string + service_id: + type: string + from_replicas: + type: integer + to_replicas: + type: integer + reason: + type: string + trigger: + type: string + description: auto | manual + created_at: + type: string + format: date-time + + FailoverPolicy: + type: object + required: + - service_id + properties: + service_id: + type: string + enabled: + type: boolean + min_healthy_nodes: + type: integer + max_failures: + type: integer + failover_timeout: + type: integer + description: Nanoseconds + recovery_timeout: + type: integer + description: Nanoseconds + failover_strategy: + type: string + backup_nodes: + type: array + items: + type: string + health_check_config: + type: object + + HealthCheck: + type: object + properties: + id: + type: string + service_id: + type: string + node_id: + type: string + type: + type: string + description: http | tcp | exec + config: + type: object + last_check: + type: string + format: date-time + status: + type: string + + AlertRule: + type: object + properties: + id: + type: string + name: + type: string + description: + type: string + enabled: + type: boolean + condition: + type: object + description: metric, operator, threshold, duration + severity: + type: string + enum: [info, warning, critical] + labels: + type: object + additionalProperties: + type: string + annotations: + type: object + additionalProperties: + type: string + notifiers: + type: array + items: + type: string + cooldown: + type: integer + description: Nanoseconds + + Notifier: + type: object + properties: + id: + type: string + type: + type: string + description: webhook | slack | email | discord + config: + type: object + + NotifierRequest: + type: object + required: + - type + - config + properties: + id: + type: string + type: + type: string + config: + type: object + + NodeAgent: + type: object + properties: + id: + type: string + name: + type: string + hostname: + type: string + ip_address: + type: string + port: + type: integer + status: + type: string + description: online | offline | connecting | error + version: + type: string + capabilities: + $ref: '#/components/schemas/AgentCapabilities' + resources: + $ref: '#/components/schemas/NodeResources' + metadata: + type: object + additionalProperties: true + last_heartbeat: + type: string + format: date-time + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + AgentCapabilities: + type: object + properties: + container_runtimes: + type: array + items: + type: string + supported_architectures: + type: array + items: + type: string + max_containers: + type: integer + storage_driver: + type: string + network_plugins: + type: array + items: + type: string + features: + type: array + items: + type: string + + NodeResources: + type: object + properties: + cpu: + type: object + properties: + cores: + type: integer + allocation: + type: number + description: Allocated CPU percentage + usage: + type: number + description: Current usage percentage + memory: + type: object + properties: + total: + type: integer + format: int64 + allocated: + type: integer + format: int64 + used: + type: integer + format: int64 + available: + type: integer + format: int64 + storage: + type: object + properties: + total: + type: integer + format: int64 + allocated: + type: integer + format: int64 + used: + type: integer + format: int64 + available: + type: integer + format: int64 + network: + type: object + properties: + interfaces: + type: array + items: + type: object + properties: + name: + type: string + ip_address: + type: string + mac_address: + type: string + speed: + type: integer + status: + type: string + bandwidth: + type: object + properties: + inbound: + type: integer + format: int64 + description: Bytes per second + outbound: + type: integer + format: int64 + description: Bytes per second + + RegisterAgentRequest: + type: object + required: + - name + - hostname + - ip_address + - port + - capabilities + properties: + name: + type: string + hostname: + type: string + ip_address: + type: string + port: + type: integer + capabilities: + $ref: '#/components/schemas/AgentCapabilities' + auth_token: + type: string + description: May also be sent via the X-Agent-Token header + + AgentHeartbeat: + type: object + properties: + agent_id: + type: string + status: + type: string + resources: + $ref: '#/components/schemas/NodeResources' + container_count: + type: integer + system_load: + type: object + uptime: + type: integer + version: + type: string + + AgentCommand: + type: object + properties: + id: + type: string + node_agent_id: + type: string + type: + type: string + payload: + type: object + status: + type: string + description: pending | running | completed | failed + result: + type: string + error: + type: string + created_at: + type: string + format: date-time + completed_at: + type: string + format: date-time + + ExecuteCommandRequest: + type: object + required: + - type + properties: + type: + type: string + payload: + type: object + + ContainerInstance: + type: object + properties: + id: + type: string + agent_id: + type: string + project_id: + type: string + service_id: + type: string + name: + type: string + image: + type: string + status: + type: string + resources: + type: object + ports: + type: array + items: + type: object + created_at: + type: string + format: date-time + + CreateContainerRequest: + type: object + required: + - name + - image + - project_id + - service_id + - resources + properties: + name: + type: string + image: + type: string + project_id: + type: string + service_id: + type: string + resources: + type: object + description: cpu/memory limits + ports: + type: array + items: + type: object + properties: + host_port: + type: integer + container_port: + type: integer + protocol: + type: string + environment: + type: object + additionalProperties: + type: string + volumes: + type: array + items: + type: object + networks: + type: array + items: + type: string + restart_policy: + type: object + health_check: + type: object + + PreviewEnvironment: + type: object + properties: + id: + type: string + format: uuid + project_id: + type: string + format: uuid + service_id: + type: string + format: uuid + branch_name: + type: string + pr_number: + type: integer + environment: + type: string + description: Generated name, e.g. preview-{branch}-{ts} + status: + type: string + enum: [building, running, failed, stopped, expired] + url: + type: string + expires_at: + type: string + format: date-time + deployment_id: + type: string + format: uuid + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + CreatePreviewEnvironmentRequest: + type: object + required: + - service_id + - branch_name + properties: + project_id: + type: string + format: uuid + service_id: + type: string + format: uuid + branch_name: + type: string + pr_number: + type: integer + ttl_hours: + type: integer + minimum: 1 + maximum: 168 + + UpdatePreviewEnvironmentRequest: + type: object + properties: + status: + type: string + enum: [building, running, failed, stopped, expired] + url: + type: string + expires_at: + type: string + format: date-time + ttl_hours: + type: integer + minimum: 1 + maximum: 168 + + PromotePreviewEnvironmentRequest: + type: object + required: + - target_environment + properties: + target_environment: + type: string + enum: [production, development] + create_backup: + type: boolean + + StartSecurityScanRequest: + type: object + required: + - project_id + - scan_type + properties: + project_id: + type: string + service_id: + type: string + scan_type: + type: string + enum: [dependency, configuration, comprehensive] + + SecurityScan: + type: object + properties: + id: + type: string + project_id: + type: string + service_id: + type: string + scan_type: + type: string + status: + type: string + description: pending | running | completed | failed + findings_count: + type: integer + started_at: + type: string + format: date-time + completed_at: + type: string + format: date-time + + Vulnerability: + type: object + properties: + id: + type: string + type: + type: string + severity: + type: string + enum: [low, medium, high, critical] + title: + type: string + description: + type: string + service_id: + type: string + project_id: + type: string + status: + type: string + enum: [open, resolved, ignored] + found_at: + type: string + format: date-time + resolved_at: + type: string + format: date-time + + StartComplianceAssessmentRequest: + type: object + required: + - project_id + - framework_id + properties: + project_id: + type: string + framework_id: + type: string + + CronJob: + type: object + properties: + id: + type: string + project_id: + type: string + service_id: + type: string + name: + type: string + schedule: + type: string + description: Cron expression + command: + type: string + timezone: + type: string + enabled: + type: boolean + last_run_at: + type: string + format: date-time + next_run_at: + type: string + format: date-time + last_status: + type: string + last_output: + type: string + retention: + type: integer + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + CronExecution: + type: object + properties: + id: + type: string + cron_job_id: + type: string + started_at: + type: string + format: date-time + finished_at: + type: string + format: date-time + status: + type: string + output: + type: string + error: + type: string + + CreateCronJobRequest: + type: object + required: + - project_id + - service_id + - name + - schedule + - command + properties: + project_id: + type: string + service_id: + type: string + name: + type: string + schedule: + type: string + command: + type: string + timezone: + type: string + enabled: + type: boolean + retention: + type: integer + + UpdateCronJobRequest: + type: object + properties: + name: + type: string + schedule: + type: string + command: + type: string + timezone: + type: string + enabled: + type: boolean + retention: + type: integer + + GatewayService: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + upstream_url: + type: string + route_prefix: + type: string + enabled: + type: boolean + rpm_limit: + type: integer + monthly_quota: + type: integer + health_path: + type: string + last_validated_at: + type: string + format: date-time + last_validation_status: + type: string + created_at: + type: string + format: date-time + + GatewayServiceRequest: + type: object + required: + - name + - upstreamUrl + - routePrefix + properties: + name: + type: string + maxLength: 100 + upstreamUrl: + type: string + format: uri + maxLength: 500 + routePrefix: + type: string + maxLength: 200 + enabled: + type: boolean + rpmLimit: + type: integer + minimum: 1 + maximum: 10000 + monthlyQuota: + type: integer + minimum: 1 + maximum: 10000000 + + GatewayAPIKeyRequest: + type: object + required: + - name + properties: + name: + type: string + maxLength: 100 + plan: + type: string + enum: [free, pro, business, enterprise] + default: free + enabled: + type: boolean + rpmLimit: + type: integer + minimum: 1 + maximum: 10000 + monthlyQuota: + type: integer + minimum: 1 + maximum: 10000000 + + GatewayAPIKey: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + plan: + type: string + enabled: + type: boolean + rpm_limit: + type: integer + monthly_quota: + type: integer + key_prefix: + type: string + created_at: + type: string + format: date-time + + GatewayResponse: + type: object + description: Standard gateway management envelope — `data` carries the payload, `error` carries {code, message, details}, `meta` carries pagination. + properties: + success: + type: boolean + data: + description: Endpoint-specific payload (GatewayService, GatewayAPIKey, arrays, or analytics objects) + error: + type: object + properties: + code: + type: string + message: + type: string + details: {} + meta: + type: object + properties: + page: + type: integer + per_page: + type: integer + total: + type: integer + total_pages: + type: integer + + parameters: + IdParam: + name: id + in: path + required: true + description: Resource ID + schema: + type: string + ProjectIdParam: + name: id + in: path + required: true + description: Project ID + schema: + type: string + ServiceIdParam: + name: serviceId + in: path + required: true + description: Service ID + schema: + type: string + AgentIdParam: + name: id + in: path + required: true + description: Node agent ID + schema: + type: string + ContainerIdParam: + name: containerId + in: path + required: true + description: Container ID + schema: + type: string tags: - name: Health @@ -2240,3 +6118,21 @@ tags: description: Database management - name: Git description: Git integration + - name: System + description: System upgrade and host monitoring + - name: Realtime + description: WebSocket event stream + - name: Agents + description: Node agent management and agent ingestion + - name: Scaling + description: Autoscaling policies and controls + - name: HA + description: High availability, failover, health checks, alerts + - name: Preview Environments + description: Per-branch/PR preview deployments + - name: Security + description: Vulnerability scans and compliance reporting + - name: Cron + description: Scheduled jobs + - name: Gateway + description: API gateway — upstream services, keys, analytics