From dac28d3ea5a40703b958b31b75a0ddecf4495222 Mon Sep 17 00:00:00 2001 From: allanice001 Date: Fri, 26 Dec 2025 00:30:46 +0000 Subject: [PATCH] feat: move jobs to action based Signed-off-by: allanice001 --- cmd/serve.go | 76 +++-- docs/docs.go | 4 +- docs/openapi.json | 4 +- docs/openapi.yaml | 468 ++++++++++++++++++++++++++ internal/api/mount_admin_routes.go | 11 + internal/api/mount_api_routes.go | 2 +- internal/api/mount_cluster_routes.go | 9 +- internal/app/runtime.go | 3 + internal/bg/bg.go | 40 ++- internal/bg/cluster_action.go | 166 +++++++++ internal/handlers/actions.go | 256 ++++++++++++++ internal/handlers/cluster_runs.go | 257 ++++++++++++++ internal/handlers/dto/actions.go | 28 ++ internal/handlers/dto/cluster_runs.go | 19 ++ internal/models/action.go | 16 + internal/models/cluster_runs.go | 27 ++ ui/src/App.tsx | 2 + ui/src/api/actions.ts | 30 ++ ui/src/api/clusters.ts | 19 +- ui/src/layouts/nav-config.ts | 2 + ui/src/pages/actions-page.tsx | 433 ++++++++++++++++++++++++ ui/src/pages/cluster-page.tsx | 450 +++++++++++++++++-------- ui/src/sdkClient.ts | 10 + 23 files changed, 2128 insertions(+), 204 deletions(-) create mode 100644 internal/bg/cluster_action.go create mode 100644 internal/handlers/actions.go create mode 100644 internal/handlers/cluster_runs.go create mode 100644 internal/handlers/dto/actions.go create mode 100644 internal/handlers/dto/cluster_runs.go create mode 100644 internal/models/action.go create mode 100644 internal/models/cluster_runs.go create mode 100644 ui/src/api/actions.ts create mode 100644 ui/src/pages/actions-page.tsx diff --git a/cmd/serve.go b/cmd/serve.go index 0d1b819..0d24495 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -116,46 +116,48 @@ var serveCmd = &cobra.Command{ log.Printf("failed to enqueue bootstrap_bastion: %v", err) } - _, err = jobs.Enqueue( - context.Background(), - uuid.NewString(), - "prepare_cluster", - bg.ClusterPrepareArgs{IntervalS: 120}, - archer.WithMaxRetries(3), - archer.WithScheduleTime(time.Now().Add(60*time.Second)), - ) - if err != nil { - log.Printf("failed to enqueue prepare_cluster: %v", err) - } + /* + _, err = jobs.Enqueue( + context.Background(), + uuid.NewString(), + "prepare_cluster", + bg.ClusterPrepareArgs{IntervalS: 120}, + archer.WithMaxRetries(3), + archer.WithScheduleTime(time.Now().Add(60*time.Second)), + ) + if err != nil { + log.Printf("failed to enqueue prepare_cluster: %v", err) + } - _, err = jobs.Enqueue( - context.Background(), - uuid.NewString(), - "cluster_setup", - bg.ClusterSetupArgs{ - IntervalS: 120, - }, - archer.WithMaxRetries(3), - archer.WithScheduleTime(time.Now().Add(60*time.Second)), - ) + _, err = jobs.Enqueue( + context.Background(), + uuid.NewString(), + "cluster_setup", + bg.ClusterSetupArgs{ + IntervalS: 120, + }, + archer.WithMaxRetries(3), + archer.WithScheduleTime(time.Now().Add(60*time.Second)), + ) - if err != nil { - log.Printf("failed to enqueue cluster setup: %v", err) - } + if err != nil { + log.Printf("failed to enqueue cluster setup: %v", err) + } - _, err = jobs.Enqueue( - context.Background(), - uuid.NewString(), - "cluster_bootstrap", - bg.ClusterBootstrapArgs{ - IntervalS: 120, - }, - archer.WithMaxRetries(3), - archer.WithScheduleTime(time.Now().Add(60*time.Second)), - ) - if err != nil { - log.Printf("failed to enqueue cluster bootstrap: %v", err) - } + _, err = jobs.Enqueue( + context.Background(), + uuid.NewString(), + "cluster_bootstrap", + bg.ClusterBootstrapArgs{ + IntervalS: 120, + }, + archer.WithMaxRetries(3), + archer.WithScheduleTime(time.Now().Add(60*time.Second)), + ) + if err != nil { + log.Printf("failed to enqueue cluster bootstrap: %v", err) + } + */ _, err = jobs.Enqueue( context.Background(), diff --git a/docs/docs.go b/docs/docs.go index 45782ab..3f11197 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -6,10 +6,10 @@ import "github.com/swaggo/swag/v2" const docTemplate = `{ "schemes": {{ marshal .Schemes }}, - "components": {"schemas":{"dto.AnnotationResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.AttachAnnotationsRequest":{"properties":{"annotation_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachBastionRequest":{"properties":{"server_id":{"type":"string"}},"type":"object"},"dto.AttachCaptainDomainRequest":{"properties":{"domain_id":{"type":"string"}},"type":"object"},"dto.AttachLabelsRequest":{"properties":{"label_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachLoadBalancerRequest":{"properties":{"load_balancer_id":{"type":"string"}},"type":"object"},"dto.AttachNodePoolRequest":{"properties":{"node_pool_id":{"type":"string"}},"type":"object"},"dto.AttachRecordSetRequest":{"properties":{"record_set_id":{"type":"string"}},"type":"object"},"dto.AttachServersRequest":{"properties":{"server_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachTaintsRequest":{"properties":{"taint_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AuthStartResponse":{"properties":{"auth_url":{"example":"https://accounts.google.com/o/oauth2/v2/auth?client_id=...","type":"string"}},"type":"object"},"dto.ClusterResponse":{"properties":{"apps_load_balancer":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"bastion_server":{"$ref":"#/components/schemas/dto.ServerResponse"},"captain_domain":{"$ref":"#/components/schemas/dto.DomainResponse"},"certificate_key":{"type":"string"},"cluster_provider":{"type":"string"},"control_plane_fqdn":{"type":"string"},"control_plane_record_set":{"$ref":"#/components/schemas/dto.RecordSetResponse"},"created_at":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"glueops_load_balancer":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"id":{"type":"string"},"kubeconfig":{"type":"string"},"last_error":{"type":"string"},"name":{"type":"string"},"node_pools":{"items":{"$ref":"#/components/schemas/dto.NodePoolResponse"},"type":"array","uniqueItems":false},"org_key":{"type":"string"},"org_secret":{"type":"string"},"random_token":{"type":"string"},"region":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.CreateAnnotationRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CreateClusterRequest":{"properties":{"cluster_provider":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"}},"type":"object"},"dto.CreateCredentialRequest":{"properties":{"account_id":{"maxLength":32,"type":"string"},"credential_provider":{"enum":["aws","cloudflare","hetzner","digitalocean","generic"],"type":"string"},"kind":{"description":"aws_access_key, api_token, basic_auth, oauth2","type":"string"},"name":{"description":"human label","maxLength":100,"type":"string"},"region":{"maxLength":32,"type":"string"},"schema_version":{"description":"secret schema version","minimum":1,"type":"integer"},"scope":{"description":"{\"service\":\"route53\"} or {\"arn\":\"...\"}","type":"object"},"scope_kind":{"enum":["credential_provider","service","resource"],"type":"string"},"scope_version":{"description":"scope schema version","minimum":1,"type":"integer"},"secret":{"description":"encrypted later","type":"object"}},"required":["credential_provider","kind","schema_version","scope","scope_kind","scope_version","secret"],"type":"object"},"dto.CreateDomainRequest":{"properties":{"credential_id":{"type":"string"},"domain_name":{"type":"string"},"zone_id":{"maxLength":128,"type":"string"}},"required":["credential_id","domain_name"],"type":"object"},"dto.CreateLabelRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CreateLoadBalancerRequest":{"properties":{"kind":{"enum":["glueops","public"],"example":"public","type":"string"},"name":{"example":"glueops","type":"string"},"private_ip_address":{"example":"192.168.0.2","type":"string"},"public_ip_address":{"example":"8.8.8.8","type":"string"}},"type":"object"},"dto.CreateNodePoolRequest":{"properties":{"name":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"}},"type":"object"},"dto.CreateRecordSetRequest":{"properties":{"name":{"description":"Name relative to domain (\"endpoint\") OR FQDN (\"endpoint.example.com\").\nServer normalizes to relative.","maxLength":253,"type":"string"},"ttl":{"maximum":86400,"minimum":1,"type":"integer"},"type":{"type":"string"},"values":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"required":["name","type"],"type":"object"},"dto.CreateSSHRequest":{"properties":{"bits":{"description":"Only for RSA","type":"integer"},"comment":{"example":"deploy@autoglue","type":"string"},"name":{"type":"string"},"type":{"description":"\"rsa\" (default) or \"ed25519\"","type":"string"}},"type":"object"},"dto.CreateServerRequest":{"properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"}},"type":"object"},"dto.CreateTaintRequest":{"properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CredentialOut":{"properties":{"account_id":{"type":"string"},"created_at":{"type":"string"},"credential_provider":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"schema_version":{"type":"integer"},"scope":{"type":"object"},"scope_kind":{"type":"string"},"scope_version":{"type":"integer"},"updated_at":{"type":"string"}},"type":"object"},"dto.DomainResponse":{"properties":{"created_at":{"type":"string"},"credential_id":{"type":"string"},"domain_name":{"type":"string"},"id":{"type":"string"},"last_error":{"type":"string"},"organization_id":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"},"zone_id":{"type":"string"}},"type":"object"},"dto.EnqueueRequest":{"properties":{"payload":{"type":"object"},"queue":{"example":"default","type":"string"},"run_at":{"example":"2025-11-05T08:00:00Z","type":"string"},"type":{"example":"email.send","type":"string"}},"type":"object"},"dto.JWK":{"properties":{"alg":{"example":"RS256","type":"string"},"e":{"example":"AQAB","type":"string"},"kid":{"example":"7c6f1d0a-7a98-4e6a-9dbf-6b1af4b9f345","type":"string"},"kty":{"example":"RSA","type":"string"},"n":{"type":"string"},"use":{"example":"sig","type":"string"},"x":{"type":"string"}},"type":"object"},"dto.JWKS":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/dto.JWK"},"type":"array","uniqueItems":false}},"type":"object"},"dto.Job":{"properties":{"attempts":{"example":0,"type":"integer"},"created_at":{"example":"2025-11-04T09:30:00Z","type":"string"},"id":{"example":"01HF7SZK8Z8WG1M3J7S2Z8M2N6","type":"string"},"last_error":{"example":"error message","type":"string"},"max_attempts":{"example":3,"type":"integer"},"payload":{},"queue":{"example":"default","type":"string"},"run_at":{"example":"2025-11-04T09:30:00Z","type":"string"},"status":{"$ref":"#/components/schemas/dto.JobStatus"},"type":{"example":"email.send","type":"string"},"updated_at":{"example":"2025-11-04T09:30:00Z","type":"string"}},"type":"object"},"dto.JobStatus":{"enum":["queued|running|succeeded|failed|canceled|retrying|scheduled"],"example":"queued","type":"string","x-enum-varnames":["StatusQueued","StatusRunning","StatusSucceeded","StatusFailed","StatusCanceled","StatusRetrying","StatusScheduled"]},"dto.LabelResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.LoadBalancerResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.LogoutRequest":{"properties":{"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf...","type":"string"}},"type":"object"},"dto.NodePoolResponse":{"properties":{"annotations":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array","uniqueItems":false},"created_at":{"type":"string"},"id":{"type":"string"},"labels":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array","uniqueItems":false},"name":{"type":"string"},"organization_id":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"},"servers":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array","uniqueItems":false},"taints":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array","uniqueItems":false},"updated_at":{"type":"string"}},"type":"object"},"dto.PageJob":{"properties":{"items":{"items":{"$ref":"#/components/schemas/dto.Job"},"type":"array","uniqueItems":false},"page":{"example":1,"type":"integer"},"page_size":{"example":25,"type":"integer"},"total":{"example":120,"type":"integer"}},"type":"object"},"dto.QueueInfo":{"properties":{"failed":{"example":5,"type":"integer"},"name":{"example":"default","type":"string"},"pending":{"example":42,"type":"integer"},"running":{"example":3,"type":"integer"},"scheduled":{"example":7,"type":"integer"}},"type":"object"},"dto.RecordSetResponse":{"properties":{"created_at":{"type":"string"},"domain_id":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"last_error":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"status":{"type":"string"},"ttl":{"type":"integer"},"type":{"type":"string"},"updated_at":{"type":"string"},"values":{"description":"[]string JSON","type":"object"}},"type":"object"},"dto.RefreshRequest":{"properties":{"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf...","type":"string"}},"type":"object"},"dto.ServerResponse":{"properties":{"created_at":{"type":"string"},"hostname":{"type":"string"},"id":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.SetKubeconfigRequest":{"properties":{"kubeconfig":{"type":"string"}},"type":"object"},"dto.SshResponse":{"properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.SshRevealResponse":{"properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_key":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.TaintResponse":{"properties":{"created_at":{"type":"string"},"effect":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.TokenPair":{"properties":{"access_token":{"example":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ij...","type":"string"},"expires_in":{"example":3600,"type":"integer"},"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf....","type":"string"},"token_type":{"example":"Bearer","type":"string"}},"type":"object"},"dto.UpdateAnnotationRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.UpdateClusterRequest":{"properties":{"cluster_provider":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"}},"type":"object"},"dto.UpdateCredentialRequest":{"properties":{"account_id":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"scope":{"type":"object"},"scope_kind":{"type":"string"},"scope_version":{"type":"integer"},"secret":{"description":"set if rotating","type":"object"}},"type":"object"},"dto.UpdateDomainRequest":{"properties":{"credential_id":{"type":"string"},"domain_name":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"type":"string"},"zone_id":{"maxLength":128,"type":"string"}},"type":"object"},"dto.UpdateLabelRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.UpdateLoadBalancerRequest":{"properties":{"kind":{"enum":["glueops","public"],"example":"public","type":"string"},"name":{"example":"glue","type":"string"},"private_ip_address":{"example":"192.168.0.2","type":"string"},"public_ip_address":{"example":"8.8.8.8","type":"string"}},"type":"object"},"dto.UpdateNodePoolRequest":{"properties":{"name":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"}},"type":"object"},"dto.UpdateRecordSetRequest":{"properties":{"name":{"description":"Any change flips status back to pending (worker will UPSERT)","maxLength":253,"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"type":"string"},"ttl":{"maximum":86400,"minimum":1,"type":"integer"},"type":{"type":"string"},"values":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.UpdateServerRequest":{"properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"}},"type":"object"},"dto.UpdateTaintRequest":{"properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"handlers.HealthStatus":{"properties":{"status":{"example":"ok","type":"string"}},"type":"object"},"handlers.VersionResponse":{"properties":{"built":{"example":"2025-11-08T12:34:56Z","type":"string"},"builtBy":{"example":"ci","type":"string"},"commit":{"example":"a1b2c3d","type":"string"},"commitTime":{"example":"2025-11-08T12:31:00Z","type":"string"},"go":{"example":"go1.23.3","type":"string"},"goArch":{"example":"amd64","type":"string"},"goOS":{"example":"linux","type":"string"},"modified":{"example":false,"type":"boolean"},"revision":{"example":"a1b2c3d4e5f6abcdef","type":"string"},"vcs":{"example":"git","type":"string"},"version":{"example":"1.4.2","type":"string"}},"type":"object"},"handlers.createUserKeyRequest":{"properties":{"expires_in_hours":{"description":"optional TTL","type":"integer"},"name":{"type":"string"}},"type":"object"},"handlers.meResponse":{"properties":{"avatar_url":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"emails":{"items":{"$ref":"#/components/schemas/models.UserEmail"},"type":"array","uniqueItems":false},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"organizations":{"items":{"$ref":"#/components/schemas/models.Organization"},"type":"array","uniqueItems":false},"primary_email":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"handlers.memberOut":{"properties":{"email":{"type":"string"},"role":{"description":"owner/admin/member","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"handlers.memberUpsertReq":{"properties":{"role":{"example":"member","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"handlers.orgCreateReq":{"properties":{"domain":{"example":"acme.com","type":"string"},"name":{"example":"Acme Corp","type":"string"}},"type":"object"},"handlers.orgKeyCreateReq":{"properties":{"expires_in_hours":{"example":720,"type":"integer"},"name":{"example":"automation-bot","type":"string"}},"type":"object"},"handlers.orgKeyCreateResp":{"properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"org_key":{"description":"shown once:","type":"string"},"org_secret":{"description":"shown once:","type":"string"},"scope":{"description":"\"org\"","type":"string"}},"type":"object"},"handlers.orgUpdateReq":{"properties":{"domain":{"type":"string"},"name":{"type":"string"}},"type":"object"},"handlers.updateMeRequest":{"properties":{"display_name":{"type":"string"}},"type":"object"},"handlers.userAPIKeyOut":{"properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"format":"uuid","type":"string"},"last_used_at":{"type":"string"},"name":{"type":"string"},"plain":{"description":"Shown only on create:","type":"string"},"scope":{"description":"\"user\"","type":"string"}},"type":"object"},"models.APIKey":{"properties":{"cluster_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"is_ephemeral":{"type":"boolean"},"last_used_at":{"format":"date-time","type":"string"},"name":{"type":"string"},"org_id":{"format":"uuid","type":"string"},"prefix":{"type":"string"},"purpose":{"type":"string"},"revoked":{"type":"boolean"},"scope":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"models.Organization":{"properties":{"created_at":{"format":"date-time","type":"string"},"domain":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"name":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"models.User":{"properties":{"avatar_url":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"primary_email":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"models.UserEmail":{"properties":{"created_at":{"format":"date-time","type":"string"},"email":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_primary":{"type":"boolean"},"is_verified":{"type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/models.User"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"utils.ErrorResponse":{"properties":{"code":{"description":"A machine-readable error code, e.g. \"validation_error\"\nexample: validation_error","type":"string"},"message":{"description":"Human-readable message\nexample: slug is required","type":"string"}},"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"description":"User API key","in":"header","name":"X-API-KEY","type":"apiKey"},"BearerAuth":{"description":"Bearer token authentication","in":"header","name":"Authorization","type":"apiKey"},"OrgKeyAuth":{"description":"Org-level key/secret authentication","in":"header","name":"X-ORG-KEY","type":"apiKey"},"OrgSecretAuth":{"description":"Org-level secret","in":"header","name":"X-ORG-SECRET","type":"apiKey"}}}, + "components": {"schemas":{"dto.ActionResponse":{"properties":{"created_at":{"format":"date-time","type":"string"},"description":{"type":"string"},"id":{"format":"uuid","type":"string"},"label":{"type":"string"},"make_target":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"dto.AnnotationResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.AttachAnnotationsRequest":{"properties":{"annotation_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachBastionRequest":{"properties":{"server_id":{"type":"string"}},"type":"object"},"dto.AttachCaptainDomainRequest":{"properties":{"domain_id":{"type":"string"}},"type":"object"},"dto.AttachLabelsRequest":{"properties":{"label_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachLoadBalancerRequest":{"properties":{"load_balancer_id":{"type":"string"}},"type":"object"},"dto.AttachNodePoolRequest":{"properties":{"node_pool_id":{"type":"string"}},"type":"object"},"dto.AttachRecordSetRequest":{"properties":{"record_set_id":{"type":"string"}},"type":"object"},"dto.AttachServersRequest":{"properties":{"server_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachTaintsRequest":{"properties":{"taint_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AuthStartResponse":{"properties":{"auth_url":{"example":"https://accounts.google.com/o/oauth2/v2/auth?client_id=...","type":"string"}},"type":"object"},"dto.ClusterResponse":{"properties":{"apps_load_balancer":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"bastion_server":{"$ref":"#/components/schemas/dto.ServerResponse"},"captain_domain":{"$ref":"#/components/schemas/dto.DomainResponse"},"certificate_key":{"type":"string"},"cluster_provider":{"type":"string"},"control_plane_fqdn":{"type":"string"},"control_plane_record_set":{"$ref":"#/components/schemas/dto.RecordSetResponse"},"created_at":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"glueops_load_balancer":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"id":{"type":"string"},"kubeconfig":{"type":"string"},"last_error":{"type":"string"},"name":{"type":"string"},"node_pools":{"items":{"$ref":"#/components/schemas/dto.NodePoolResponse"},"type":"array","uniqueItems":false},"org_key":{"type":"string"},"org_secret":{"type":"string"},"random_token":{"type":"string"},"region":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.ClusterRunResponse":{"properties":{"action":{"type":"string"},"cluster_id":{"format":"uuid","type":"string"},"created_at":{"format":"date-time","type":"string"},"error":{"type":"string"},"finished_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"organization_id":{"format":"uuid","type":"string"},"status":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"dto.CreateActionRequest":{"properties":{"description":{"type":"string"},"label":{"type":"string"},"make_target":{"type":"string"}},"type":"object"},"dto.CreateAnnotationRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CreateClusterRequest":{"properties":{"cluster_provider":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"}},"type":"object"},"dto.CreateCredentialRequest":{"properties":{"account_id":{"maxLength":32,"type":"string"},"credential_provider":{"enum":["aws","cloudflare","hetzner","digitalocean","generic"],"type":"string"},"kind":{"description":"aws_access_key, api_token, basic_auth, oauth2","type":"string"},"name":{"description":"human label","maxLength":100,"type":"string"},"region":{"maxLength":32,"type":"string"},"schema_version":{"description":"secret schema version","minimum":1,"type":"integer"},"scope":{"description":"{\"service\":\"route53\"} or {\"arn\":\"...\"}","type":"object"},"scope_kind":{"enum":["credential_provider","service","resource"],"type":"string"},"scope_version":{"description":"scope schema version","minimum":1,"type":"integer"},"secret":{"description":"encrypted later","type":"object"}},"required":["credential_provider","kind","schema_version","scope","scope_kind","scope_version","secret"],"type":"object"},"dto.CreateDomainRequest":{"properties":{"credential_id":{"type":"string"},"domain_name":{"type":"string"},"zone_id":{"maxLength":128,"type":"string"}},"required":["credential_id","domain_name"],"type":"object"},"dto.CreateLabelRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CreateLoadBalancerRequest":{"properties":{"kind":{"enum":["glueops","public"],"example":"public","type":"string"},"name":{"example":"glueops","type":"string"},"private_ip_address":{"example":"192.168.0.2","type":"string"},"public_ip_address":{"example":"8.8.8.8","type":"string"}},"type":"object"},"dto.CreateNodePoolRequest":{"properties":{"name":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"}},"type":"object"},"dto.CreateRecordSetRequest":{"properties":{"name":{"description":"Name relative to domain (\"endpoint\") OR FQDN (\"endpoint.example.com\").\nServer normalizes to relative.","maxLength":253,"type":"string"},"ttl":{"maximum":86400,"minimum":1,"type":"integer"},"type":{"type":"string"},"values":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"required":["name","type"],"type":"object"},"dto.CreateSSHRequest":{"properties":{"bits":{"description":"Only for RSA","type":"integer"},"comment":{"example":"deploy@autoglue","type":"string"},"name":{"type":"string"},"type":{"description":"\"rsa\" (default) or \"ed25519\"","type":"string"}},"type":"object"},"dto.CreateServerRequest":{"properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"}},"type":"object"},"dto.CreateTaintRequest":{"properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CredentialOut":{"properties":{"account_id":{"type":"string"},"created_at":{"type":"string"},"credential_provider":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"schema_version":{"type":"integer"},"scope":{"type":"object"},"scope_kind":{"type":"string"},"scope_version":{"type":"integer"},"updated_at":{"type":"string"}},"type":"object"},"dto.DomainResponse":{"properties":{"created_at":{"type":"string"},"credential_id":{"type":"string"},"domain_name":{"type":"string"},"id":{"type":"string"},"last_error":{"type":"string"},"organization_id":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"},"zone_id":{"type":"string"}},"type":"object"},"dto.EnqueueRequest":{"properties":{"payload":{"type":"object"},"queue":{"example":"default","type":"string"},"run_at":{"example":"2025-11-05T08:00:00Z","type":"string"},"type":{"example":"email.send","type":"string"}},"type":"object"},"dto.JWK":{"properties":{"alg":{"example":"RS256","type":"string"},"e":{"example":"AQAB","type":"string"},"kid":{"example":"7c6f1d0a-7a98-4e6a-9dbf-6b1af4b9f345","type":"string"},"kty":{"example":"RSA","type":"string"},"n":{"type":"string"},"use":{"example":"sig","type":"string"},"x":{"type":"string"}},"type":"object"},"dto.JWKS":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/dto.JWK"},"type":"array","uniqueItems":false}},"type":"object"},"dto.Job":{"properties":{"attempts":{"example":0,"type":"integer"},"created_at":{"example":"2025-11-04T09:30:00Z","type":"string"},"id":{"example":"01HF7SZK8Z8WG1M3J7S2Z8M2N6","type":"string"},"last_error":{"example":"error message","type":"string"},"max_attempts":{"example":3,"type":"integer"},"payload":{},"queue":{"example":"default","type":"string"},"run_at":{"example":"2025-11-04T09:30:00Z","type":"string"},"status":{"$ref":"#/components/schemas/dto.JobStatus"},"type":{"example":"email.send","type":"string"},"updated_at":{"example":"2025-11-04T09:30:00Z","type":"string"}},"type":"object"},"dto.JobStatus":{"enum":["queued|running|succeeded|failed|canceled|retrying|scheduled"],"example":"queued","type":"string","x-enum-varnames":["StatusQueued","StatusRunning","StatusSucceeded","StatusFailed","StatusCanceled","StatusRetrying","StatusScheduled"]},"dto.LabelResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.LoadBalancerResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.LogoutRequest":{"properties":{"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf...","type":"string"}},"type":"object"},"dto.NodePoolResponse":{"properties":{"annotations":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array","uniqueItems":false},"created_at":{"type":"string"},"id":{"type":"string"},"labels":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array","uniqueItems":false},"name":{"type":"string"},"organization_id":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"},"servers":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array","uniqueItems":false},"taints":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array","uniqueItems":false},"updated_at":{"type":"string"}},"type":"object"},"dto.PageJob":{"properties":{"items":{"items":{"$ref":"#/components/schemas/dto.Job"},"type":"array","uniqueItems":false},"page":{"example":1,"type":"integer"},"page_size":{"example":25,"type":"integer"},"total":{"example":120,"type":"integer"}},"type":"object"},"dto.QueueInfo":{"properties":{"failed":{"example":5,"type":"integer"},"name":{"example":"default","type":"string"},"pending":{"example":42,"type":"integer"},"running":{"example":3,"type":"integer"},"scheduled":{"example":7,"type":"integer"}},"type":"object"},"dto.RecordSetResponse":{"properties":{"created_at":{"type":"string"},"domain_id":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"last_error":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"status":{"type":"string"},"ttl":{"type":"integer"},"type":{"type":"string"},"updated_at":{"type":"string"},"values":{"description":"[]string JSON","type":"object"}},"type":"object"},"dto.RefreshRequest":{"properties":{"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf...","type":"string"}},"type":"object"},"dto.ServerResponse":{"properties":{"created_at":{"type":"string"},"hostname":{"type":"string"},"id":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.SetKubeconfigRequest":{"properties":{"kubeconfig":{"type":"string"}},"type":"object"},"dto.SshResponse":{"properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.SshRevealResponse":{"properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_key":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.TaintResponse":{"properties":{"created_at":{"type":"string"},"effect":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.TokenPair":{"properties":{"access_token":{"example":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ij...","type":"string"},"expires_in":{"example":3600,"type":"integer"},"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf....","type":"string"},"token_type":{"example":"Bearer","type":"string"}},"type":"object"},"dto.UpdateActionRequest":{"properties":{"description":{"type":"string"},"label":{"type":"string"},"make_target":{"type":"string"}},"type":"object"},"dto.UpdateAnnotationRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.UpdateClusterRequest":{"properties":{"cluster_provider":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"}},"type":"object"},"dto.UpdateCredentialRequest":{"properties":{"account_id":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"scope":{"type":"object"},"scope_kind":{"type":"string"},"scope_version":{"type":"integer"},"secret":{"description":"set if rotating","type":"object"}},"type":"object"},"dto.UpdateDomainRequest":{"properties":{"credential_id":{"type":"string"},"domain_name":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"type":"string"},"zone_id":{"maxLength":128,"type":"string"}},"type":"object"},"dto.UpdateLabelRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.UpdateLoadBalancerRequest":{"properties":{"kind":{"enum":["glueops","public"],"example":"public","type":"string"},"name":{"example":"glue","type":"string"},"private_ip_address":{"example":"192.168.0.2","type":"string"},"public_ip_address":{"example":"8.8.8.8","type":"string"}},"type":"object"},"dto.UpdateNodePoolRequest":{"properties":{"name":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"}},"type":"object"},"dto.UpdateRecordSetRequest":{"properties":{"name":{"description":"Any change flips status back to pending (worker will UPSERT)","maxLength":253,"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"type":"string"},"ttl":{"maximum":86400,"minimum":1,"type":"integer"},"type":{"type":"string"},"values":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.UpdateServerRequest":{"properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"}},"type":"object"},"dto.UpdateTaintRequest":{"properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"handlers.HealthStatus":{"properties":{"status":{"example":"ok","type":"string"}},"type":"object"},"handlers.VersionResponse":{"properties":{"built":{"example":"2025-11-08T12:34:56Z","type":"string"},"builtBy":{"example":"ci","type":"string"},"commit":{"example":"a1b2c3d","type":"string"},"commitTime":{"example":"2025-11-08T12:31:00Z","type":"string"},"go":{"example":"go1.23.3","type":"string"},"goArch":{"example":"amd64","type":"string"},"goOS":{"example":"linux","type":"string"},"modified":{"example":false,"type":"boolean"},"revision":{"example":"a1b2c3d4e5f6abcdef","type":"string"},"vcs":{"example":"git","type":"string"},"version":{"example":"1.4.2","type":"string"}},"type":"object"},"handlers.createUserKeyRequest":{"properties":{"expires_in_hours":{"description":"optional TTL","type":"integer"},"name":{"type":"string"}},"type":"object"},"handlers.meResponse":{"properties":{"avatar_url":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"emails":{"items":{"$ref":"#/components/schemas/models.UserEmail"},"type":"array","uniqueItems":false},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"organizations":{"items":{"$ref":"#/components/schemas/models.Organization"},"type":"array","uniqueItems":false},"primary_email":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"handlers.memberOut":{"properties":{"email":{"type":"string"},"role":{"description":"owner/admin/member","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"handlers.memberUpsertReq":{"properties":{"role":{"example":"member","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"handlers.orgCreateReq":{"properties":{"domain":{"example":"acme.com","type":"string"},"name":{"example":"Acme Corp","type":"string"}},"type":"object"},"handlers.orgKeyCreateReq":{"properties":{"expires_in_hours":{"example":720,"type":"integer"},"name":{"example":"automation-bot","type":"string"}},"type":"object"},"handlers.orgKeyCreateResp":{"properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"org_key":{"description":"shown once:","type":"string"},"org_secret":{"description":"shown once:","type":"string"},"scope":{"description":"\"org\"","type":"string"}},"type":"object"},"handlers.orgUpdateReq":{"properties":{"domain":{"type":"string"},"name":{"type":"string"}},"type":"object"},"handlers.updateMeRequest":{"properties":{"display_name":{"type":"string"}},"type":"object"},"handlers.userAPIKeyOut":{"properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"format":"uuid","type":"string"},"last_used_at":{"type":"string"},"name":{"type":"string"},"plain":{"description":"Shown only on create:","type":"string"},"scope":{"description":"\"user\"","type":"string"}},"type":"object"},"models.APIKey":{"properties":{"cluster_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"is_ephemeral":{"type":"boolean"},"last_used_at":{"format":"date-time","type":"string"},"name":{"type":"string"},"org_id":{"format":"uuid","type":"string"},"prefix":{"type":"string"},"purpose":{"type":"string"},"revoked":{"type":"boolean"},"scope":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"models.Organization":{"properties":{"created_at":{"format":"date-time","type":"string"},"domain":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"name":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"models.User":{"properties":{"avatar_url":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"primary_email":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"models.UserEmail":{"properties":{"created_at":{"format":"date-time","type":"string"},"email":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_primary":{"type":"boolean"},"is_verified":{"type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/models.User"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"utils.ErrorResponse":{"properties":{"code":{"description":"A machine-readable error code, e.g. \"validation_error\"\nexample: validation_error","type":"string"},"message":{"description":"Human-readable message\nexample: slug is required","type":"string"}},"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"description":"User API key","in":"header","name":"X-API-KEY","type":"apiKey"},"BearerAuth":{"description":"Bearer token authentication","in":"header","name":"Authorization","type":"apiKey"},"OrgKeyAuth":{"description":"Org-level key/secret authentication","in":"header","name":"X-ORG-KEY","type":"apiKey"},"OrgSecretAuth":{"description":"Org-level secret","in":"header","name":"X-ORG-SECRET","type":"apiKey"}}}, "info": {"contact":{"name":"GlueOps"},"description":"{{escape .Description}}","title":"{{.Title}}","version":"{{.Version}}"}, "externalDocs": {"description":"","url":""}, - "paths": {"/.well-known/jwks.json":{"get":{"description":"Returns the JSON Web Key Set for token verification","operationId":"getJWKS","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.JWKS"}}},"description":"OK"}},"summary":"Get JWKS","tags":["Auth"]}},"/admin/archer/jobs":{"get":{"description":"Paginated background jobs with optional filters. Search ` + "`" + `q` + "`" + ` may match id, type, error, payload (implementation-dependent).","operationId":"AdminListArcherJobs","parameters":[{"description":"Filter by status","in":"query","name":"status","schema":{"enum":["queued","running","succeeded","failed","canceled","retrying","scheduled"],"type":"string"}},{"description":"Filter by queue name / worker name","in":"query","name":"queue","schema":{"type":"string"}},{"description":"Free-text search","in":"query","name":"q","schema":{"type":"string"}},{"description":"Page number","in":"query","name":"page","schema":{"default":1,"type":"integer"}},{"description":"Items per page","in":"query","name":"page_size","schema":{"default":25,"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.PageJob"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"List Archer jobs (admin)","tags":["ArcherAdmin"]},"post":{"description":"Create a job immediately or schedule it for the future via ` + "`" + `run_at` + "`" + `.","operationId":"AdminEnqueueArcherJob","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.EnqueueRequest"}}},"description":"Job parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json or missing fields"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"Enqueue a new Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/jobs/{id}/cancel":{"post":{"description":"Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill.","operationId":"AdminCancelArcherJob","parameters":[{"description":"Job ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid job or not cancellable"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]}],"summary":"Cancel an Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/jobs/{id}/retry":{"post":{"description":"Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one.","operationId":"AdminRetryArcherJob","parameters":[{"description":"Job ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid job or not eligible"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]}],"summary":"Retry a failed/canceled Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/queues":{"get":{"description":"Summary metrics per queue (pending, running, failed, scheduled).","operationId":"AdminListArcherQueues","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.QueueInfo"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"List Archer queues (admin)","tags":["ArcherAdmin"]}},"/annotations":{"get":{"description":"Returns annotations for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node pools.","operationId":"ListAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list annotations"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List annotations (org scoped)","tags":["Annotations"]},"post":{"description":"Creates an annotation.","operationId":"CreateAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateAnnotationRequest"}}},"description":"Annotation payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create annotation (org scoped)","tags":["Annotations"]}},"/annotations/{id}":{"delete":{"description":"Permanently deletes the annotation.","operationId":"DeleteAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete annotation (org scoped)","tags":["Annotations"]},"get":{"description":"Returns one annotation. Add ` + "`" + `include=node_pools` + "`" + ` to include node pools.","operationId":"GetAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get annotation by ID (org scoped)","tags":["Annotations"]},"patch":{"description":"Partially update annotation fields.","operationId":"UpdateAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateAnnotationRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update annotation (org scoped)","tags":["Annotations"]}},"/auth/logout":{"post":{"operationId":"Logout","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LogoutRequest"}}},"description":"Refresh token","required":true},"responses":{"204":{"description":"No Content"}},"summary":"Revoke refresh token family (logout everywhere)","tags":["Auth"]}},"/auth/refresh":{"post":{"operationId":"Refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RefreshRequest"}}},"description":"Refresh token","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TokenPair"}}},"description":"OK"}},"summary":"Rotate refresh token","tags":["Auth"]}},"/auth/{provider}/callback":{"get":{"operationId":"AuthCallback","parameters":[{"description":"google|github","in":"path","name":"provider","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TokenPair"}}},"description":"OK"}},"summary":"Handle social login callback","tags":["Auth"]}},"/auth/{provider}/start":{"post":{"description":"Returns provider authorization URL for the frontend to redirect","operationId":"AuthStart","parameters":[{"description":"google|github","in":"path","name":"provider","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AuthStartResponse"}}},"description":"OK"}},"summary":"Begin social login","tags":["Auth"]}},"/clusters":{"get":{"description":"Returns clusters for the organization in X-Org-ID. Filter by ` + "`" + `q` + "`" + ` (name contains).","operationId":"ListClusters","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Name contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ClusterResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List clusters (org scoped)","tags":["Clusters"]},"post":{"description":"Creates a cluster. Status is managed by the system and starts as ` + "`" + `pre_pending` + "`" + ` for validation.","operationId":"CreateCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateClusterRequest"}}},"description":"payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create cluster (org scoped)","tags":["Clusters"]}},"/clusters/{clusterID}":{"delete":{"description":"Deletes the cluster. Related resources are cleaned up via DB constraints (e.g. CASCADE).","operationId":"DeleteCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"deleted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a cluster (org scoped)","tags":["Clusters"]},"get":{"description":"Returns a cluster with all related resources (domain, record set, load balancers, bastion, node pools).","operationId":"GetCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a single cluster by ID (org scoped)","tags":["Clusters"]},"patch":{"description":"Updates the cluster name, provider, and/or region. Status is managed by the system.","operationId":"UpdateCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateClusterRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update basic cluster details (org scoped)","tags":["Clusters"]}},"/clusters/{clusterID}/apps-load-balancer":{"delete":{"description":"Clears apps_load_balancer_id on the cluster.","operationId":"DetachAppsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the apps load balancer from a cluster","tags":["Clusters"]},"post":{"description":"Sets apps_load_balancer_id on the cluster.","operationId":"AttachAppsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLoadBalancerRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or load balancer not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach an apps load balancer to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/bastion":{"delete":{"description":"Clears bastion_server_id on the cluster.","operationId":"DetachBastionServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the bastion server from a cluster","tags":["Clusters"]},"post":{"description":"Sets bastion_server_id on the cluster.","operationId":"AttachBastionServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachBastionRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or server not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a bastion server to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/captain-domain":{"delete":{"description":"Clears captain_domain_id on the cluster. This will likely cause the cluster to become incomplete.","operationId":"DetachCaptainDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the captain domain from a cluster","tags":["Clusters"]},"post":{"description":"Sets captain_domain_id on the cluster. Validation of shape happens asynchronously.","operationId":"AttachCaptainDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachCaptainDomainRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or domain not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a captain domain to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/control-plane-record-set":{"delete":{"description":"Clears control_plane_record_set_id on the cluster.","operationId":"DetachControlPlaneRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the control plane record set from a cluster","tags":["Clusters"]},"post":{"description":"Sets control_plane_record_set_id on the cluster.","operationId":"AttachControlPlaneRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachRecordSetRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or record set not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a control plane record set to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/glueops-load-balancer":{"delete":{"description":"Clears glueops_load_balancer_id on the cluster.","operationId":"DetachGlueOpsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the GlueOps/control-plane load balancer from a cluster","tags":["Clusters"]},"post":{"description":"Sets glueops_load_balancer_id on the cluster.","operationId":"AttachGlueOpsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLoadBalancerRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or load balancer not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a GlueOps/control-plane load balancer to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/kubeconfig":{"delete":{"description":"Removes the encrypted kubeconfig, IV, and tag from the cluster record.","operationId":"ClearClusterKubeconfig","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Clear the kubeconfig for a cluster","tags":["Clusters"]},"post":{"description":"Stores the kubeconfig encrypted per organization. The kubeconfig is never returned in responses.","operationId":"SetClusterKubeconfig","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.SetKubeconfigRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Set (or replace) the kubeconfig for a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/node-pools":{"post":{"description":"Adds an entry in the cluster_node_pools join table.","operationId":"AttachNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachNodePoolRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or node pool not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a node pool to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/node-pools/{nodePoolID}":{"delete":{"description":"Removes an entry from the cluster_node_pools join table.","operationId":"DetachNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}},{"description":"Node Pool ID","in":"path","name":"nodePoolID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or node pool not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach a node pool from a cluster","tags":["Clusters"]}},"/credentials":{"get":{"description":"Returns credential metadata for the current org. Secrets are never returned.","operationId":"ListCredentials","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Filter by provider (e.g., aws)","in":"query","name":"credential_provider","schema":{"type":"string"}},{"description":"Filter by kind (e.g., aws_access_key)","in":"query","name":"kind","schema":{"type":"string"}},{"description":"Filter by scope kind (credential_provider/service/resource)","in":"query","name":"scope_kind","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.CredentialOut"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List credentials (metadata only)","tags":["Credentials"]},"post":{"operationId":"CreateCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateCredentialRequest"}}},"description":"Credential payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"Created"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a credential (encrypts secret)","tags":["Credentials"]}},"/credentials/{id}":{"delete":{"operationId":"DeleteCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete credential","tags":["Credentials"]},"get":{"operationId":"GetCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get credential by ID (metadata only)","tags":["Credentials"]},"patch":{"operationId":"UpdateCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateCredentialRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"X-Org-ID required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update credential metadata and/or rotate secret","tags":["Credentials"]}},"/credentials/{id}/reveal":{"post":{"operationId":"RevealCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Reveal decrypted secret (one-time read)","tags":["Credentials"]}},"/dns/domains":{"get":{"description":"Returns domains for X-Org-ID. Filters: ` + "`" + `domain_name` + "`" + `, ` + "`" + `status` + "`" + `, ` + "`" + `q` + "`" + ` (contains).","operationId":"ListDomains","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact domain name (lowercase, no trailing dot)","in":"query","name":"domain_name","schema":{"type":"string"}},{"description":"pending|provisioning|ready|failed","in":"query","name":"status","schema":{"type":"string"}},{"description":"Domain contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.DomainResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List domains (org scoped)","tags":["DNS"]},"post":{"description":"Creates a domain bound to a Route 53 scoped credential. Archer will backfill ZoneID if omitted.","operationId":"CreateDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateDomainRequest"}}},"description":"Domain payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a domain (org scoped)","tags":["DNS"]}},"/dns/domains/{domain_id}/records":{"get":{"description":"Filters: ` + "`" + `name` + "`" + `, ` + "`" + `type` + "`" + `, ` + "`" + `status` + "`" + `.","operationId":"ListRecordSets","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"domain_id","required":true,"schema":{"type":"string"}},{"description":"Exact relative name or FQDN (server normalizes)","in":"query","name":"name","schema":{"type":"string"}},{"description":"RR type (A, AAAA, CNAME, TXT, MX, NS, SRV, CAA)","in":"query","name":"type","schema":{"type":"string"}},{"description":"pending|provisioning|ready|failed","in":"query","name":"status","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.RecordSetResponse"},"type":"array"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List record sets for a domain","tags":["DNS"]},"post":{"operationId":"CreateRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"domain_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateRecordSetRequest"}}},"description":"Record set payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RecordSetResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a record set (pending; Archer will UPSERT to Route 53)","tags":["DNS"]}},"/dns/domains/{id}":{"delete":{"operationId":"DeleteDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a domain","tags":["DNS"]},"get":{"operationId":"GetDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a domain (org scoped)","tags":["DNS"]},"patch":{"operationId":"UpdateDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateDomainRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a domain (org scoped)","tags":["DNS"]}},"/dns/records/{id}":{"delete":{"operationId":"DeleteRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Record Set ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a record set (API removes row; worker can optionally handle external deletion policy)","tags":["DNS"]},"patch":{"operationId":"UpdateRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Record Set ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateRecordSetRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RecordSetResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a record set (flips to pending for reconciliation)","tags":["DNS"]}},"/healthz":{"get":{"description":"Returns 200 OK when the service is up","operationId":"HealthCheck // operationId","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.HealthStatus"}}},"description":"OK"}},"summary":"Basic health check","tags":["Health"]}},"/labels":{"get":{"description":"Returns node labels for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node groups.","operationId":"ListLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"Key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node taints"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node labels (org scoped)","tags":["Labels"]},"post":{"description":"Creates a label.","operationId":"CreateLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateLabelRequest"}}},"description":"Label payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid node_pool_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create label (org scoped)","tags":["Labels"]}},"/labels/{id}":{"delete":{"description":"Permanently deletes the label.","operationId":"DeleteLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete label (org scoped)","tags":["Labels"]},"get":{"description":"Returns one label.","operationId":"GetLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get label by ID (org scoped)","tags":["Labels"]},"patch":{"description":"Partially update label fields.","operationId":"UpdateLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateLabelRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update label (org scoped)","tags":["Labels"]}},"/load-balancers":{"get":{"description":"Returns load balancers for the organization in X-Org-ID.","operationId":"ListLoadBalancers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List load balancers (org scoped)","tags":["LoadBalancers"]},"post":{"operationId":"CreateLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateLoadBalancerRequest"}}},"description":"Record set payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a load balancer","tags":["LoadBalancers"]}},"/load-balancers/{id}":{"delete":{"operationId":"DeleteLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Load Balancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a load balancer","tags":["LoadBalancers"]},"get":{"description":"Returns load balancer for the organization in X-Org-ID.","operationId":"GetLoadBalancers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"LoadBalancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a load balancer (org scoped)","tags":["LoadBalancers"]},"patch":{"operationId":"UpdateLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Load Balancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateLoadBalancerRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a load balancer (org scoped)","tags":["LoadBalancers"]}},"/me":{"get":{"operationId":"GetMe","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.meResponse"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get current user profile","tags":["Me"]},"patch":{"operationId":"UpdateMe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.updateMeRequest"}}},"description":"Patch profile","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.User"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Update current user profile","tags":["Me"]}},"/me/api-keys":{"get":{"operationId":"ListUserAPIKeys","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/handlers.userAPIKeyOut"},"type":"array"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"List my API keys","tags":["MeAPIKeys"]},"post":{"description":"Returns the plaintext key once. Store it securely on the client side.","operationId":"CreateUserAPIKey","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.createUserKeyRequest"}}},"description":"Key options","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.userAPIKeyOut"}}},"description":"Created"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Create a new user API key","tags":["MeAPIKeys"]}},"/me/api-keys/{id}":{"delete":{"operationId":"DeleteUserAPIKey","parameters":[{"description":"Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"}},"security":[{"BearerAuth":[]}],"summary":"Delete a user API key","tags":["MeAPIKeys"]}},"/node-pools":{"get":{"description":"Returns node pools for the organization in X-Org-ID.","operationId":"ListNodePools","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Name contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.NodePoolResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node pools"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node pools (org scoped)","tags":["NodePools"]},"post":{"description":"Creates a node pool. Optionally attach initial servers.","operationId":"CreateNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateNodePoolRequest"}}},"description":"NodePool payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}":{"delete":{"description":"Permanently deletes the node pool.","operationId":"DeleteNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete node pool (org scoped)","tags":["NodePools"]},"get":{"description":"Returns one node pool. Add ` + "`" + `include=servers` + "`" + ` to include servers.","operationId":"GetNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get node pool by ID (org scoped)","tags":["NodePools"]},"patch":{"description":"Partially update node pool fields.","operationId":"UpdateNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateNodePoolRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/annotations":{"get":{"operationId":"ListNodePoolAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List annotations attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Group ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachAnnotationsRequest"}}},"description":"Annotation IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach annotation to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/annotations/{annotationId}":{"delete":{"operationId":"DetachNodePoolAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"annotationId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one annotation from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/labels":{"get":{"operationId":"ListNodePoolLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List labels attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLabelsRequest"}}},"description":"Label IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach labels to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/labels/{labelId}":{"delete":{"operationId":"DetachNodePoolLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"labelId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one label from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/servers":{"get":{"operationId":"ListNodePoolServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List servers attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachServersRequest"}}},"description":"Server IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach servers to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/servers/{serverId}":{"delete":{"operationId":"DetachNodePoolServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"serverId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one server from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/taints":{"get":{"operationId":"ListNodePoolTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List taints attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachTaintsRequest"}}},"description":"Taint IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid taint_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach taints to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/taints/{taintId}":{"delete":{"operationId":"DetachNodePoolTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Taint ID (UUID)","in":"path","name":"taintId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one taint from a node pool (org scoped)","tags":["NodePools"]}},"/orgs":{"get":{"operationId":"listMyOrgs","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.Organization"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List organizations I belong to","tags":["Orgs"]},"post":{"operationId":"createOrg","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgCreateReq"}}},"description":"Org payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Conflict"}},"security":[{"BearerAuth":[]}],"summary":"Create organization","tags":["Orgs"]}},"/orgs/{id}":{"delete":{"operationId":"deleteOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Delete organization (owner)","tags":["Orgs"]},"get":{"operationId":"getOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Get organization","tags":["Orgs"]},"patch":{"operationId":"updateOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgUpdateReq"}}},"description":"Update payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Update organization (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/api-keys":{"get":{"operationId":"listOrgKeys","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.APIKey"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List org-scoped API keys (no secrets)","tags":["Orgs"]},"post":{"operationId":"createOrgKey","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgKeyCreateReq"}}},"description":"Key name + optional expiry","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgKeyCreateResp"}}},"description":"Created"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Create org key/secret pair (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/api-keys/{key_id}":{"delete":{"operationId":"deleteOrgKey","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Key ID (UUID)","in":"path","name":"key_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Delete org key (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/members":{"get":{"operationId":"listMembers","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/handlers.memberOut"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List members in org","tags":["Orgs"]},"post":{"operationId":"addOrUpdateMember","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.memberUpsertReq"}}},"description":"User \u0026 role","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.memberOut"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Add or update a member (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/members/{user_id}":{"delete":{"operationId":"removeMember","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"User ID (UUID)","in":"path","name":"user_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Remove a member (owner/admin)","tags":["Orgs"]}},"/servers":{"get":{"description":"Returns servers for the organization in X-Org-ID. Optional filters: status, role.","operationId":"ListServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Filter by status (pending|provisioning|ready|failed)","in":"query","name":"status","schema":{"type":"string"}},{"description":"Filter by role","in":"query","name":"role","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list servers"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List servers (org scoped)","tags":["Servers"]},"post":{"description":"Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org.","operationId":"CreateServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateServerRequest"}}},"description":"Server payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid status / invalid ssh_key_id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create server (org scoped)","tags":["Servers"]}},"/servers/{id}":{"delete":{"description":"Permanently deletes the server.","operationId":"DeleteServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete server (org scoped)","tags":["Servers"]},"get":{"description":"Returns one server in the given organization.","operationId":"GetServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get server by ID (org scoped)","tags":["Servers"]},"patch":{"description":"Partially update fields; changing ssh_key_id validates ownership.","operationId":"UpdateServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateServerRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json / invalid status / invalid ssh_key_id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update server (org scoped)","tags":["Servers"]}},"/servers/{id}/reset-hostkey":{"post":{"description":"Clears the stored SSH host key for this server. The next SSH connection will re-learn the host key (trust-on-first-use).","operationId":"ResetServerHostKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"reset failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Reset SSH host key (org scoped)","tags":["Servers"]}},"/ssh":{"get":{"description":"Returns ssh keys for the organization in X-Org-ID.","operationId":"ListPublicSshKeys","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.SshResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list keys"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List ssh keys (org scoped)","tags":["Ssh"]},"post":{"description":"Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits.","operationId":"CreateSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateSSHRequest"}}},"description":"Key generation options","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.SshResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / invalid bits"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"generation/create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create ssh keypair (org scoped)","tags":["Ssh"]}},"/ssh/{id}":{"delete":{"description":"Permanently deletes a keypair.","operationId":"DeleteSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete ssh keypair (org scoped)","tags":["Ssh"]},"get":{"description":"Returns public key fields. Append ` + "`" + `?reveal=true` + "`" + ` to include the private key PEM.","operationId":"GetSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Reveal private key PEM","in":"query","name":"reveal","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/dto.SshResponse"},{"$ref":"#/components/schemas/dto.SshRevealResponse"}]}}},"description":"When reveal=true"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get ssh key by ID (org scoped)","tags":["Ssh"]}},"/ssh/{id}/download":{"get":{"description":"Download ` + "`" + `part=public|private|both` + "`" + ` of the keypair. ` + "`" + `both` + "`" + ` returns a zip file.","operationId":"DownloadSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","required":true,"schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Which part to download","in":"query","name":"part","required":true,"schema":{"enum":["public","private","both"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"file content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid part"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"download failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Download ssh key files by ID (org scoped)","tags":["Ssh"]}},"/taints":{"get":{"description":"Returns node taints for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node pools.","operationId":"ListTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node taints"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node pool taints (org scoped)","tags":["Taints"]},"post":{"description":"Creates a taint.","operationId":"CreateTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateTaintRequest"}}},"description":"Taint payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid node_pool_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create node taint (org scoped)","tags":["Taints"]}},"/taints/{id}":{"delete":{"description":"Permanently deletes the taint.","operationId":"DeleteTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete taint (org scoped)","tags":["Taints"]},"get":{"operationId":"GetTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get node taint by ID (org scoped)","tags":["Taints"]},"patch":{"description":"Partially update taint fields.","operationId":"UpdateTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateTaintRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update node taint (org scoped)","tags":["Taints"]}},"/version":{"get":{"description":"Returns build/runtime metadata for the running service.","operationId":"Version // operationId","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.VersionResponse"}}},"description":"OK"}},"summary":"Service version information","tags":["Meta"]}}}, + "paths": {"/.well-known/jwks.json":{"get":{"description":"Returns the JSON Web Key Set for token verification","operationId":"getJWKS","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.JWKS"}}},"description":"OK"}},"summary":"Get JWKS","tags":["Auth"]}},"/admin/actions":{"get":{"description":"Returns all admin-configured actions.","operationId":"ListActions","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ActionResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"List available actions","tags":["Actions"]},"post":{"description":"Creates a new admin-configured action.","operationId":"CreateAction","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateActionRequest"}}},"description":"payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ActionResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"Create an action","tags":["Actions"]}},"/admin/actions/{actionID}":{"delete":{"description":"Deletes an action.","operationId":"DeleteAction","parameters":[{"description":"Action ID","in":"path","name":"actionID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"deleted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"Delete an action","tags":["Actions"]},"get":{"description":"Returns a single action.","operationId":"GetAction","parameters":[{"description":"Action ID","in":"path","name":"actionID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ActionResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"Get a single action by ID","tags":["Actions"]},"patch":{"description":"Updates an action. Only provided fields are modified.","operationId":"UpdateAction","parameters":[{"description":"Action ID","in":"path","name":"actionID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateActionRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ActionResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"Update an action","tags":["Actions"]}},"/admin/archer/jobs":{"get":{"description":"Paginated background jobs with optional filters. Search ` + "`" + `q` + "`" + ` may match id, type, error, payload (implementation-dependent).","operationId":"AdminListArcherJobs","parameters":[{"description":"Filter by status","in":"query","name":"status","schema":{"enum":["queued","running","succeeded","failed","canceled","retrying","scheduled"],"type":"string"}},{"description":"Filter by queue name / worker name","in":"query","name":"queue","schema":{"type":"string"}},{"description":"Free-text search","in":"query","name":"q","schema":{"type":"string"}},{"description":"Page number","in":"query","name":"page","schema":{"default":1,"type":"integer"}},{"description":"Items per page","in":"query","name":"page_size","schema":{"default":25,"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.PageJob"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"List Archer jobs (admin)","tags":["ArcherAdmin"]},"post":{"description":"Create a job immediately or schedule it for the future via ` + "`" + `run_at` + "`" + `.","operationId":"AdminEnqueueArcherJob","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.EnqueueRequest"}}},"description":"Job parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json or missing fields"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"Enqueue a new Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/jobs/{id}/cancel":{"post":{"description":"Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill.","operationId":"AdminCancelArcherJob","parameters":[{"description":"Job ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid job or not cancellable"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]}],"summary":"Cancel an Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/jobs/{id}/retry":{"post":{"description":"Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one.","operationId":"AdminRetryArcherJob","parameters":[{"description":"Job ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid job or not eligible"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]}],"summary":"Retry a failed/canceled Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/queues":{"get":{"description":"Summary metrics per queue (pending, running, failed, scheduled).","operationId":"AdminListArcherQueues","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.QueueInfo"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"List Archer queues (admin)","tags":["ArcherAdmin"]}},"/annotations":{"get":{"description":"Returns annotations for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node pools.","operationId":"ListAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list annotations"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List annotations (org scoped)","tags":["Annotations"]},"post":{"description":"Creates an annotation.","operationId":"CreateAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateAnnotationRequest"}}},"description":"Annotation payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create annotation (org scoped)","tags":["Annotations"]}},"/annotations/{id}":{"delete":{"description":"Permanently deletes the annotation.","operationId":"DeleteAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete annotation (org scoped)","tags":["Annotations"]},"get":{"description":"Returns one annotation. Add ` + "`" + `include=node_pools` + "`" + ` to include node pools.","operationId":"GetAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get annotation by ID (org scoped)","tags":["Annotations"]},"patch":{"description":"Partially update annotation fields.","operationId":"UpdateAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateAnnotationRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update annotation (org scoped)","tags":["Annotations"]}},"/auth/logout":{"post":{"operationId":"Logout","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LogoutRequest"}}},"description":"Refresh token","required":true},"responses":{"204":{"description":"No Content"}},"summary":"Revoke refresh token family (logout everywhere)","tags":["Auth"]}},"/auth/refresh":{"post":{"operationId":"Refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RefreshRequest"}}},"description":"Refresh token","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TokenPair"}}},"description":"OK"}},"summary":"Rotate refresh token","tags":["Auth"]}},"/auth/{provider}/callback":{"get":{"operationId":"AuthCallback","parameters":[{"description":"google|github","in":"path","name":"provider","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TokenPair"}}},"description":"OK"}},"summary":"Handle social login callback","tags":["Auth"]}},"/auth/{provider}/start":{"post":{"description":"Returns provider authorization URL for the frontend to redirect","operationId":"AuthStart","parameters":[{"description":"google|github","in":"path","name":"provider","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AuthStartResponse"}}},"description":"OK"}},"summary":"Begin social login","tags":["Auth"]}},"/clusters":{"get":{"description":"Returns clusters for the organization in X-Org-ID. Filter by ` + "`" + `q` + "`" + ` (name contains).","operationId":"ListClusters","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Name contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ClusterResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List clusters (org scoped)","tags":["Clusters"]},"post":{"description":"Creates a cluster. Status is managed by the system and starts as ` + "`" + `pre_pending` + "`" + ` for validation.","operationId":"CreateCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateClusterRequest"}}},"description":"payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create cluster (org scoped)","tags":["Clusters"]}},"/clusters/{clusterID}":{"delete":{"description":"Deletes the cluster. Related resources are cleaned up via DB constraints (e.g. CASCADE).","operationId":"DeleteCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"deleted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a cluster (org scoped)","tags":["Clusters"]},"get":{"description":"Returns a cluster with all related resources (domain, record set, load balancers, bastion, node pools).","operationId":"GetCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a single cluster by ID (org scoped)","tags":["Clusters"]},"patch":{"description":"Updates the cluster name, provider, and/or region. Status is managed by the system.","operationId":"UpdateCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateClusterRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update basic cluster details (org scoped)","tags":["Clusters"]}},"/clusters/{clusterID}/actions/{actionID}/runs":{"post":{"description":"Creates a ClusterRun record for the cluster/action. Execution is handled asynchronously by workers.","operationId":"RunClusterAction","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}},{"description":"Action ID","in":"path","name":"actionID","required":true,"schema":{"type":"string"}}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterRunResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or action not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Run an admin-configured action on a cluster (org scoped)","tags":["ClusterRuns"]}},"/clusters/{clusterID}/apps-load-balancer":{"delete":{"description":"Clears apps_load_balancer_id on the cluster.","operationId":"DetachAppsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the apps load balancer from a cluster","tags":["Clusters"]},"post":{"description":"Sets apps_load_balancer_id on the cluster.","operationId":"AttachAppsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLoadBalancerRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or load balancer not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach an apps load balancer to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/bastion":{"delete":{"description":"Clears bastion_server_id on the cluster.","operationId":"DetachBastionServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the bastion server from a cluster","tags":["Clusters"]},"post":{"description":"Sets bastion_server_id on the cluster.","operationId":"AttachBastionServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachBastionRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or server not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a bastion server to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/captain-domain":{"delete":{"description":"Clears captain_domain_id on the cluster. This will likely cause the cluster to become incomplete.","operationId":"DetachCaptainDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the captain domain from a cluster","tags":["Clusters"]},"post":{"description":"Sets captain_domain_id on the cluster. Validation of shape happens asynchronously.","operationId":"AttachCaptainDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachCaptainDomainRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or domain not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a captain domain to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/control-plane-record-set":{"delete":{"description":"Clears control_plane_record_set_id on the cluster.","operationId":"DetachControlPlaneRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the control plane record set from a cluster","tags":["Clusters"]},"post":{"description":"Sets control_plane_record_set_id on the cluster.","operationId":"AttachControlPlaneRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachRecordSetRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or record set not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a control plane record set to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/glueops-load-balancer":{"delete":{"description":"Clears glueops_load_balancer_id on the cluster.","operationId":"DetachGlueOpsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the GlueOps/control-plane load balancer from a cluster","tags":["Clusters"]},"post":{"description":"Sets glueops_load_balancer_id on the cluster.","operationId":"AttachGlueOpsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLoadBalancerRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or load balancer not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a GlueOps/control-plane load balancer to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/kubeconfig":{"delete":{"description":"Removes the encrypted kubeconfig, IV, and tag from the cluster record.","operationId":"ClearClusterKubeconfig","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Clear the kubeconfig for a cluster","tags":["Clusters"]},"post":{"description":"Stores the kubeconfig encrypted per organization. The kubeconfig is never returned in responses.","operationId":"SetClusterKubeconfig","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.SetKubeconfigRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Set (or replace) the kubeconfig for a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/node-pools":{"post":{"description":"Adds an entry in the cluster_node_pools join table.","operationId":"AttachNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachNodePoolRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or node pool not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a node pool to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/node-pools/{nodePoolID}":{"delete":{"description":"Removes an entry from the cluster_node_pools join table.","operationId":"DetachNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}},{"description":"Node Pool ID","in":"path","name":"nodePoolID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or node pool not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach a node pool from a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/runs":{"get":{"description":"Returns runs for a cluster within the organization in X-Org-ID.","operationId":"ListClusterRuns","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ClusterRunResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List cluster runs (org scoped)","tags":["ClusterRuns"]}},"/clusters/{clusterID}/runs/{runID}":{"get":{"description":"Returns a single run for a cluster within the organization in X-Org-ID.","operationId":"GetClusterRun","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}},{"description":"Run ID","in":"path","name":"runID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterRunResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a cluster run (org scoped)","tags":["ClusterRuns"]}},"/credentials":{"get":{"description":"Returns credential metadata for the current org. Secrets are never returned.","operationId":"ListCredentials","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Filter by provider (e.g., aws)","in":"query","name":"credential_provider","schema":{"type":"string"}},{"description":"Filter by kind (e.g., aws_access_key)","in":"query","name":"kind","schema":{"type":"string"}},{"description":"Filter by scope kind (credential_provider/service/resource)","in":"query","name":"scope_kind","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.CredentialOut"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List credentials (metadata only)","tags":["Credentials"]},"post":{"operationId":"CreateCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateCredentialRequest"}}},"description":"Credential payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"Created"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a credential (encrypts secret)","tags":["Credentials"]}},"/credentials/{id}":{"delete":{"operationId":"DeleteCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete credential","tags":["Credentials"]},"get":{"operationId":"GetCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get credential by ID (metadata only)","tags":["Credentials"]},"patch":{"operationId":"UpdateCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateCredentialRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"X-Org-ID required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update credential metadata and/or rotate secret","tags":["Credentials"]}},"/credentials/{id}/reveal":{"post":{"operationId":"RevealCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Reveal decrypted secret (one-time read)","tags":["Credentials"]}},"/dns/domains":{"get":{"description":"Returns domains for X-Org-ID. Filters: ` + "`" + `domain_name` + "`" + `, ` + "`" + `status` + "`" + `, ` + "`" + `q` + "`" + ` (contains).","operationId":"ListDomains","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact domain name (lowercase, no trailing dot)","in":"query","name":"domain_name","schema":{"type":"string"}},{"description":"pending|provisioning|ready|failed","in":"query","name":"status","schema":{"type":"string"}},{"description":"Domain contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.DomainResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List domains (org scoped)","tags":["DNS"]},"post":{"description":"Creates a domain bound to a Route 53 scoped credential. Archer will backfill ZoneID if omitted.","operationId":"CreateDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateDomainRequest"}}},"description":"Domain payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a domain (org scoped)","tags":["DNS"]}},"/dns/domains/{domain_id}/records":{"get":{"description":"Filters: ` + "`" + `name` + "`" + `, ` + "`" + `type` + "`" + `, ` + "`" + `status` + "`" + `.","operationId":"ListRecordSets","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"domain_id","required":true,"schema":{"type":"string"}},{"description":"Exact relative name or FQDN (server normalizes)","in":"query","name":"name","schema":{"type":"string"}},{"description":"RR type (A, AAAA, CNAME, TXT, MX, NS, SRV, CAA)","in":"query","name":"type","schema":{"type":"string"}},{"description":"pending|provisioning|ready|failed","in":"query","name":"status","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.RecordSetResponse"},"type":"array"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List record sets for a domain","tags":["DNS"]},"post":{"operationId":"CreateRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"domain_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateRecordSetRequest"}}},"description":"Record set payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RecordSetResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a record set (pending; Archer will UPSERT to Route 53)","tags":["DNS"]}},"/dns/domains/{id}":{"delete":{"operationId":"DeleteDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a domain","tags":["DNS"]},"get":{"operationId":"GetDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a domain (org scoped)","tags":["DNS"]},"patch":{"operationId":"UpdateDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateDomainRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a domain (org scoped)","tags":["DNS"]}},"/dns/records/{id}":{"delete":{"operationId":"DeleteRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Record Set ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a record set (API removes row; worker can optionally handle external deletion policy)","tags":["DNS"]},"patch":{"operationId":"UpdateRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Record Set ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateRecordSetRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RecordSetResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a record set (flips to pending for reconciliation)","tags":["DNS"]}},"/healthz":{"get":{"description":"Returns 200 OK when the service is up","operationId":"HealthCheck // operationId","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.HealthStatus"}}},"description":"OK"}},"summary":"Basic health check","tags":["Health"]}},"/labels":{"get":{"description":"Returns node labels for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node groups.","operationId":"ListLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"Key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node taints"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node labels (org scoped)","tags":["Labels"]},"post":{"description":"Creates a label.","operationId":"CreateLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateLabelRequest"}}},"description":"Label payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid node_pool_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create label (org scoped)","tags":["Labels"]}},"/labels/{id}":{"delete":{"description":"Permanently deletes the label.","operationId":"DeleteLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete label (org scoped)","tags":["Labels"]},"get":{"description":"Returns one label.","operationId":"GetLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get label by ID (org scoped)","tags":["Labels"]},"patch":{"description":"Partially update label fields.","operationId":"UpdateLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateLabelRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update label (org scoped)","tags":["Labels"]}},"/load-balancers":{"get":{"description":"Returns load balancers for the organization in X-Org-ID.","operationId":"ListLoadBalancers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List load balancers (org scoped)","tags":["LoadBalancers"]},"post":{"operationId":"CreateLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateLoadBalancerRequest"}}},"description":"Record set payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a load balancer","tags":["LoadBalancers"]}},"/load-balancers/{id}":{"delete":{"operationId":"DeleteLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Load Balancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a load balancer","tags":["LoadBalancers"]},"get":{"description":"Returns load balancer for the organization in X-Org-ID.","operationId":"GetLoadBalancers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"LoadBalancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a load balancer (org scoped)","tags":["LoadBalancers"]},"patch":{"operationId":"UpdateLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Load Balancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateLoadBalancerRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a load balancer (org scoped)","tags":["LoadBalancers"]}},"/me":{"get":{"operationId":"GetMe","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.meResponse"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get current user profile","tags":["Me"]},"patch":{"operationId":"UpdateMe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.updateMeRequest"}}},"description":"Patch profile","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.User"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Update current user profile","tags":["Me"]}},"/me/api-keys":{"get":{"operationId":"ListUserAPIKeys","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/handlers.userAPIKeyOut"},"type":"array"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"List my API keys","tags":["MeAPIKeys"]},"post":{"description":"Returns the plaintext key once. Store it securely on the client side.","operationId":"CreateUserAPIKey","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.createUserKeyRequest"}}},"description":"Key options","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.userAPIKeyOut"}}},"description":"Created"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Create a new user API key","tags":["MeAPIKeys"]}},"/me/api-keys/{id}":{"delete":{"operationId":"DeleteUserAPIKey","parameters":[{"description":"Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"}},"security":[{"BearerAuth":[]}],"summary":"Delete a user API key","tags":["MeAPIKeys"]}},"/node-pools":{"get":{"description":"Returns node pools for the organization in X-Org-ID.","operationId":"ListNodePools","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Name contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.NodePoolResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node pools"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node pools (org scoped)","tags":["NodePools"]},"post":{"description":"Creates a node pool. Optionally attach initial servers.","operationId":"CreateNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateNodePoolRequest"}}},"description":"NodePool payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}":{"delete":{"description":"Permanently deletes the node pool.","operationId":"DeleteNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete node pool (org scoped)","tags":["NodePools"]},"get":{"description":"Returns one node pool. Add ` + "`" + `include=servers` + "`" + ` to include servers.","operationId":"GetNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get node pool by ID (org scoped)","tags":["NodePools"]},"patch":{"description":"Partially update node pool fields.","operationId":"UpdateNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateNodePoolRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/annotations":{"get":{"operationId":"ListNodePoolAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List annotations attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Group ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachAnnotationsRequest"}}},"description":"Annotation IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach annotation to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/annotations/{annotationId}":{"delete":{"operationId":"DetachNodePoolAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"annotationId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one annotation from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/labels":{"get":{"operationId":"ListNodePoolLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List labels attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLabelsRequest"}}},"description":"Label IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach labels to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/labels/{labelId}":{"delete":{"operationId":"DetachNodePoolLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"labelId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one label from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/servers":{"get":{"operationId":"ListNodePoolServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List servers attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachServersRequest"}}},"description":"Server IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach servers to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/servers/{serverId}":{"delete":{"operationId":"DetachNodePoolServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"serverId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one server from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/taints":{"get":{"operationId":"ListNodePoolTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List taints attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachTaintsRequest"}}},"description":"Taint IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid taint_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach taints to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/taints/{taintId}":{"delete":{"operationId":"DetachNodePoolTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Taint ID (UUID)","in":"path","name":"taintId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one taint from a node pool (org scoped)","tags":["NodePools"]}},"/orgs":{"get":{"operationId":"listMyOrgs","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.Organization"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List organizations I belong to","tags":["Orgs"]},"post":{"operationId":"createOrg","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgCreateReq"}}},"description":"Org payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Conflict"}},"security":[{"BearerAuth":[]}],"summary":"Create organization","tags":["Orgs"]}},"/orgs/{id}":{"delete":{"operationId":"deleteOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Delete organization (owner)","tags":["Orgs"]},"get":{"operationId":"getOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Get organization","tags":["Orgs"]},"patch":{"operationId":"updateOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgUpdateReq"}}},"description":"Update payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Update organization (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/api-keys":{"get":{"operationId":"listOrgKeys","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.APIKey"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List org-scoped API keys (no secrets)","tags":["Orgs"]},"post":{"operationId":"createOrgKey","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgKeyCreateReq"}}},"description":"Key name + optional expiry","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgKeyCreateResp"}}},"description":"Created"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Create org key/secret pair (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/api-keys/{key_id}":{"delete":{"operationId":"deleteOrgKey","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Key ID (UUID)","in":"path","name":"key_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Delete org key (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/members":{"get":{"operationId":"listMembers","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/handlers.memberOut"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List members in org","tags":["Orgs"]},"post":{"operationId":"addOrUpdateMember","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.memberUpsertReq"}}},"description":"User \u0026 role","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.memberOut"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Add or update a member (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/members/{user_id}":{"delete":{"operationId":"removeMember","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"User ID (UUID)","in":"path","name":"user_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Remove a member (owner/admin)","tags":["Orgs"]}},"/servers":{"get":{"description":"Returns servers for the organization in X-Org-ID. Optional filters: status, role.","operationId":"ListServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Filter by status (pending|provisioning|ready|failed)","in":"query","name":"status","schema":{"type":"string"}},{"description":"Filter by role","in":"query","name":"role","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list servers"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List servers (org scoped)","tags":["Servers"]},"post":{"description":"Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org.","operationId":"CreateServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateServerRequest"}}},"description":"Server payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid status / invalid ssh_key_id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create server (org scoped)","tags":["Servers"]}},"/servers/{id}":{"delete":{"description":"Permanently deletes the server.","operationId":"DeleteServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete server (org scoped)","tags":["Servers"]},"get":{"description":"Returns one server in the given organization.","operationId":"GetServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get server by ID (org scoped)","tags":["Servers"]},"patch":{"description":"Partially update fields; changing ssh_key_id validates ownership.","operationId":"UpdateServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateServerRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json / invalid status / invalid ssh_key_id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update server (org scoped)","tags":["Servers"]}},"/servers/{id}/reset-hostkey":{"post":{"description":"Clears the stored SSH host key for this server. The next SSH connection will re-learn the host key (trust-on-first-use).","operationId":"ResetServerHostKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"reset failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Reset SSH host key (org scoped)","tags":["Servers"]}},"/ssh":{"get":{"description":"Returns ssh keys for the organization in X-Org-ID.","operationId":"ListPublicSshKeys","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.SshResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list keys"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List ssh keys (org scoped)","tags":["Ssh"]},"post":{"description":"Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits.","operationId":"CreateSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateSSHRequest"}}},"description":"Key generation options","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.SshResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / invalid bits"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"generation/create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create ssh keypair (org scoped)","tags":["Ssh"]}},"/ssh/{id}":{"delete":{"description":"Permanently deletes a keypair.","operationId":"DeleteSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete ssh keypair (org scoped)","tags":["Ssh"]},"get":{"description":"Returns public key fields. Append ` + "`" + `?reveal=true` + "`" + ` to include the private key PEM.","operationId":"GetSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Reveal private key PEM","in":"query","name":"reveal","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/dto.SshResponse"},{"$ref":"#/components/schemas/dto.SshRevealResponse"}]}}},"description":"When reveal=true"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get ssh key by ID (org scoped)","tags":["Ssh"]}},"/ssh/{id}/download":{"get":{"description":"Download ` + "`" + `part=public|private|both` + "`" + ` of the keypair. ` + "`" + `both` + "`" + ` returns a zip file.","operationId":"DownloadSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","required":true,"schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Which part to download","in":"query","name":"part","required":true,"schema":{"enum":["public","private","both"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"file content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid part"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"download failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Download ssh key files by ID (org scoped)","tags":["Ssh"]}},"/taints":{"get":{"description":"Returns node taints for the organization in X-Org-ID. Filters: ` + "`" + `key` + "`" + `, ` + "`" + `value` + "`" + `, and ` + "`" + `q` + "`" + ` (key contains). Add ` + "`" + `include=node_pools` + "`" + ` to include linked node pools.","operationId":"ListTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node taints"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node pool taints (org scoped)","tags":["Taints"]},"post":{"description":"Creates a taint.","operationId":"CreateTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateTaintRequest"}}},"description":"Taint payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid node_pool_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create node taint (org scoped)","tags":["Taints"]}},"/taints/{id}":{"delete":{"description":"Permanently deletes the taint.","operationId":"DeleteTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete taint (org scoped)","tags":["Taints"]},"get":{"operationId":"GetTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get node taint by ID (org scoped)","tags":["Taints"]},"patch":{"description":"Partially update taint fields.","operationId":"UpdateTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateTaintRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update node taint (org scoped)","tags":["Taints"]}},"/version":{"get":{"description":"Returns build/runtime metadata for the running service.","operationId":"Version // operationId","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.VersionResponse"}}},"description":"OK"}},"summary":"Service version information","tags":["Meta"]}}}, "openapi": "3.1.0", "servers": [ {"description":"Production API","url":"https://autoglue.glueopshosted.com/api/v1"}, diff --git a/docs/openapi.json b/docs/openapi.json index 1d6152e..55c707d 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -1,8 +1,8 @@ { - "components": {"schemas":{"dto.AnnotationResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.AttachAnnotationsRequest":{"properties":{"annotation_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachBastionRequest":{"properties":{"server_id":{"type":"string"}},"type":"object"},"dto.AttachCaptainDomainRequest":{"properties":{"domain_id":{"type":"string"}},"type":"object"},"dto.AttachLabelsRequest":{"properties":{"label_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachLoadBalancerRequest":{"properties":{"load_balancer_id":{"type":"string"}},"type":"object"},"dto.AttachNodePoolRequest":{"properties":{"node_pool_id":{"type":"string"}},"type":"object"},"dto.AttachRecordSetRequest":{"properties":{"record_set_id":{"type":"string"}},"type":"object"},"dto.AttachServersRequest":{"properties":{"server_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachTaintsRequest":{"properties":{"taint_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AuthStartResponse":{"properties":{"auth_url":{"example":"https://accounts.google.com/o/oauth2/v2/auth?client_id=...","type":"string"}},"type":"object"},"dto.ClusterResponse":{"properties":{"apps_load_balancer":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"bastion_server":{"$ref":"#/components/schemas/dto.ServerResponse"},"captain_domain":{"$ref":"#/components/schemas/dto.DomainResponse"},"certificate_key":{"type":"string"},"cluster_provider":{"type":"string"},"control_plane_fqdn":{"type":"string"},"control_plane_record_set":{"$ref":"#/components/schemas/dto.RecordSetResponse"},"created_at":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"glueops_load_balancer":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"id":{"type":"string"},"kubeconfig":{"type":"string"},"last_error":{"type":"string"},"name":{"type":"string"},"node_pools":{"items":{"$ref":"#/components/schemas/dto.NodePoolResponse"},"type":"array","uniqueItems":false},"org_key":{"type":"string"},"org_secret":{"type":"string"},"random_token":{"type":"string"},"region":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.CreateAnnotationRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CreateClusterRequest":{"properties":{"cluster_provider":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"}},"type":"object"},"dto.CreateCredentialRequest":{"properties":{"account_id":{"maxLength":32,"type":"string"},"credential_provider":{"enum":["aws","cloudflare","hetzner","digitalocean","generic"],"type":"string"},"kind":{"description":"aws_access_key, api_token, basic_auth, oauth2","type":"string"},"name":{"description":"human label","maxLength":100,"type":"string"},"region":{"maxLength":32,"type":"string"},"schema_version":{"description":"secret schema version","minimum":1,"type":"integer"},"scope":{"description":"{\"service\":\"route53\"} or {\"arn\":\"...\"}","type":"object"},"scope_kind":{"enum":["credential_provider","service","resource"],"type":"string"},"scope_version":{"description":"scope schema version","minimum":1,"type":"integer"},"secret":{"description":"encrypted later","type":"object"}},"required":["credential_provider","kind","schema_version","scope","scope_kind","scope_version","secret"],"type":"object"},"dto.CreateDomainRequest":{"properties":{"credential_id":{"type":"string"},"domain_name":{"type":"string"},"zone_id":{"maxLength":128,"type":"string"}},"required":["credential_id","domain_name"],"type":"object"},"dto.CreateLabelRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CreateLoadBalancerRequest":{"properties":{"kind":{"enum":["glueops","public"],"example":"public","type":"string"},"name":{"example":"glueops","type":"string"},"private_ip_address":{"example":"192.168.0.2","type":"string"},"public_ip_address":{"example":"8.8.8.8","type":"string"}},"type":"object"},"dto.CreateNodePoolRequest":{"properties":{"name":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"}},"type":"object"},"dto.CreateRecordSetRequest":{"properties":{"name":{"description":"Name relative to domain (\"endpoint\") OR FQDN (\"endpoint.example.com\").\nServer normalizes to relative.","maxLength":253,"type":"string"},"ttl":{"maximum":86400,"minimum":1,"type":"integer"},"type":{"type":"string"},"values":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"required":["name","type"],"type":"object"},"dto.CreateSSHRequest":{"properties":{"bits":{"description":"Only for RSA","type":"integer"},"comment":{"example":"deploy@autoglue","type":"string"},"name":{"type":"string"},"type":{"description":"\"rsa\" (default) or \"ed25519\"","type":"string"}},"type":"object"},"dto.CreateServerRequest":{"properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"}},"type":"object"},"dto.CreateTaintRequest":{"properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CredentialOut":{"properties":{"account_id":{"type":"string"},"created_at":{"type":"string"},"credential_provider":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"schema_version":{"type":"integer"},"scope":{"type":"object"},"scope_kind":{"type":"string"},"scope_version":{"type":"integer"},"updated_at":{"type":"string"}},"type":"object"},"dto.DomainResponse":{"properties":{"created_at":{"type":"string"},"credential_id":{"type":"string"},"domain_name":{"type":"string"},"id":{"type":"string"},"last_error":{"type":"string"},"organization_id":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"},"zone_id":{"type":"string"}},"type":"object"},"dto.EnqueueRequest":{"properties":{"payload":{"type":"object"},"queue":{"example":"default","type":"string"},"run_at":{"example":"2025-11-05T08:00:00Z","type":"string"},"type":{"example":"email.send","type":"string"}},"type":"object"},"dto.JWK":{"properties":{"alg":{"example":"RS256","type":"string"},"e":{"example":"AQAB","type":"string"},"kid":{"example":"7c6f1d0a-7a98-4e6a-9dbf-6b1af4b9f345","type":"string"},"kty":{"example":"RSA","type":"string"},"n":{"type":"string"},"use":{"example":"sig","type":"string"},"x":{"type":"string"}},"type":"object"},"dto.JWKS":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/dto.JWK"},"type":"array","uniqueItems":false}},"type":"object"},"dto.Job":{"properties":{"attempts":{"example":0,"type":"integer"},"created_at":{"example":"2025-11-04T09:30:00Z","type":"string"},"id":{"example":"01HF7SZK8Z8WG1M3J7S2Z8M2N6","type":"string"},"last_error":{"example":"error message","type":"string"},"max_attempts":{"example":3,"type":"integer"},"payload":{},"queue":{"example":"default","type":"string"},"run_at":{"example":"2025-11-04T09:30:00Z","type":"string"},"status":{"$ref":"#/components/schemas/dto.JobStatus"},"type":{"example":"email.send","type":"string"},"updated_at":{"example":"2025-11-04T09:30:00Z","type":"string"}},"type":"object"},"dto.JobStatus":{"enum":["queued|running|succeeded|failed|canceled|retrying|scheduled"],"example":"queued","type":"string","x-enum-varnames":["StatusQueued","StatusRunning","StatusSucceeded","StatusFailed","StatusCanceled","StatusRetrying","StatusScheduled"]},"dto.LabelResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.LoadBalancerResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.LogoutRequest":{"properties":{"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf...","type":"string"}},"type":"object"},"dto.NodePoolResponse":{"properties":{"annotations":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array","uniqueItems":false},"created_at":{"type":"string"},"id":{"type":"string"},"labels":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array","uniqueItems":false},"name":{"type":"string"},"organization_id":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"},"servers":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array","uniqueItems":false},"taints":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array","uniqueItems":false},"updated_at":{"type":"string"}},"type":"object"},"dto.PageJob":{"properties":{"items":{"items":{"$ref":"#/components/schemas/dto.Job"},"type":"array","uniqueItems":false},"page":{"example":1,"type":"integer"},"page_size":{"example":25,"type":"integer"},"total":{"example":120,"type":"integer"}},"type":"object"},"dto.QueueInfo":{"properties":{"failed":{"example":5,"type":"integer"},"name":{"example":"default","type":"string"},"pending":{"example":42,"type":"integer"},"running":{"example":3,"type":"integer"},"scheduled":{"example":7,"type":"integer"}},"type":"object"},"dto.RecordSetResponse":{"properties":{"created_at":{"type":"string"},"domain_id":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"last_error":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"status":{"type":"string"},"ttl":{"type":"integer"},"type":{"type":"string"},"updated_at":{"type":"string"},"values":{"description":"[]string JSON","type":"object"}},"type":"object"},"dto.RefreshRequest":{"properties":{"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf...","type":"string"}},"type":"object"},"dto.ServerResponse":{"properties":{"created_at":{"type":"string"},"hostname":{"type":"string"},"id":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.SetKubeconfigRequest":{"properties":{"kubeconfig":{"type":"string"}},"type":"object"},"dto.SshResponse":{"properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.SshRevealResponse":{"properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_key":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.TaintResponse":{"properties":{"created_at":{"type":"string"},"effect":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.TokenPair":{"properties":{"access_token":{"example":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ij...","type":"string"},"expires_in":{"example":3600,"type":"integer"},"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf....","type":"string"},"token_type":{"example":"Bearer","type":"string"}},"type":"object"},"dto.UpdateAnnotationRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.UpdateClusterRequest":{"properties":{"cluster_provider":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"}},"type":"object"},"dto.UpdateCredentialRequest":{"properties":{"account_id":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"scope":{"type":"object"},"scope_kind":{"type":"string"},"scope_version":{"type":"integer"},"secret":{"description":"set if rotating","type":"object"}},"type":"object"},"dto.UpdateDomainRequest":{"properties":{"credential_id":{"type":"string"},"domain_name":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"type":"string"},"zone_id":{"maxLength":128,"type":"string"}},"type":"object"},"dto.UpdateLabelRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.UpdateLoadBalancerRequest":{"properties":{"kind":{"enum":["glueops","public"],"example":"public","type":"string"},"name":{"example":"glue","type":"string"},"private_ip_address":{"example":"192.168.0.2","type":"string"},"public_ip_address":{"example":"8.8.8.8","type":"string"}},"type":"object"},"dto.UpdateNodePoolRequest":{"properties":{"name":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"}},"type":"object"},"dto.UpdateRecordSetRequest":{"properties":{"name":{"description":"Any change flips status back to pending (worker will UPSERT)","maxLength":253,"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"type":"string"},"ttl":{"maximum":86400,"minimum":1,"type":"integer"},"type":{"type":"string"},"values":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.UpdateServerRequest":{"properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"}},"type":"object"},"dto.UpdateTaintRequest":{"properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"handlers.HealthStatus":{"properties":{"status":{"example":"ok","type":"string"}},"type":"object"},"handlers.VersionResponse":{"properties":{"built":{"example":"2025-11-08T12:34:56Z","type":"string"},"builtBy":{"example":"ci","type":"string"},"commit":{"example":"a1b2c3d","type":"string"},"commitTime":{"example":"2025-11-08T12:31:00Z","type":"string"},"go":{"example":"go1.23.3","type":"string"},"goArch":{"example":"amd64","type":"string"},"goOS":{"example":"linux","type":"string"},"modified":{"example":false,"type":"boolean"},"revision":{"example":"a1b2c3d4e5f6abcdef","type":"string"},"vcs":{"example":"git","type":"string"},"version":{"example":"1.4.2","type":"string"}},"type":"object"},"handlers.createUserKeyRequest":{"properties":{"expires_in_hours":{"description":"optional TTL","type":"integer"},"name":{"type":"string"}},"type":"object"},"handlers.meResponse":{"properties":{"avatar_url":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"emails":{"items":{"$ref":"#/components/schemas/models.UserEmail"},"type":"array","uniqueItems":false},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"organizations":{"items":{"$ref":"#/components/schemas/models.Organization"},"type":"array","uniqueItems":false},"primary_email":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"handlers.memberOut":{"properties":{"email":{"type":"string"},"role":{"description":"owner/admin/member","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"handlers.memberUpsertReq":{"properties":{"role":{"example":"member","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"handlers.orgCreateReq":{"properties":{"domain":{"example":"acme.com","type":"string"},"name":{"example":"Acme Corp","type":"string"}},"type":"object"},"handlers.orgKeyCreateReq":{"properties":{"expires_in_hours":{"example":720,"type":"integer"},"name":{"example":"automation-bot","type":"string"}},"type":"object"},"handlers.orgKeyCreateResp":{"properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"org_key":{"description":"shown once:","type":"string"},"org_secret":{"description":"shown once:","type":"string"},"scope":{"description":"\"org\"","type":"string"}},"type":"object"},"handlers.orgUpdateReq":{"properties":{"domain":{"type":"string"},"name":{"type":"string"}},"type":"object"},"handlers.updateMeRequest":{"properties":{"display_name":{"type":"string"}},"type":"object"},"handlers.userAPIKeyOut":{"properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"format":"uuid","type":"string"},"last_used_at":{"type":"string"},"name":{"type":"string"},"plain":{"description":"Shown only on create:","type":"string"},"scope":{"description":"\"user\"","type":"string"}},"type":"object"},"models.APIKey":{"properties":{"cluster_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"is_ephemeral":{"type":"boolean"},"last_used_at":{"format":"date-time","type":"string"},"name":{"type":"string"},"org_id":{"format":"uuid","type":"string"},"prefix":{"type":"string"},"purpose":{"type":"string"},"revoked":{"type":"boolean"},"scope":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"models.Organization":{"properties":{"created_at":{"format":"date-time","type":"string"},"domain":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"name":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"models.User":{"properties":{"avatar_url":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"primary_email":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"models.UserEmail":{"properties":{"created_at":{"format":"date-time","type":"string"},"email":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_primary":{"type":"boolean"},"is_verified":{"type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/models.User"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"utils.ErrorResponse":{"properties":{"code":{"description":"A machine-readable error code, e.g. \"validation_error\"\nexample: validation_error","type":"string"},"message":{"description":"Human-readable message\nexample: slug is required","type":"string"}},"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"description":"User API key","in":"header","name":"X-API-KEY","type":"apiKey"},"BearerAuth":{"description":"Bearer token authentication","in":"header","name":"Authorization","type":"apiKey"},"OrgKeyAuth":{"description":"Org-level key/secret authentication","in":"header","name":"X-ORG-KEY","type":"apiKey"},"OrgSecretAuth":{"description":"Org-level secret","in":"header","name":"X-ORG-SECRET","type":"apiKey"}}}, + "components": {"schemas":{"dto.ActionResponse":{"properties":{"created_at":{"format":"date-time","type":"string"},"description":{"type":"string"},"id":{"format":"uuid","type":"string"},"label":{"type":"string"},"make_target":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"dto.AnnotationResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.AttachAnnotationsRequest":{"properties":{"annotation_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachBastionRequest":{"properties":{"server_id":{"type":"string"}},"type":"object"},"dto.AttachCaptainDomainRequest":{"properties":{"domain_id":{"type":"string"}},"type":"object"},"dto.AttachLabelsRequest":{"properties":{"label_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachLoadBalancerRequest":{"properties":{"load_balancer_id":{"type":"string"}},"type":"object"},"dto.AttachNodePoolRequest":{"properties":{"node_pool_id":{"type":"string"}},"type":"object"},"dto.AttachRecordSetRequest":{"properties":{"record_set_id":{"type":"string"}},"type":"object"},"dto.AttachServersRequest":{"properties":{"server_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AttachTaintsRequest":{"properties":{"taint_ids":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.AuthStartResponse":{"properties":{"auth_url":{"example":"https://accounts.google.com/o/oauth2/v2/auth?client_id=...","type":"string"}},"type":"object"},"dto.ClusterResponse":{"properties":{"apps_load_balancer":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"bastion_server":{"$ref":"#/components/schemas/dto.ServerResponse"},"captain_domain":{"$ref":"#/components/schemas/dto.DomainResponse"},"certificate_key":{"type":"string"},"cluster_provider":{"type":"string"},"control_plane_fqdn":{"type":"string"},"control_plane_record_set":{"$ref":"#/components/schemas/dto.RecordSetResponse"},"created_at":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"glueops_load_balancer":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"id":{"type":"string"},"kubeconfig":{"type":"string"},"last_error":{"type":"string"},"name":{"type":"string"},"node_pools":{"items":{"$ref":"#/components/schemas/dto.NodePoolResponse"},"type":"array","uniqueItems":false},"org_key":{"type":"string"},"org_secret":{"type":"string"},"random_token":{"type":"string"},"region":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.ClusterRunResponse":{"properties":{"action":{"type":"string"},"cluster_id":{"format":"uuid","type":"string"},"created_at":{"format":"date-time","type":"string"},"error":{"type":"string"},"finished_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"organization_id":{"format":"uuid","type":"string"},"status":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"dto.CreateActionRequest":{"properties":{"description":{"type":"string"},"label":{"type":"string"},"make_target":{"type":"string"}},"type":"object"},"dto.CreateAnnotationRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CreateClusterRequest":{"properties":{"cluster_provider":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"}},"type":"object"},"dto.CreateCredentialRequest":{"properties":{"account_id":{"maxLength":32,"type":"string"},"credential_provider":{"enum":["aws","cloudflare","hetzner","digitalocean","generic"],"type":"string"},"kind":{"description":"aws_access_key, api_token, basic_auth, oauth2","type":"string"},"name":{"description":"human label","maxLength":100,"type":"string"},"region":{"maxLength":32,"type":"string"},"schema_version":{"description":"secret schema version","minimum":1,"type":"integer"},"scope":{"description":"{\"service\":\"route53\"} or {\"arn\":\"...\"}","type":"object"},"scope_kind":{"enum":["credential_provider","service","resource"],"type":"string"},"scope_version":{"description":"scope schema version","minimum":1,"type":"integer"},"secret":{"description":"encrypted later","type":"object"}},"required":["credential_provider","kind","schema_version","scope","scope_kind","scope_version","secret"],"type":"object"},"dto.CreateDomainRequest":{"properties":{"credential_id":{"type":"string"},"domain_name":{"type":"string"},"zone_id":{"maxLength":128,"type":"string"}},"required":["credential_id","domain_name"],"type":"object"},"dto.CreateLabelRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CreateLoadBalancerRequest":{"properties":{"kind":{"enum":["glueops","public"],"example":"public","type":"string"},"name":{"example":"glueops","type":"string"},"private_ip_address":{"example":"192.168.0.2","type":"string"},"public_ip_address":{"example":"8.8.8.8","type":"string"}},"type":"object"},"dto.CreateNodePoolRequest":{"properties":{"name":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"}},"type":"object"},"dto.CreateRecordSetRequest":{"properties":{"name":{"description":"Name relative to domain (\"endpoint\") OR FQDN (\"endpoint.example.com\").\nServer normalizes to relative.","maxLength":253,"type":"string"},"ttl":{"maximum":86400,"minimum":1,"type":"integer"},"type":{"type":"string"},"values":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"required":["name","type"],"type":"object"},"dto.CreateSSHRequest":{"properties":{"bits":{"description":"Only for RSA","type":"integer"},"comment":{"example":"deploy@autoglue","type":"string"},"name":{"type":"string"},"type":{"description":"\"rsa\" (default) or \"ed25519\"","type":"string"}},"type":"object"},"dto.CreateServerRequest":{"properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"}},"type":"object"},"dto.CreateTaintRequest":{"properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.CredentialOut":{"properties":{"account_id":{"type":"string"},"created_at":{"type":"string"},"credential_provider":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"schema_version":{"type":"integer"},"scope":{"type":"object"},"scope_kind":{"type":"string"},"scope_version":{"type":"integer"},"updated_at":{"type":"string"}},"type":"object"},"dto.DomainResponse":{"properties":{"created_at":{"type":"string"},"credential_id":{"type":"string"},"domain_name":{"type":"string"},"id":{"type":"string"},"last_error":{"type":"string"},"organization_id":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"string"},"zone_id":{"type":"string"}},"type":"object"},"dto.EnqueueRequest":{"properties":{"payload":{"type":"object"},"queue":{"example":"default","type":"string"},"run_at":{"example":"2025-11-05T08:00:00Z","type":"string"},"type":{"example":"email.send","type":"string"}},"type":"object"},"dto.JWK":{"properties":{"alg":{"example":"RS256","type":"string"},"e":{"example":"AQAB","type":"string"},"kid":{"example":"7c6f1d0a-7a98-4e6a-9dbf-6b1af4b9f345","type":"string"},"kty":{"example":"RSA","type":"string"},"n":{"type":"string"},"use":{"example":"sig","type":"string"},"x":{"type":"string"}},"type":"object"},"dto.JWKS":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/dto.JWK"},"type":"array","uniqueItems":false}},"type":"object"},"dto.Job":{"properties":{"attempts":{"example":0,"type":"integer"},"created_at":{"example":"2025-11-04T09:30:00Z","type":"string"},"id":{"example":"01HF7SZK8Z8WG1M3J7S2Z8M2N6","type":"string"},"last_error":{"example":"error message","type":"string"},"max_attempts":{"example":3,"type":"integer"},"payload":{},"queue":{"example":"default","type":"string"},"run_at":{"example":"2025-11-04T09:30:00Z","type":"string"},"status":{"$ref":"#/components/schemas/dto.JobStatus"},"type":{"example":"email.send","type":"string"},"updated_at":{"example":"2025-11-04T09:30:00Z","type":"string"}},"type":"object"},"dto.JobStatus":{"enum":["queued|running|succeeded|failed|canceled|retrying|scheduled"],"example":"queued","type":"string","x-enum-varnames":["StatusQueued","StatusRunning","StatusSucceeded","StatusFailed","StatusCanceled","StatusRetrying","StatusScheduled"]},"dto.LabelResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.LoadBalancerResponse":{"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.LogoutRequest":{"properties":{"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf...","type":"string"}},"type":"object"},"dto.NodePoolResponse":{"properties":{"annotations":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array","uniqueItems":false},"created_at":{"type":"string"},"id":{"type":"string"},"labels":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array","uniqueItems":false},"name":{"type":"string"},"organization_id":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"},"servers":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array","uniqueItems":false},"taints":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array","uniqueItems":false},"updated_at":{"type":"string"}},"type":"object"},"dto.PageJob":{"properties":{"items":{"items":{"$ref":"#/components/schemas/dto.Job"},"type":"array","uniqueItems":false},"page":{"example":1,"type":"integer"},"page_size":{"example":25,"type":"integer"},"total":{"example":120,"type":"integer"}},"type":"object"},"dto.QueueInfo":{"properties":{"failed":{"example":5,"type":"integer"},"name":{"example":"default","type":"string"},"pending":{"example":42,"type":"integer"},"running":{"example":3,"type":"integer"},"scheduled":{"example":7,"type":"integer"}},"type":"object"},"dto.RecordSetResponse":{"properties":{"created_at":{"type":"string"},"domain_id":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"last_error":{"type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"status":{"type":"string"},"ttl":{"type":"integer"},"type":{"type":"string"},"updated_at":{"type":"string"},"values":{"description":"[]string JSON","type":"object"}},"type":"object"},"dto.RefreshRequest":{"properties":{"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf...","type":"string"}},"type":"object"},"dto.ServerResponse":{"properties":{"created_at":{"type":"string"},"hostname":{"type":"string"},"id":{"type":"string"},"organization_id":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.SetKubeconfigRequest":{"properties":{"kubeconfig":{"type":"string"}},"type":"object"},"dto.SshResponse":{"properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.SshRevealResponse":{"properties":{"created_at":{"type":"string"},"fingerprint":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"organization_id":{"type":"string"},"private_key":{"type":"string"},"public_key":{"type":"string"},"updated_at":{"type":"string"}},"type":"object"},"dto.TaintResponse":{"properties":{"created_at":{"type":"string"},"effect":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"organization_id":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.TokenPair":{"properties":{"access_token":{"example":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ij...","type":"string"},"expires_in":{"example":3600,"type":"integer"},"refresh_token":{"example":"m0l9o8rT3t0V8d3eFf....","type":"string"},"token_type":{"example":"Bearer","type":"string"}},"type":"object"},"dto.UpdateActionRequest":{"properties":{"description":{"type":"string"},"label":{"type":"string"},"make_target":{"type":"string"}},"type":"object"},"dto.UpdateAnnotationRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.UpdateClusterRequest":{"properties":{"cluster_provider":{"type":"string"},"docker_image":{"type":"string"},"docker_tag":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"}},"type":"object"},"dto.UpdateCredentialRequest":{"properties":{"account_id":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"scope":{"type":"object"},"scope_kind":{"type":"string"},"scope_version":{"type":"integer"},"secret":{"description":"set if rotating","type":"object"}},"type":"object"},"dto.UpdateDomainRequest":{"properties":{"credential_id":{"type":"string"},"domain_name":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"type":"string"},"zone_id":{"maxLength":128,"type":"string"}},"type":"object"},"dto.UpdateLabelRequest":{"properties":{"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"dto.UpdateLoadBalancerRequest":{"properties":{"kind":{"enum":["glueops","public"],"example":"public","type":"string"},"name":{"example":"glue","type":"string"},"private_ip_address":{"example":"192.168.0.2","type":"string"},"public_ip_address":{"example":"8.8.8.8","type":"string"}},"type":"object"},"dto.UpdateNodePoolRequest":{"properties":{"name":{"type":"string"},"role":{"enum":["master","worker"],"type":"string"}},"type":"object"},"dto.UpdateRecordSetRequest":{"properties":{"name":{"description":"Any change flips status back to pending (worker will UPSERT)","maxLength":253,"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"type":"string"},"ttl":{"maximum":86400,"minimum":1,"type":"integer"},"type":{"type":"string"},"values":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"dto.UpdateServerRequest":{"properties":{"hostname":{"type":"string"},"private_ip_address":{"type":"string"},"public_ip_address":{"type":"string"},"role":{"enum":["master","worker","bastion"],"example":"master|worker|bastion","type":"string"},"ssh_key_id":{"type":"string"},"ssh_user":{"type":"string"},"status":{"enum":["pending","provisioning","ready","failed"],"example":"pending|provisioning|ready|failed","type":"string"}},"type":"object"},"dto.UpdateTaintRequest":{"properties":{"effect":{"type":"string"},"key":{"type":"string"},"value":{"type":"string"}},"type":"object"},"handlers.HealthStatus":{"properties":{"status":{"example":"ok","type":"string"}},"type":"object"},"handlers.VersionResponse":{"properties":{"built":{"example":"2025-11-08T12:34:56Z","type":"string"},"builtBy":{"example":"ci","type":"string"},"commit":{"example":"a1b2c3d","type":"string"},"commitTime":{"example":"2025-11-08T12:31:00Z","type":"string"},"go":{"example":"go1.23.3","type":"string"},"goArch":{"example":"amd64","type":"string"},"goOS":{"example":"linux","type":"string"},"modified":{"example":false,"type":"boolean"},"revision":{"example":"a1b2c3d4e5f6abcdef","type":"string"},"vcs":{"example":"git","type":"string"},"version":{"example":"1.4.2","type":"string"}},"type":"object"},"handlers.createUserKeyRequest":{"properties":{"expires_in_hours":{"description":"optional TTL","type":"integer"},"name":{"type":"string"}},"type":"object"},"handlers.meResponse":{"properties":{"avatar_url":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"emails":{"items":{"$ref":"#/components/schemas/models.UserEmail"},"type":"array","uniqueItems":false},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"organizations":{"items":{"$ref":"#/components/schemas/models.Organization"},"type":"array","uniqueItems":false},"primary_email":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"handlers.memberOut":{"properties":{"email":{"type":"string"},"role":{"description":"owner/admin/member","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"handlers.memberUpsertReq":{"properties":{"role":{"example":"member","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"handlers.orgCreateReq":{"properties":{"domain":{"example":"acme.com","type":"string"},"name":{"example":"Acme Corp","type":"string"}},"type":"object"},"handlers.orgKeyCreateReq":{"properties":{"expires_in_hours":{"example":720,"type":"integer"},"name":{"example":"automation-bot","type":"string"}},"type":"object"},"handlers.orgKeyCreateResp":{"properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"org_key":{"description":"shown once:","type":"string"},"org_secret":{"description":"shown once:","type":"string"},"scope":{"description":"\"org\"","type":"string"}},"type":"object"},"handlers.orgUpdateReq":{"properties":{"domain":{"type":"string"},"name":{"type":"string"}},"type":"object"},"handlers.updateMeRequest":{"properties":{"display_name":{"type":"string"}},"type":"object"},"handlers.userAPIKeyOut":{"properties":{"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"format":"uuid","type":"string"},"last_used_at":{"type":"string"},"name":{"type":"string"},"plain":{"description":"Shown only on create:","type":"string"},"scope":{"description":"\"user\"","type":"string"}},"type":"object"},"models.APIKey":{"properties":{"cluster_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"is_ephemeral":{"type":"boolean"},"last_used_at":{"format":"date-time","type":"string"},"name":{"type":"string"},"org_id":{"format":"uuid","type":"string"},"prefix":{"type":"string"},"purpose":{"type":"string"},"revoked":{"type":"boolean"},"scope":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"models.Organization":{"properties":{"created_at":{"format":"date-time","type":"string"},"domain":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"name":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"models.User":{"properties":{"avatar_url":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_admin":{"type":"boolean"},"is_disabled":{"type":"boolean"},"primary_email":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"models.UserEmail":{"properties":{"created_at":{"format":"date-time","type":"string"},"email":{"type":"string"},"id":{"description":"example: 3fa85f64-5717-4562-b3fc-2c963f66afa6","format":"uuid","type":"string"},"is_primary":{"type":"boolean"},"is_verified":{"type":"boolean"},"updated_at":{"format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/models.User"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"utils.ErrorResponse":{"properties":{"code":{"description":"A machine-readable error code, e.g. \"validation_error\"\nexample: validation_error","type":"string"},"message":{"description":"Human-readable message\nexample: slug is required","type":"string"}},"type":"object"}},"securitySchemes":{"ApiKeyAuth":{"description":"User API key","in":"header","name":"X-API-KEY","type":"apiKey"},"BearerAuth":{"description":"Bearer token authentication","in":"header","name":"Authorization","type":"apiKey"},"OrgKeyAuth":{"description":"Org-level key/secret authentication","in":"header","name":"X-ORG-KEY","type":"apiKey"},"OrgSecretAuth":{"description":"Org-level secret","in":"header","name":"X-ORG-SECRET","type":"apiKey"}}}, "info": {"contact":{"name":"GlueOps"},"description":"API for managing K3s clusters across cloud providers","title":"AutoGlue API","version":"dev"}, "externalDocs": {"description":"","url":""}, - "paths": {"/.well-known/jwks.json":{"get":{"description":"Returns the JSON Web Key Set for token verification","operationId":"getJWKS","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.JWKS"}}},"description":"OK"}},"summary":"Get JWKS","tags":["Auth"]}},"/admin/archer/jobs":{"get":{"description":"Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent).","operationId":"AdminListArcherJobs","parameters":[{"description":"Filter by status","in":"query","name":"status","schema":{"enum":["queued","running","succeeded","failed","canceled","retrying","scheduled"],"type":"string"}},{"description":"Filter by queue name / worker name","in":"query","name":"queue","schema":{"type":"string"}},{"description":"Free-text search","in":"query","name":"q","schema":{"type":"string"}},{"description":"Page number","in":"query","name":"page","schema":{"default":1,"type":"integer"}},{"description":"Items per page","in":"query","name":"page_size","schema":{"default":25,"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.PageJob"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"List Archer jobs (admin)","tags":["ArcherAdmin"]},"post":{"description":"Create a job immediately or schedule it for the future via `run_at`.","operationId":"AdminEnqueueArcherJob","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.EnqueueRequest"}}},"description":"Job parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json or missing fields"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"Enqueue a new Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/jobs/{id}/cancel":{"post":{"description":"Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill.","operationId":"AdminCancelArcherJob","parameters":[{"description":"Job ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid job or not cancellable"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]}],"summary":"Cancel an Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/jobs/{id}/retry":{"post":{"description":"Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one.","operationId":"AdminRetryArcherJob","parameters":[{"description":"Job ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid job or not eligible"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]}],"summary":"Retry a failed/canceled Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/queues":{"get":{"description":"Summary metrics per queue (pending, running, failed, scheduled).","operationId":"AdminListArcherQueues","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.QueueInfo"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"List Archer queues (admin)","tags":["ArcherAdmin"]}},"/annotations":{"get":{"description":"Returns annotations for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools.","operationId":"ListAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list annotations"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List annotations (org scoped)","tags":["Annotations"]},"post":{"description":"Creates an annotation.","operationId":"CreateAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateAnnotationRequest"}}},"description":"Annotation payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create annotation (org scoped)","tags":["Annotations"]}},"/annotations/{id}":{"delete":{"description":"Permanently deletes the annotation.","operationId":"DeleteAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete annotation (org scoped)","tags":["Annotations"]},"get":{"description":"Returns one annotation. Add `include=node_pools` to include node pools.","operationId":"GetAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get annotation by ID (org scoped)","tags":["Annotations"]},"patch":{"description":"Partially update annotation fields.","operationId":"UpdateAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateAnnotationRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update annotation (org scoped)","tags":["Annotations"]}},"/auth/logout":{"post":{"operationId":"Logout","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LogoutRequest"}}},"description":"Refresh token","required":true},"responses":{"204":{"description":"No Content"}},"summary":"Revoke refresh token family (logout everywhere)","tags":["Auth"]}},"/auth/refresh":{"post":{"operationId":"Refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RefreshRequest"}}},"description":"Refresh token","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TokenPair"}}},"description":"OK"}},"summary":"Rotate refresh token","tags":["Auth"]}},"/auth/{provider}/callback":{"get":{"operationId":"AuthCallback","parameters":[{"description":"google|github","in":"path","name":"provider","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TokenPair"}}},"description":"OK"}},"summary":"Handle social login callback","tags":["Auth"]}},"/auth/{provider}/start":{"post":{"description":"Returns provider authorization URL for the frontend to redirect","operationId":"AuthStart","parameters":[{"description":"google|github","in":"path","name":"provider","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AuthStartResponse"}}},"description":"OK"}},"summary":"Begin social login","tags":["Auth"]}},"/clusters":{"get":{"description":"Returns clusters for the organization in X-Org-ID. Filter by `q` (name contains).","operationId":"ListClusters","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Name contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ClusterResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List clusters (org scoped)","tags":["Clusters"]},"post":{"description":"Creates a cluster. Status is managed by the system and starts as `pre_pending` for validation.","operationId":"CreateCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateClusterRequest"}}},"description":"payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create cluster (org scoped)","tags":["Clusters"]}},"/clusters/{clusterID}":{"delete":{"description":"Deletes the cluster. Related resources are cleaned up via DB constraints (e.g. CASCADE).","operationId":"DeleteCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"deleted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a cluster (org scoped)","tags":["Clusters"]},"get":{"description":"Returns a cluster with all related resources (domain, record set, load balancers, bastion, node pools).","operationId":"GetCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a single cluster by ID (org scoped)","tags":["Clusters"]},"patch":{"description":"Updates the cluster name, provider, and/or region. Status is managed by the system.","operationId":"UpdateCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateClusterRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update basic cluster details (org scoped)","tags":["Clusters"]}},"/clusters/{clusterID}/apps-load-balancer":{"delete":{"description":"Clears apps_load_balancer_id on the cluster.","operationId":"DetachAppsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the apps load balancer from a cluster","tags":["Clusters"]},"post":{"description":"Sets apps_load_balancer_id on the cluster.","operationId":"AttachAppsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLoadBalancerRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or load balancer not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach an apps load balancer to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/bastion":{"delete":{"description":"Clears bastion_server_id on the cluster.","operationId":"DetachBastionServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the bastion server from a cluster","tags":["Clusters"]},"post":{"description":"Sets bastion_server_id on the cluster.","operationId":"AttachBastionServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachBastionRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or server not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a bastion server to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/captain-domain":{"delete":{"description":"Clears captain_domain_id on the cluster. This will likely cause the cluster to become incomplete.","operationId":"DetachCaptainDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the captain domain from a cluster","tags":["Clusters"]},"post":{"description":"Sets captain_domain_id on the cluster. Validation of shape happens asynchronously.","operationId":"AttachCaptainDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachCaptainDomainRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or domain not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a captain domain to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/control-plane-record-set":{"delete":{"description":"Clears control_plane_record_set_id on the cluster.","operationId":"DetachControlPlaneRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the control plane record set from a cluster","tags":["Clusters"]},"post":{"description":"Sets control_plane_record_set_id on the cluster.","operationId":"AttachControlPlaneRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachRecordSetRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or record set not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a control plane record set to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/glueops-load-balancer":{"delete":{"description":"Clears glueops_load_balancer_id on the cluster.","operationId":"DetachGlueOpsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the GlueOps/control-plane load balancer from a cluster","tags":["Clusters"]},"post":{"description":"Sets glueops_load_balancer_id on the cluster.","operationId":"AttachGlueOpsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLoadBalancerRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or load balancer not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a GlueOps/control-plane load balancer to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/kubeconfig":{"delete":{"description":"Removes the encrypted kubeconfig, IV, and tag from the cluster record.","operationId":"ClearClusterKubeconfig","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Clear the kubeconfig for a cluster","tags":["Clusters"]},"post":{"description":"Stores the kubeconfig encrypted per organization. The kubeconfig is never returned in responses.","operationId":"SetClusterKubeconfig","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.SetKubeconfigRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Set (or replace) the kubeconfig for a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/node-pools":{"post":{"description":"Adds an entry in the cluster_node_pools join table.","operationId":"AttachNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachNodePoolRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or node pool not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a node pool to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/node-pools/{nodePoolID}":{"delete":{"description":"Removes an entry from the cluster_node_pools join table.","operationId":"DetachNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}},{"description":"Node Pool ID","in":"path","name":"nodePoolID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or node pool not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach a node pool from a cluster","tags":["Clusters"]}},"/credentials":{"get":{"description":"Returns credential metadata for the current org. Secrets are never returned.","operationId":"ListCredentials","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Filter by provider (e.g., aws)","in":"query","name":"credential_provider","schema":{"type":"string"}},{"description":"Filter by kind (e.g., aws_access_key)","in":"query","name":"kind","schema":{"type":"string"}},{"description":"Filter by scope kind (credential_provider/service/resource)","in":"query","name":"scope_kind","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.CredentialOut"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List credentials (metadata only)","tags":["Credentials"]},"post":{"operationId":"CreateCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateCredentialRequest"}}},"description":"Credential payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"Created"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a credential (encrypts secret)","tags":["Credentials"]}},"/credentials/{id}":{"delete":{"operationId":"DeleteCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete credential","tags":["Credentials"]},"get":{"operationId":"GetCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get credential by ID (metadata only)","tags":["Credentials"]},"patch":{"operationId":"UpdateCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateCredentialRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"X-Org-ID required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update credential metadata and/or rotate secret","tags":["Credentials"]}},"/credentials/{id}/reveal":{"post":{"operationId":"RevealCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Reveal decrypted secret (one-time read)","tags":["Credentials"]}},"/dns/domains":{"get":{"description":"Returns domains for X-Org-ID. Filters: `domain_name`, `status`, `q` (contains).","operationId":"ListDomains","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact domain name (lowercase, no trailing dot)","in":"query","name":"domain_name","schema":{"type":"string"}},{"description":"pending|provisioning|ready|failed","in":"query","name":"status","schema":{"type":"string"}},{"description":"Domain contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.DomainResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List domains (org scoped)","tags":["DNS"]},"post":{"description":"Creates a domain bound to a Route 53 scoped credential. Archer will backfill ZoneID if omitted.","operationId":"CreateDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateDomainRequest"}}},"description":"Domain payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a domain (org scoped)","tags":["DNS"]}},"/dns/domains/{domain_id}/records":{"get":{"description":"Filters: `name`, `type`, `status`.","operationId":"ListRecordSets","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"domain_id","required":true,"schema":{"type":"string"}},{"description":"Exact relative name or FQDN (server normalizes)","in":"query","name":"name","schema":{"type":"string"}},{"description":"RR type (A, AAAA, CNAME, TXT, MX, NS, SRV, CAA)","in":"query","name":"type","schema":{"type":"string"}},{"description":"pending|provisioning|ready|failed","in":"query","name":"status","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.RecordSetResponse"},"type":"array"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List record sets for a domain","tags":["DNS"]},"post":{"operationId":"CreateRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"domain_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateRecordSetRequest"}}},"description":"Record set payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RecordSetResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a record set (pending; Archer will UPSERT to Route 53)","tags":["DNS"]}},"/dns/domains/{id}":{"delete":{"operationId":"DeleteDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a domain","tags":["DNS"]},"get":{"operationId":"GetDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a domain (org scoped)","tags":["DNS"]},"patch":{"operationId":"UpdateDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateDomainRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a domain (org scoped)","tags":["DNS"]}},"/dns/records/{id}":{"delete":{"operationId":"DeleteRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Record Set ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a record set (API removes row; worker can optionally handle external deletion policy)","tags":["DNS"]},"patch":{"operationId":"UpdateRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Record Set ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateRecordSetRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RecordSetResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a record set (flips to pending for reconciliation)","tags":["DNS"]}},"/healthz":{"get":{"description":"Returns 200 OK when the service is up","operationId":"HealthCheck // operationId","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.HealthStatus"}}},"description":"OK"}},"summary":"Basic health check","tags":["Health"]}},"/labels":{"get":{"description":"Returns node labels for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node groups.","operationId":"ListLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"Key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node taints"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node labels (org scoped)","tags":["Labels"]},"post":{"description":"Creates a label.","operationId":"CreateLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateLabelRequest"}}},"description":"Label payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid node_pool_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create label (org scoped)","tags":["Labels"]}},"/labels/{id}":{"delete":{"description":"Permanently deletes the label.","operationId":"DeleteLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete label (org scoped)","tags":["Labels"]},"get":{"description":"Returns one label.","operationId":"GetLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get label by ID (org scoped)","tags":["Labels"]},"patch":{"description":"Partially update label fields.","operationId":"UpdateLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateLabelRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update label (org scoped)","tags":["Labels"]}},"/load-balancers":{"get":{"description":"Returns load balancers for the organization in X-Org-ID.","operationId":"ListLoadBalancers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List load balancers (org scoped)","tags":["LoadBalancers"]},"post":{"operationId":"CreateLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateLoadBalancerRequest"}}},"description":"Record set payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a load balancer","tags":["LoadBalancers"]}},"/load-balancers/{id}":{"delete":{"operationId":"DeleteLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Load Balancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a load balancer","tags":["LoadBalancers"]},"get":{"description":"Returns load balancer for the organization in X-Org-ID.","operationId":"GetLoadBalancers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"LoadBalancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a load balancer (org scoped)","tags":["LoadBalancers"]},"patch":{"operationId":"UpdateLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Load Balancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateLoadBalancerRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a load balancer (org scoped)","tags":["LoadBalancers"]}},"/me":{"get":{"operationId":"GetMe","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.meResponse"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get current user profile","tags":["Me"]},"patch":{"operationId":"UpdateMe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.updateMeRequest"}}},"description":"Patch profile","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.User"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Update current user profile","tags":["Me"]}},"/me/api-keys":{"get":{"operationId":"ListUserAPIKeys","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/handlers.userAPIKeyOut"},"type":"array"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"List my API keys","tags":["MeAPIKeys"]},"post":{"description":"Returns the plaintext key once. Store it securely on the client side.","operationId":"CreateUserAPIKey","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.createUserKeyRequest"}}},"description":"Key options","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.userAPIKeyOut"}}},"description":"Created"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Create a new user API key","tags":["MeAPIKeys"]}},"/me/api-keys/{id}":{"delete":{"operationId":"DeleteUserAPIKey","parameters":[{"description":"Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"}},"security":[{"BearerAuth":[]}],"summary":"Delete a user API key","tags":["MeAPIKeys"]}},"/node-pools":{"get":{"description":"Returns node pools for the organization in X-Org-ID.","operationId":"ListNodePools","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Name contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.NodePoolResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node pools"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node pools (org scoped)","tags":["NodePools"]},"post":{"description":"Creates a node pool. Optionally attach initial servers.","operationId":"CreateNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateNodePoolRequest"}}},"description":"NodePool payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}":{"delete":{"description":"Permanently deletes the node pool.","operationId":"DeleteNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete node pool (org scoped)","tags":["NodePools"]},"get":{"description":"Returns one node pool. Add `include=servers` to include servers.","operationId":"GetNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get node pool by ID (org scoped)","tags":["NodePools"]},"patch":{"description":"Partially update node pool fields.","operationId":"UpdateNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateNodePoolRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/annotations":{"get":{"operationId":"ListNodePoolAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List annotations attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Group ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachAnnotationsRequest"}}},"description":"Annotation IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach annotation to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/annotations/{annotationId}":{"delete":{"operationId":"DetachNodePoolAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"annotationId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one annotation from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/labels":{"get":{"operationId":"ListNodePoolLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List labels attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLabelsRequest"}}},"description":"Label IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach labels to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/labels/{labelId}":{"delete":{"operationId":"DetachNodePoolLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"labelId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one label from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/servers":{"get":{"operationId":"ListNodePoolServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List servers attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachServersRequest"}}},"description":"Server IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach servers to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/servers/{serverId}":{"delete":{"operationId":"DetachNodePoolServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"serverId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one server from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/taints":{"get":{"operationId":"ListNodePoolTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List taints attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachTaintsRequest"}}},"description":"Taint IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid taint_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach taints to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/taints/{taintId}":{"delete":{"operationId":"DetachNodePoolTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Taint ID (UUID)","in":"path","name":"taintId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one taint from a node pool (org scoped)","tags":["NodePools"]}},"/orgs":{"get":{"operationId":"listMyOrgs","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.Organization"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List organizations I belong to","tags":["Orgs"]},"post":{"operationId":"createOrg","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgCreateReq"}}},"description":"Org payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Conflict"}},"security":[{"BearerAuth":[]}],"summary":"Create organization","tags":["Orgs"]}},"/orgs/{id}":{"delete":{"operationId":"deleteOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Delete organization (owner)","tags":["Orgs"]},"get":{"operationId":"getOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Get organization","tags":["Orgs"]},"patch":{"operationId":"updateOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgUpdateReq"}}},"description":"Update payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Update organization (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/api-keys":{"get":{"operationId":"listOrgKeys","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.APIKey"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List org-scoped API keys (no secrets)","tags":["Orgs"]},"post":{"operationId":"createOrgKey","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgKeyCreateReq"}}},"description":"Key name + optional expiry","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgKeyCreateResp"}}},"description":"Created"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Create org key/secret pair (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/api-keys/{key_id}":{"delete":{"operationId":"deleteOrgKey","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Key ID (UUID)","in":"path","name":"key_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Delete org key (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/members":{"get":{"operationId":"listMembers","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/handlers.memberOut"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List members in org","tags":["Orgs"]},"post":{"operationId":"addOrUpdateMember","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.memberUpsertReq"}}},"description":"User \u0026 role","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.memberOut"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Add or update a member (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/members/{user_id}":{"delete":{"operationId":"removeMember","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"User ID (UUID)","in":"path","name":"user_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Remove a member (owner/admin)","tags":["Orgs"]}},"/servers":{"get":{"description":"Returns servers for the organization in X-Org-ID. Optional filters: status, role.","operationId":"ListServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Filter by status (pending|provisioning|ready|failed)","in":"query","name":"status","schema":{"type":"string"}},{"description":"Filter by role","in":"query","name":"role","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list servers"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List servers (org scoped)","tags":["Servers"]},"post":{"description":"Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org.","operationId":"CreateServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateServerRequest"}}},"description":"Server payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid status / invalid ssh_key_id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create server (org scoped)","tags":["Servers"]}},"/servers/{id}":{"delete":{"description":"Permanently deletes the server.","operationId":"DeleteServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete server (org scoped)","tags":["Servers"]},"get":{"description":"Returns one server in the given organization.","operationId":"GetServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get server by ID (org scoped)","tags":["Servers"]},"patch":{"description":"Partially update fields; changing ssh_key_id validates ownership.","operationId":"UpdateServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateServerRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json / invalid status / invalid ssh_key_id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update server (org scoped)","tags":["Servers"]}},"/servers/{id}/reset-hostkey":{"post":{"description":"Clears the stored SSH host key for this server. The next SSH connection will re-learn the host key (trust-on-first-use).","operationId":"ResetServerHostKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"reset failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Reset SSH host key (org scoped)","tags":["Servers"]}},"/ssh":{"get":{"description":"Returns ssh keys for the organization in X-Org-ID.","operationId":"ListPublicSshKeys","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.SshResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list keys"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List ssh keys (org scoped)","tags":["Ssh"]},"post":{"description":"Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits.","operationId":"CreateSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateSSHRequest"}}},"description":"Key generation options","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.SshResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / invalid bits"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"generation/create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create ssh keypair (org scoped)","tags":["Ssh"]}},"/ssh/{id}":{"delete":{"description":"Permanently deletes a keypair.","operationId":"DeleteSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete ssh keypair (org scoped)","tags":["Ssh"]},"get":{"description":"Returns public key fields. Append `?reveal=true` to include the private key PEM.","operationId":"GetSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Reveal private key PEM","in":"query","name":"reveal","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/dto.SshResponse"},{"$ref":"#/components/schemas/dto.SshRevealResponse"}]}}},"description":"When reveal=true"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get ssh key by ID (org scoped)","tags":["Ssh"]}},"/ssh/{id}/download":{"get":{"description":"Download `part=public|private|both` of the keypair. `both` returns a zip file.","operationId":"DownloadSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","required":true,"schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Which part to download","in":"query","name":"part","required":true,"schema":{"enum":["public","private","both"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"file content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid part"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"download failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Download ssh key files by ID (org scoped)","tags":["Ssh"]}},"/taints":{"get":{"description":"Returns node taints for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools.","operationId":"ListTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node taints"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node pool taints (org scoped)","tags":["Taints"]},"post":{"description":"Creates a taint.","operationId":"CreateTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateTaintRequest"}}},"description":"Taint payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid node_pool_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create node taint (org scoped)","tags":["Taints"]}},"/taints/{id}":{"delete":{"description":"Permanently deletes the taint.","operationId":"DeleteTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete taint (org scoped)","tags":["Taints"]},"get":{"operationId":"GetTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get node taint by ID (org scoped)","tags":["Taints"]},"patch":{"description":"Partially update taint fields.","operationId":"UpdateTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateTaintRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update node taint (org scoped)","tags":["Taints"]}},"/version":{"get":{"description":"Returns build/runtime metadata for the running service.","operationId":"Version // operationId","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.VersionResponse"}}},"description":"OK"}},"summary":"Service version information","tags":["Meta"]}}}, + "paths": {"/.well-known/jwks.json":{"get":{"description":"Returns the JSON Web Key Set for token verification","operationId":"getJWKS","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.JWKS"}}},"description":"OK"}},"summary":"Get JWKS","tags":["Auth"]}},"/admin/actions":{"get":{"description":"Returns all admin-configured actions.","operationId":"ListActions","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ActionResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"List available actions","tags":["Actions"]},"post":{"description":"Creates a new admin-configured action.","operationId":"CreateAction","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateActionRequest"}}},"description":"payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ActionResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"Create an action","tags":["Actions"]}},"/admin/actions/{actionID}":{"delete":{"description":"Deletes an action.","operationId":"DeleteAction","parameters":[{"description":"Action ID","in":"path","name":"actionID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"deleted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"Delete an action","tags":["Actions"]},"get":{"description":"Returns a single action.","operationId":"GetAction","parameters":[{"description":"Action ID","in":"path","name":"actionID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ActionResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"Get a single action by ID","tags":["Actions"]},"patch":{"description":"Updates an action. Only provided fields are modified.","operationId":"UpdateAction","parameters":[{"description":"Action ID","in":"path","name":"actionID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateActionRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ActionResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]}],"summary":"Update an action","tags":["Actions"]}},"/admin/archer/jobs":{"get":{"description":"Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent).","operationId":"AdminListArcherJobs","parameters":[{"description":"Filter by status","in":"query","name":"status","schema":{"enum":["queued","running","succeeded","failed","canceled","retrying","scheduled"],"type":"string"}},{"description":"Filter by queue name / worker name","in":"query","name":"queue","schema":{"type":"string"}},{"description":"Free-text search","in":"query","name":"q","schema":{"type":"string"}},{"description":"Page number","in":"query","name":"page","schema":{"default":1,"type":"integer"}},{"description":"Items per page","in":"query","name":"page_size","schema":{"default":25,"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.PageJob"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"List Archer jobs (admin)","tags":["ArcherAdmin"]},"post":{"description":"Create a job immediately or schedule it for the future via `run_at`.","operationId":"AdminEnqueueArcherJob","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.EnqueueRequest"}}},"description":"Job parameters","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json or missing fields"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"Enqueue a new Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/jobs/{id}/cancel":{"post":{"description":"Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill.","operationId":"AdminCancelArcherJob","parameters":[{"description":"Job ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid job or not cancellable"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]}],"summary":"Cancel an Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/jobs/{id}/retry":{"post":{"description":"Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one.","operationId":"AdminRetryArcherJob","parameters":[{"description":"Job ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.Job"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid job or not eligible"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]}],"summary":"Retry a failed/canceled Archer job (admin)","tags":["ArcherAdmin"]}},"/admin/archer/queues":{"get":{"description":"Summary metrics per queue (pending, running, failed, scheduled).","operationId":"AdminListArcherQueues","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.QueueInfo"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"forbidden"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal error"}},"security":[{"BearerAuth":[]}],"summary":"List Archer queues (admin)","tags":["ArcherAdmin"]}},"/annotations":{"get":{"description":"Returns annotations for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools.","operationId":"ListAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list annotations"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List annotations (org scoped)","tags":["Annotations"]},"post":{"description":"Creates an annotation.","operationId":"CreateAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateAnnotationRequest"}}},"description":"Annotation payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create annotation (org scoped)","tags":["Annotations"]}},"/annotations/{id}":{"delete":{"description":"Permanently deletes the annotation.","operationId":"DeleteAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete annotation (org scoped)","tags":["Annotations"]},"get":{"description":"Returns one annotation. Add `include=node_pools` to include node pools.","operationId":"GetAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get annotation by ID (org scoped)","tags":["Annotations"]},"patch":{"description":"Partially update annotation fields.","operationId":"UpdateAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateAnnotationRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AnnotationResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update annotation (org scoped)","tags":["Annotations"]}},"/auth/logout":{"post":{"operationId":"Logout","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LogoutRequest"}}},"description":"Refresh token","required":true},"responses":{"204":{"description":"No Content"}},"summary":"Revoke refresh token family (logout everywhere)","tags":["Auth"]}},"/auth/refresh":{"post":{"operationId":"Refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RefreshRequest"}}},"description":"Refresh token","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TokenPair"}}},"description":"OK"}},"summary":"Rotate refresh token","tags":["Auth"]}},"/auth/{provider}/callback":{"get":{"operationId":"AuthCallback","parameters":[{"description":"google|github","in":"path","name":"provider","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TokenPair"}}},"description":"OK"}},"summary":"Handle social login callback","tags":["Auth"]}},"/auth/{provider}/start":{"post":{"description":"Returns provider authorization URL for the frontend to redirect","operationId":"AuthStart","parameters":[{"description":"google|github","in":"path","name":"provider","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AuthStartResponse"}}},"description":"OK"}},"summary":"Begin social login","tags":["Auth"]}},"/clusters":{"get":{"description":"Returns clusters for the organization in X-Org-ID. Filter by `q` (name contains).","operationId":"ListClusters","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Name contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ClusterResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List clusters (org scoped)","tags":["Clusters"]},"post":{"description":"Creates a cluster. Status is managed by the system and starts as `pre_pending` for validation.","operationId":"CreateCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateClusterRequest"}}},"description":"payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create cluster (org scoped)","tags":["Clusters"]}},"/clusters/{clusterID}":{"delete":{"description":"Deletes the cluster. Related resources are cleaned up via DB constraints (e.g. CASCADE).","operationId":"DeleteCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"deleted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a cluster (org scoped)","tags":["Clusters"]},"get":{"description":"Returns a cluster with all related resources (domain, record set, load balancers, bastion, node pools).","operationId":"GetCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a single cluster by ID (org scoped)","tags":["Clusters"]},"patch":{"description":"Updates the cluster name, provider, and/or region. Status is managed by the system.","operationId":"UpdateCluster","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateClusterRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update basic cluster details (org scoped)","tags":["Clusters"]}},"/clusters/{clusterID}/actions/{actionID}/runs":{"post":{"description":"Creates a ClusterRun record for the cluster/action. Execution is handled asynchronously by workers.","operationId":"RunClusterAction","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}},{"description":"Action ID","in":"path","name":"actionID","required":true,"schema":{"type":"string"}}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterRunResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or action not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Run an admin-configured action on a cluster (org scoped)","tags":["ClusterRuns"]}},"/clusters/{clusterID}/apps-load-balancer":{"delete":{"description":"Clears apps_load_balancer_id on the cluster.","operationId":"DetachAppsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the apps load balancer from a cluster","tags":["Clusters"]},"post":{"description":"Sets apps_load_balancer_id on the cluster.","operationId":"AttachAppsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLoadBalancerRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or load balancer not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach an apps load balancer to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/bastion":{"delete":{"description":"Clears bastion_server_id on the cluster.","operationId":"DetachBastionServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the bastion server from a cluster","tags":["Clusters"]},"post":{"description":"Sets bastion_server_id on the cluster.","operationId":"AttachBastionServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachBastionRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or server not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a bastion server to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/captain-domain":{"delete":{"description":"Clears captain_domain_id on the cluster. This will likely cause the cluster to become incomplete.","operationId":"DetachCaptainDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the captain domain from a cluster","tags":["Clusters"]},"post":{"description":"Sets captain_domain_id on the cluster. Validation of shape happens asynchronously.","operationId":"AttachCaptainDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachCaptainDomainRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or domain not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a captain domain to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/control-plane-record-set":{"delete":{"description":"Clears control_plane_record_set_id on the cluster.","operationId":"DetachControlPlaneRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the control plane record set from a cluster","tags":["Clusters"]},"post":{"description":"Sets control_plane_record_set_id on the cluster.","operationId":"AttachControlPlaneRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachRecordSetRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or record set not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a control plane record set to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/glueops-load-balancer":{"delete":{"description":"Clears glueops_load_balancer_id on the cluster.","operationId":"DetachGlueOpsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach the GlueOps/control-plane load balancer from a cluster","tags":["Clusters"]},"post":{"description":"Sets glueops_load_balancer_id on the cluster.","operationId":"AttachGlueOpsLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLoadBalancerRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or load balancer not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a GlueOps/control-plane load balancer to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/kubeconfig":{"delete":{"description":"Removes the encrypted kubeconfig, IV, and tag from the cluster record.","operationId":"ClearClusterKubeconfig","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Clear the kubeconfig for a cluster","tags":["Clusters"]},"post":{"description":"Stores the kubeconfig encrypted per organization. The kubeconfig is never returned in responses.","operationId":"SetClusterKubeconfig","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.SetKubeconfigRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Set (or replace) the kubeconfig for a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/node-pools":{"post":{"description":"Adds an entry in the cluster_node_pools join table.","operationId":"AttachNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachNodePoolRequest"}}},"description":"payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or node pool not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach a node pool to a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/node-pools/{nodePoolID}":{"delete":{"description":"Removes an entry from the cluster_node_pools join table.","operationId":"DetachNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}},{"description":"Node Pool ID","in":"path","name":"nodePoolID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster or node pool not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach a node pool from a cluster","tags":["Clusters"]}},"/clusters/{clusterID}/runs":{"get":{"description":"Returns runs for a cluster within the organization in X-Org-ID.","operationId":"ListClusterRuns","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ClusterRunResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"cluster not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List cluster runs (org scoped)","tags":["ClusterRuns"]}},"/clusters/{clusterID}/runs/{runID}":{"get":{"description":"Returns a single run for a cluster within the organization in X-Org-ID.","operationId":"GetClusterRun","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Cluster ID","in":"path","name":"clusterID","required":true,"schema":{"type":"string"}},{"description":"Run ID","in":"path","name":"runID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ClusterRunResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"bad request"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a cluster run (org scoped)","tags":["ClusterRuns"]}},"/credentials":{"get":{"description":"Returns credential metadata for the current org. Secrets are never returned.","operationId":"ListCredentials","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Filter by provider (e.g., aws)","in":"query","name":"credential_provider","schema":{"type":"string"}},{"description":"Filter by kind (e.g., aws_access_key)","in":"query","name":"kind","schema":{"type":"string"}},{"description":"Filter by scope kind (credential_provider/service/resource)","in":"query","name":"scope_kind","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.CredentialOut"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List credentials (metadata only)","tags":["Credentials"]},"post":{"operationId":"CreateCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateCredentialRequest"}}},"description":"Credential payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"Created"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a credential (encrypts secret)","tags":["Credentials"]}},"/credentials/{id}":{"delete":{"operationId":"DeleteCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete credential","tags":["Credentials"]},"get":{"operationId":"GetCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"internal server error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get credential by ID (metadata only)","tags":["Credentials"]},"patch":{"operationId":"UpdateCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateCredentialRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CredentialOut"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"X-Org-ID required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update credential metadata and/or rotate secret","tags":["Credentials"]}},"/credentials/{id}/reveal":{"post":{"operationId":"RevealCredential","parameters":[{"description":"Organization ID (UUID)","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Credential ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{},"type":"object"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Reveal decrypted secret (one-time read)","tags":["Credentials"]}},"/dns/domains":{"get":{"description":"Returns domains for X-Org-ID. Filters: `domain_name`, `status`, `q` (contains).","operationId":"ListDomains","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact domain name (lowercase, no trailing dot)","in":"query","name":"domain_name","schema":{"type":"string"}},{"description":"pending|provisioning|ready|failed","in":"query","name":"status","schema":{"type":"string"}},{"description":"Domain contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.DomainResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List domains (org scoped)","tags":["DNS"]},"post":{"description":"Creates a domain bound to a Route 53 scoped credential. Archer will backfill ZoneID if omitted.","operationId":"CreateDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateDomainRequest"}}},"description":"Domain payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"db error"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a domain (org scoped)","tags":["DNS"]}},"/dns/domains/{domain_id}/records":{"get":{"description":"Filters: `name`, `type`, `status`.","operationId":"ListRecordSets","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"domain_id","required":true,"schema":{"type":"string"}},{"description":"Exact relative name or FQDN (server normalizes)","in":"query","name":"name","schema":{"type":"string"}},{"description":"RR type (A, AAAA, CNAME, TXT, MX, NS, SRV, CAA)","in":"query","name":"type","schema":{"type":"string"}},{"description":"pending|provisioning|ready|failed","in":"query","name":"status","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.RecordSetResponse"},"type":"array"}}},"description":"OK"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List record sets for a domain","tags":["DNS"]},"post":{"operationId":"CreateRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"domain_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateRecordSetRequest"}}},"description":"Record set payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RecordSetResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a record set (pending; Archer will UPSERT to Route 53)","tags":["DNS"]}},"/dns/domains/{id}":{"delete":{"operationId":"DeleteDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a domain","tags":["DNS"]},"get":{"operationId":"GetDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a domain (org scoped)","tags":["DNS"]},"patch":{"operationId":"UpdateDomain","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Domain ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateDomainRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.DomainResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a domain (org scoped)","tags":["DNS"]}},"/dns/records/{id}":{"delete":{"operationId":"DeleteRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Record Set ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a record set (API removes row; worker can optionally handle external deletion policy)","tags":["DNS"]},"patch":{"operationId":"UpdateRecordSet","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Record Set ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateRecordSetRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.RecordSetResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a record set (flips to pending for reconciliation)","tags":["DNS"]}},"/healthz":{"get":{"description":"Returns 200 OK when the service is up","operationId":"HealthCheck // operationId","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.HealthStatus"}}},"description":"OK"}},"summary":"Basic health check","tags":["Health"]}},"/labels":{"get":{"description":"Returns node labels for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node groups.","operationId":"ListLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"Key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node taints"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node labels (org scoped)","tags":["Labels"]},"post":{"description":"Creates a label.","operationId":"CreateLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateLabelRequest"}}},"description":"Label payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid node_pool_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create label (org scoped)","tags":["Labels"]}},"/labels/{id}":{"delete":{"description":"Permanently deletes the label.","operationId":"DeleteLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete label (org scoped)","tags":["Labels"]},"get":{"description":"Returns one label.","operationId":"GetLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get label by ID (org scoped)","tags":["Labels"]},"patch":{"description":"Partially update label fields.","operationId":"UpdateLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateLabelRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LabelResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update label (org scoped)","tags":["Labels"]}},"/load-balancers":{"get":{"description":"Returns load balancers for the organization in X-Org-ID.","operationId":"ListLoadBalancers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List load balancers (org scoped)","tags":["LoadBalancers"]},"post":{"operationId":"CreateLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateLoadBalancerRequest"}}},"description":"Record set payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"domain not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create a load balancer","tags":["LoadBalancers"]}},"/load-balancers/{id}":{"delete":{"operationId":"DeleteLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Load Balancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete a load balancer","tags":["LoadBalancers"]},"get":{"description":"Returns load balancer for the organization in X-Org-ID.","operationId":"GetLoadBalancers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"LoadBalancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list clusters"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get a load balancer (org scoped)","tags":["LoadBalancers"]},"patch":{"operationId":"UpdateLoadBalancer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Load Balancer ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateLoadBalancerRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.LoadBalancerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"validation error"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update a load balancer (org scoped)","tags":["LoadBalancers"]}},"/me":{"get":{"operationId":"GetMe","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.meResponse"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Get current user profile","tags":["Me"]},"patch":{"operationId":"UpdateMe","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.updateMeRequest"}}},"description":"Patch profile","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.User"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Update current user profile","tags":["Me"]}},"/me/api-keys":{"get":{"operationId":"ListUserAPIKeys","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/handlers.userAPIKeyOut"},"type":"array"}}},"description":"OK"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"List my API keys","tags":["MeAPIKeys"]},"post":{"description":"Returns the plaintext key once. Store it securely on the client side.","operationId":"CreateUserAPIKey","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.createUserKeyRequest"}}},"description":"Key options","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.userAPIKeyOut"}}},"description":"Created"}},"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"summary":"Create a new user API key","tags":["MeAPIKeys"]}},"/me/api-keys/{id}":{"delete":{"operationId":"DeleteUserAPIKey","parameters":[{"description":"Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"}},"security":[{"BearerAuth":[]}],"summary":"Delete a user API key","tags":["MeAPIKeys"]}},"/node-pools":{"get":{"description":"Returns node pools for the organization in X-Org-ID.","operationId":"ListNodePools","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Name contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.NodePoolResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node pools"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node pools (org scoped)","tags":["NodePools"]},"post":{"description":"Creates a node pool. Optionally attach initial servers.","operationId":"CreateNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateNodePoolRequest"}}},"description":"NodePool payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}":{"delete":{"description":"Permanently deletes the node pool.","operationId":"DeleteNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete node pool (org scoped)","tags":["NodePools"]},"get":{"description":"Returns one node pool. Add `include=servers` to include servers.","operationId":"GetNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get node pool by ID (org scoped)","tags":["NodePools"]},"patch":{"description":"Partially update node pool fields.","operationId":"UpdateNodePool","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateNodePoolRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.NodePoolResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/annotations":{"get":{"operationId":"ListNodePoolAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.AnnotationResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List annotations attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolAnnotations","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Group ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachAnnotationsRequest"}}},"description":"Annotation IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach annotation to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/annotations/{annotationId}":{"delete":{"operationId":"DetachNodePoolAnnotation","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Annotation ID (UUID)","in":"path","name":"annotationId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one annotation from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/labels":{"get":{"operationId":"ListNodePoolLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Label Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.LabelResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List labels attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolLabels","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachLabelsRequest"}}},"description":"Label IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach labels to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/labels/{labelId}":{"delete":{"operationId":"DetachNodePoolLabel","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Label ID (UUID)","in":"path","name":"labelId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one label from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/servers":{"get":{"operationId":"ListNodePoolServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List servers attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachServersRequest"}}},"description":"Server IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid server_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach servers to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/servers/{serverId}":{"delete":{"operationId":"DetachNodePoolServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"serverId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one server from a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/taints":{"get":{"operationId":"ListNodePoolTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List taints attached to a node pool (org scoped)","tags":["NodePools"]},"post":{"operationId":"AttachNodePoolTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.AttachTaintsRequest"}}},"description":"Taint IDs to attach","required":true},"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid taint_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"attach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Attach taints to a node pool (org scoped)","tags":["NodePools"]}},"/node-pools/{id}/taints/{taintId}":{"delete":{"operationId":"DetachNodePoolTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Pool ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Taint ID (UUID)","in":"path","name":"taintId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"detach failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Detach one taint from a node pool (org scoped)","tags":["NodePools"]}},"/orgs":{"get":{"operationId":"listMyOrgs","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.Organization"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List organizations I belong to","tags":["Orgs"]},"post":{"operationId":"createOrg","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgCreateReq"}}},"description":"Org payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Conflict"}},"security":[{"BearerAuth":[]}],"summary":"Create organization","tags":["Orgs"]}},"/orgs/{id}":{"delete":{"operationId":"deleteOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Delete organization (owner)","tags":["Orgs"]},"get":{"operationId":"getOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Get organization","tags":["Orgs"]},"patch":{"operationId":"updateOrg","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgUpdateReq"}}},"description":"Update payload","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.Organization"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Not Found"}},"security":[{"BearerAuth":[]}],"summary":"Update organization (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/api-keys":{"get":{"operationId":"listOrgKeys","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.APIKey"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List org-scoped API keys (no secrets)","tags":["Orgs"]},"post":{"operationId":"createOrgKey","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgKeyCreateReq"}}},"description":"Key name + optional expiry","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.orgKeyCreateResp"}}},"description":"Created"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Create org key/secret pair (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/api-keys/{key_id}":{"delete":{"operationId":"deleteOrgKey","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Key ID (UUID)","in":"path","name":"key_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Delete org key (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/members":{"get":{"operationId":"listMembers","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/handlers.memberOut"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"List members in org","tags":["Orgs"]},"post":{"operationId":"addOrUpdateMember","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.memberUpsertReq"}}},"description":"User \u0026 role","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.memberOut"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Add or update a member (owner/admin)","tags":["Orgs"]}},"/orgs/{id}/members/{user_id}":{"delete":{"operationId":"removeMember","parameters":[{"description":"Org ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"User ID (UUID)","in":"path","name":"user_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/utils.ErrorResponse"}}},"description":"Unauthorized"}},"security":[{"BearerAuth":[]}],"summary":"Remove a member (owner/admin)","tags":["Orgs"]}},"/servers":{"get":{"description":"Returns servers for the organization in X-Org-ID. Optional filters: status, role.","operationId":"ListServers","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Filter by status (pending|provisioning|ready|failed)","in":"query","name":"status","schema":{"type":"string"}},{"description":"Filter by role","in":"query","name":"role","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.ServerResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list servers"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List servers (org scoped)","tags":["Servers"]},"post":{"description":"Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org.","operationId":"CreateServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateServerRequest"}}},"description":"Server payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid status / invalid ssh_key_id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create server (org scoped)","tags":["Servers"]}},"/servers/{id}":{"delete":{"description":"Permanently deletes the server.","operationId":"DeleteServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete server (org scoped)","tags":["Servers"]},"get":{"description":"Returns one server in the given organization.","operationId":"GetServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get server by ID (org scoped)","tags":["Servers"]},"patch":{"description":"Partially update fields; changing ssh_key_id validates ownership.","operationId":"UpdateServer","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateServerRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json / invalid status / invalid ssh_key_id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update server (org scoped)","tags":["Servers"]}},"/servers/{id}/reset-hostkey":{"post":{"description":"Clears the stored SSH host key for this server. The next SSH connection will re-learn the host key (trust-on-first-use).","operationId":"ResetServerHostKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Server ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.ServerResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"reset failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Reset SSH host key (org scoped)","tags":["Servers"]}},"/ssh":{"get":{"description":"Returns ssh keys for the organization in X-Org-ID.","operationId":"ListPublicSshKeys","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.SshResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list keys"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List ssh keys (org scoped)","tags":["Ssh"]},"post":{"description":"Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits.","operationId":"CreateSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateSSHRequest"}}},"description":"Key generation options","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.SshResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / invalid bits"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"generation/create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create ssh keypair (org scoped)","tags":["Ssh"]}},"/ssh/{id}":{"delete":{"description":"Permanently deletes a keypair.","operationId":"DeleteSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete ssh keypair (org scoped)","tags":["Ssh"]},"get":{"description":"Returns public key fields. Append `?reveal=true` to include the private key PEM.","operationId":"GetSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Reveal private key PEM","in":"query","name":"reveal","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/dto.SshResponse"},{"$ref":"#/components/schemas/dto.SshRevealResponse"}]}}},"description":"When reveal=true"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get ssh key by ID (org scoped)","tags":["Ssh"]}},"/ssh/{id}/download":{"get":{"description":"Download `part=public|private|both` of the keypair. `both` returns a zip file.","operationId":"DownloadSSHKey","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","required":true,"schema":{"type":"string"}},{"description":"SSH Key ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}},{"description":"Which part to download","in":"query","name":"part","required":true,"schema":{"enum":["public","private","both"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"file content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid part"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"download failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Download ssh key files by ID (org scoped)","tags":["Ssh"]}},"/taints":{"get":{"description":"Returns node taints for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools.","operationId":"ListTaints","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Exact key","in":"query","name":"key","schema":{"type":"string"}},{"description":"Exact value","in":"query","name":"value","schema":{"type":"string"}},{"description":"key contains (case-insensitive)","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/dto.TaintResponse"},"type":"array"}}},"description":"OK"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"failed to list node taints"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"List node pool taints (org scoped)","tags":["Taints"]},"post":{"description":"Creates a taint.","operationId":"CreateTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.CreateTaintRequest"}}},"description":"Taint payload","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid json / missing fields / invalid node_pool_ids"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"create failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Create node taint (org scoped)","tags":["Taints"]}},"/taints/{id}":{"delete":{"description":"Permanently deletes the taint.","operationId":"DeleteTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"delete failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Delete taint (org scoped)","tags":["Taints"]},"get":{"operationId":"GetTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"fetch failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Get node taint by ID (org scoped)","tags":["Taints"]},"patch":{"description":"Partially update taint fields.","operationId":"UpdateTaint","parameters":[{"description":"Organization UUID","in":"header","name":"X-Org-ID","schema":{"type":"string"}},{"description":"Node Taint ID (UUID)","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.UpdateTaintRequest"}}},"description":"Fields to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dto.TaintResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"invalid id / invalid json"},"401":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"organization required"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"not found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"update failed"}},"security":[{"BearerAuth":[]},{"OrgKeyAuth":[]},{"OrgSecretAuth":[]}],"summary":"Update node taint (org scoped)","tags":["Taints"]}},"/version":{"get":{"description":"Returns build/runtime metadata for the running service.","operationId":"Version // operationId","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.VersionResponse"}}},"description":"OK"}},"summary":"Service version information","tags":["Meta"]}}}, "openapi": "3.1.0", "servers": [ {"description":"Production API","url":"https://autoglue.glueopshosted.com/api/v1"}, diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 46c4e7a..9501cd0 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,5 +1,23 @@ components: schemas: + dto.ActionResponse: + properties: + created_at: + format: date-time + type: string + description: + type: string + id: + format: uuid + type: string + label: + type: string + make_target: + type: string + updated_at: + format: date-time + type: string + type: object dto.AnnotationResponse: properties: created_at: @@ -128,6 +146,42 @@ components: updated_at: type: string type: object + dto.ClusterRunResponse: + properties: + action: + type: string + cluster_id: + format: uuid + type: string + created_at: + format: date-time + type: string + error: + type: string + finished_at: + format: date-time + type: string + id: + format: uuid + type: string + organization_id: + format: uuid + type: string + status: + type: string + updated_at: + format: date-time + type: string + type: object + dto.CreateActionRequest: + properties: + description: + type: string + label: + type: string + make_target: + type: string + type: object dto.CreateAnnotationRequest: properties: key: @@ -716,6 +770,15 @@ components: example: Bearer type: string type: object + dto.UpdateActionRequest: + properties: + description: + type: string + label: + type: string + make_target: + type: string + type: object dto.UpdateAnnotationRequest: properties: key: @@ -1202,6 +1265,222 @@ paths: summary: Get JWKS tags: - Auth + /admin/actions: + get: + description: Returns all admin-configured actions. + operationId: ListActions + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/dto.ActionResponse' + type: array + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "500": + content: + application/json: + schema: + type: string + description: db error + security: + - BearerAuth: [] + summary: List available actions + tags: + - Actions + post: + description: Creates a new admin-configured action. + operationId: CreateAction + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/dto.CreateActionRequest' + description: payload + required: true + responses: + "201": + content: + application/json: + schema: + $ref: '#/components/schemas/dto.ActionResponse' + description: Created + "400": + content: + application/json: + schema: + type: string + description: bad request + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "500": + content: + application/json: + schema: + type: string + description: db error + security: + - BearerAuth: [] + summary: Create an action + tags: + - Actions + /admin/actions/{actionID}: + delete: + description: Deletes an action. + operationId: DeleteAction + parameters: + - description: Action ID + in: path + name: actionID + required: true + schema: + type: string + responses: + "204": + content: + application/json: + schema: + type: string + description: deleted + "400": + content: + application/json: + schema: + type: string + description: bad request + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "404": + content: + application/json: + schema: + type: string + description: not found + "500": + content: + application/json: + schema: + type: string + description: db error + security: + - BearerAuth: [] + summary: Delete an action + tags: + - Actions + get: + description: Returns a single action. + operationId: GetAction + parameters: + - description: Action ID + in: path + name: actionID + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/dto.ActionResponse' + description: OK + "400": + content: + application/json: + schema: + type: string + description: bad request + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "404": + content: + application/json: + schema: + type: string + description: not found + "500": + content: + application/json: + schema: + type: string + description: db error + security: + - BearerAuth: [] + summary: Get a single action by ID + tags: + - Actions + patch: + description: Updates an action. Only provided fields are modified. + operationId: UpdateAction + parameters: + - description: Action ID + in: path + name: actionID + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/dto.UpdateActionRequest' + description: payload + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/dto.ActionResponse' + description: OK + "400": + content: + application/json: + schema: + type: string + description: bad request + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "404": + content: + application/json: + schema: + type: string + description: not found + "500": + content: + application/json: + schema: + type: string + description: db error + security: + - BearerAuth: [] + summary: Update an action + tags: + - Actions /admin/archer/jobs: get: description: Paginated background jobs with optional filters. Search `q` may @@ -2124,6 +2403,73 @@ paths: summary: Update basic cluster details (org scoped) tags: - Clusters + /clusters/{clusterID}/actions/{actionID}/runs: + post: + description: Creates a ClusterRun record for the cluster/action. Execution is + handled asynchronously by workers. + operationId: RunClusterAction + parameters: + - description: Organization UUID + in: header + name: X-Org-ID + schema: + type: string + - description: Cluster ID + in: path + name: clusterID + required: true + schema: + type: string + - description: Action ID + in: path + name: actionID + required: true + schema: + type: string + responses: + "201": + content: + application/json: + schema: + $ref: '#/components/schemas/dto.ClusterRunResponse' + description: Created + "400": + content: + application/json: + schema: + type: string + description: bad request + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: organization required + "404": + content: + application/json: + schema: + type: string + description: cluster or action not found + "500": + content: + application/json: + schema: + type: string + description: db error + security: + - BearerAuth: [] + - OrgKeyAuth: [] + - OrgSecretAuth: [] + summary: Run an admin-configured action on a cluster (org scoped) + tags: + - ClusterRuns /clusters/{clusterID}/apps-load-balancer: delete: description: Clears apps_load_balancer_id on the cluster. @@ -3017,6 +3363,128 @@ paths: summary: Detach a node pool from a cluster tags: - Clusters + /clusters/{clusterID}/runs: + get: + description: Returns runs for a cluster within the organization in X-Org-ID. + operationId: ListClusterRuns + parameters: + - description: Organization UUID + in: header + name: X-Org-ID + schema: + type: string + - description: Cluster ID + in: path + name: clusterID + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + $ref: '#/components/schemas/dto.ClusterRunResponse' + type: array + description: OK + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: organization required + "404": + content: + application/json: + schema: + type: string + description: cluster not found + "500": + content: + application/json: + schema: + type: string + description: db error + security: + - BearerAuth: [] + - OrgKeyAuth: [] + - OrgSecretAuth: [] + summary: List cluster runs (org scoped) + tags: + - ClusterRuns + /clusters/{clusterID}/runs/{runID}: + get: + description: Returns a single run for a cluster within the organization in X-Org-ID. + operationId: GetClusterRun + parameters: + - description: Organization UUID + in: header + name: X-Org-ID + schema: + type: string + - description: Cluster ID + in: path + name: clusterID + required: true + schema: + type: string + - description: Run ID + in: path + name: runID + required: true + schema: + type: string + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/dto.ClusterRunResponse' + description: OK + "400": + content: + application/json: + schema: + type: string + description: bad request + "401": + content: + application/json: + schema: + type: string + description: Unauthorized + "403": + content: + application/json: + schema: + type: string + description: organization required + "404": + content: + application/json: + schema: + type: string + description: not found + "500": + content: + application/json: + schema: + type: string + description: db error + security: + - BearerAuth: [] + - OrgKeyAuth: [] + - OrgSecretAuth: [] + summary: Get a cluster run (org scoped) + tags: + - ClusterRuns /credentials: get: description: Returns credential metadata for the current org. Secrets are never diff --git a/internal/api/mount_admin_routes.go b/internal/api/mount_admin_routes.go index 2dfb7c4..5fb19ba 100644 --- a/internal/api/mount_admin_routes.go +++ b/internal/api/mount_admin_routes.go @@ -22,5 +22,16 @@ func mountAdminRoutes(r chi.Router, db *gorm.DB, jobs *bg.Jobs, authUser func(ht archer.Post("/jobs/{id}/cancel", handlers.AdminCancelArcherJob(db)) archer.Get("/queues", handlers.AdminListArcherQueues(db)) }) + admin.Route("/actions", func(action chi.Router) { + action.Use(authUser) + action.Use(httpmiddleware.RequirePlatformAdmin()) + + action.Get("/", handlers.ListActions(db)) + action.Post("/", handlers.CreateAction(db)) + + action.Get("/{actionID}", handlers.GetAction(db)) + action.Patch("/{actionID}", handlers.UpdateAction(db)) + action.Delete("/{actionID}", handlers.DeleteAction(db)) + }) }) } diff --git a/internal/api/mount_api_routes.go b/internal/api/mount_api_routes.go index 27e4dee..300f25a 100644 --- a/internal/api/mount_api_routes.go +++ b/internal/api/mount_api_routes.go @@ -33,7 +33,7 @@ func mountAPIRoutes(r chi.Router, db *gorm.DB, jobs *bg.Jobs) { mountNodePoolRoutes(v1, db, authOrg) mountDNSRoutes(v1, db, authOrg) mountLoadBalancerRoutes(v1, db, authOrg) - mountClusterRoutes(v1, db, authOrg) + mountClusterRoutes(v1, db, jobs, authOrg) }) }) } diff --git a/internal/api/mount_cluster_routes.go b/internal/api/mount_cluster_routes.go index 13a2697..07fa0aa 100644 --- a/internal/api/mount_cluster_routes.go +++ b/internal/api/mount_cluster_routes.go @@ -3,12 +3,13 @@ package api import ( "net/http" + "github.com/glueops/autoglue/internal/bg" "github.com/glueops/autoglue/internal/handlers" "github.com/go-chi/chi/v5" "gorm.io/gorm" ) -func mountClusterRoutes(r chi.Router, db *gorm.DB, authOrg func(http.Handler) http.Handler) { +func mountClusterRoutes(r chi.Router, db *gorm.DB, jobs *bg.Jobs, authOrg func(http.Handler) http.Handler) { r.Route("/clusters", func(c chi.Router) { c.Use(authOrg) c.Get("/", handlers.ListClusters(db)) @@ -36,6 +37,10 @@ func mountClusterRoutes(r chi.Router, db *gorm.DB, authOrg func(http.Handler) ht c.Delete("/{clusterID}/kubeconfig", handlers.ClearClusterKubeconfig(db)) c.Post("/{clusterID}/node-pools", handlers.AttachNodePool(db)) - c.Delete("/{clusterID}/node-pools/{nodePoolID}", handlers.DeleteNodePool(db)) + c.Delete("/{clusterID}/node-pools/{nodePoolID}", handlers.DetachNodePool(db)) + + c.Get("/{clusterID}/runs", handlers.ListClusterRuns(db)) + c.Get("/{clusterID}/runs/{runID}", handlers.GetClusterRun(db)) + c.Post("/{clusterID}/actions/{actionID}/runs", handlers.RunClusterAction(db, jobs)) }) } diff --git a/internal/app/runtime.go b/internal/app/runtime.go index 952f239..0f228bf 100644 --- a/internal/app/runtime.go +++ b/internal/app/runtime.go @@ -44,6 +44,9 @@ func NewRuntime() *Runtime { &models.RecordSet{}, &models.LoadBalancer{}, &models.Cluster{}, + &models.Action{}, + &models.Cluster{}, + &models.ClusterRun{}, ) if err != nil { diff --git a/internal/bg/bg.go b/internal/bg/bg.go index a572f9d..958d78d 100644 --- a/internal/bg/bg.go +++ b/internal/bg/bg.go @@ -107,27 +107,29 @@ func NewJobs(gdb *gorm.DB, dbUrl string) (*Jobs, error) { archer.WithInstances(1), archer.WithTimeout(2*time.Minute), ) + /* + c.Register( + "prepare_cluster", + ClusterPrepareWorker(gdb, jobs), + archer.WithInstances(1), + archer.WithTimeout(2*time.Minute), + ) - c.Register( - "prepare_cluster", - ClusterPrepareWorker(gdb, jobs), - archer.WithInstances(1), - archer.WithTimeout(2*time.Minute), - ) + c.Register( + "cluster_setup", + ClusterSetupWorker(gdb, jobs), + archer.WithInstances(1), + archer.WithTimeout(2*time.Minute), + ) - c.Register( - "cluster_setup", - ClusterSetupWorker(gdb, jobs), - archer.WithInstances(1), - archer.WithTimeout(2*time.Minute), - ) + c.Register( + "cluster_bootstrap", + ClusterBootstrapWorker(gdb, jobs), + archer.WithInstances(1), + archer.WithTimeout(60*time.Minute), + ) - c.Register( - "cluster_bootstrap", - ClusterBootstrapWorker(gdb, jobs), - archer.WithInstances(1), - archer.WithTimeout(60*time.Minute), - ) + */ c.Register( "org_key_sweeper", @@ -135,6 +137,8 @@ func NewJobs(gdb *gorm.DB, dbUrl string) (*Jobs, error) { archer.WithInstances(1), archer.WithTimeout(5*time.Minute), ) + + c.Register("cluster_action", ClusterActionWorker(gdb)) return jobs, nil } diff --git a/internal/bg/cluster_action.go b/internal/bg/cluster_action.go new file mode 100644 index 0000000..c569fac --- /dev/null +++ b/internal/bg/cluster_action.go @@ -0,0 +1,166 @@ +package bg + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/dyaksa/archer" + "github.com/dyaksa/archer/job" + "github.com/glueops/autoglue/internal/mapper" + "github.com/glueops/autoglue/internal/models" + "github.com/glueops/autoglue/internal/utils" + "github.com/google/uuid" + "github.com/rs/zerolog/log" + "gorm.io/gorm" +) + +type ClusterActionArgs struct { + OrgID uuid.UUID `json:"org_id"` + ClusterID uuid.UUID `json:"cluster_id"` + Action string `json:"action"` + MakeTarget string `json:"make_target"` +} + +type ClusterActionResult struct { + Status string `json:"status"` + Action string `json:"action"` + ClusterID string `json:"cluster_id"` + ElapsedMs int `json:"elapsed_ms"` +} + +func ClusterActionWorker(db *gorm.DB) archer.WorkerFn { + return func(ctx context.Context, j job.Job) (any, error) { + start := time.Now() + var args ClusterActionArgs + _ = j.ParseArguments(&args) + + logger := log.With(). + Str("job", j.ID). + Str("cluster_id", args.ClusterID.String()). + Str("action", args.Action). + Logger() + + var c models.Cluster + if err := db. + Preload("BastionServer.SshKey"). + Preload("CaptainDomain"). + Preload("ControlPlaneRecordSet"). + Preload("AppsLoadBalancer"). + Preload("GlueOpsLoadBalancer"). + Preload("NodePools"). + Preload("NodePools.Labels"). + Preload("NodePools.Annotations"). + Preload("NodePools.Taints"). + Preload("NodePools.Servers.SshKey"). + Where("id = ? AND organization_id = ?", args.ClusterID, args.OrgID). + First(&c).Error; err != nil { + + return nil, fmt.Errorf("load cluster: %w", err) + } + + // ---- Step 1: Prepare (mostly lifted from ClusterPrepareWorker) + if err := setClusterStatus(db, c.ID, clusterStatusBootstrapping, ""); err != nil { + return nil, fmt.Errorf("mark bootstrapping: %w", err) + } + c.Status = clusterStatusBootstrapping + + if err := validateClusterForPrepare(&c); err != nil { + _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) + return nil, fmt.Errorf("validate: %w", err) + } + + allServers := flattenClusterServers(&c) + keyPayloads, sshConfig, err := buildSSHAssetsForCluster(db, &c, allServers) + if err != nil { + _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) + return nil, fmt.Errorf("build ssh assets: %w", err) + } + + dtoCluster := mapper.ClusterToDTO(c) + + if c.EncryptedKubeconfig != "" && c.KubeIV != "" && c.KubeTag != "" { + kubeconfig, err := utils.DecryptForOrg( + c.OrganizationID, + c.EncryptedKubeconfig, + c.KubeIV, + c.KubeTag, + db, + ) + if err != nil { + _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) + return nil, fmt.Errorf("decrypt kubeconfig: %w", err) + } + dtoCluster.Kubeconfig = &kubeconfig + } + + orgKey, orgSecret, err := findOrCreateClusterAutomationKey(db, c.OrganizationID, c.ID, 24*time.Hour) + if err != nil { + _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) + return nil, fmt.Errorf("org key: %w", err) + } + dtoCluster.OrgKey = &orgKey + dtoCluster.OrgSecret = &orgSecret + + payloadJSON, err := json.MarshalIndent(dtoCluster, "", " ") + if err != nil { + _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) + return nil, fmt.Errorf("marshal payload: %w", err) + } + + { + runCtx, cancel := context.WithTimeout(ctx, 8*time.Minute) + err := pushAssetsToBastion(runCtx, db, &c, sshConfig, keyPayloads, payloadJSON) + cancel() + if err != nil { + _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) + return nil, fmt.Errorf("push assets: %w", err) + } + } + + if err := setClusterStatus(db, c.ID, clusterStatusPending, ""); err != nil { + return nil, fmt.Errorf("mark pending: %w", err) + } + c.Status = clusterStatusPending + + // ---- Step 2: Setup (ping-servers) + { + runCtx, cancel := context.WithTimeout(ctx, 30*time.Minute) + out, err := runMakeOnBastion(runCtx, db, &c, "ping-servers") + cancel() + if err != nil { + logger.Error().Err(err).Str("output", out).Msg("ping-servers failed") + _ = setClusterStatus(db, c.ID, clusterStatusFailed, fmt.Sprintf("make ping-servers: %v", err)) + return nil, fmt.Errorf("ping-servers: %w", err) + } + } + + if err := setClusterStatus(db, c.ID, clusterStatusProvisioning, ""); err != nil { + return nil, fmt.Errorf("mark provisioning: %w", err) + } + c.Status = clusterStatusProvisioning + + // ---- Step 3: Bootstrap (parameterized target) + { + runCtx, cancel := context.WithTimeout(ctx, 60*time.Minute) + out, err := runMakeOnBastion(runCtx, db, &c, args.MakeTarget) + cancel() + if err != nil { + logger.Error().Err(err).Str("output", out).Msg("bootstrap target failed") + _ = setClusterStatus(db, c.ID, clusterStatusFailed, fmt.Sprintf("make %s: %v", args.MakeTarget, err)) + return nil, fmt.Errorf("make %s: %w", args.MakeTarget, err) + } + } + + if err := setClusterStatus(db, c.ID, clusterStatusReady, ""); err != nil { + return nil, fmt.Errorf("mark ready: %w", err) + } + return ClusterActionResult{ + Status: "ok", + Action: args.Action, + ClusterID: c.ID.String(), + ElapsedMs: int(time.Since(start).Milliseconds()), + }, nil + } +} diff --git a/internal/handlers/actions.go b/internal/handlers/actions.go new file mode 100644 index 0000000..3ce3da1 --- /dev/null +++ b/internal/handlers/actions.go @@ -0,0 +1,256 @@ +package handlers + +import ( + "encoding/json" + "errors" + "net/http" + "strings" + + "github.com/glueops/autoglue/internal/handlers/dto" + "github.com/glueops/autoglue/internal/models" + "github.com/glueops/autoglue/internal/utils" + "github.com/go-chi/chi/v5" + "github.com/google/uuid" + "gorm.io/gorm" +) + +// ListActions godoc +// +// @ID ListActions +// @Summary List available actions +// @Description Returns all admin-configured actions. +// @Tags Actions +// @Produce json +// @Success 200 {array} dto.ActionResponse +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "db error" +// @Router /admin/actions [get] +// @Security BearerAuth +func ListActions(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var rows []models.Action + if err := db.Order("label ASC").Find(&rows).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + out := make([]dto.ActionResponse, 0, len(rows)) + for _, a := range rows { + out = append(out, actionToDTO(a)) + } + utils.WriteJSON(w, http.StatusOK, out) + } +} + +// GetAction godoc +// +// @ID GetAction +// @Summary Get a single action by ID +// @Description Returns a single action. +// @Tags Actions +// @Produce json +// @Param actionID path string true "Action ID" +// @Success 200 {object} dto.ActionResponse +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "db error" +// @Router /admin/actions/{actionID} [get] +// @Security BearerAuth +func GetAction(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + actionID, err := uuid.Parse(chi.URLParam(r, "actionID")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_action_id", "invalid action id") + return + } + + var row models.Action + if err := db.Where("id = ?", actionID).First(&row).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + utils.WriteError(w, http.StatusNotFound, "not_found", "action not found") + return + } + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + utils.WriteJSON(w, http.StatusOK, actionToDTO(row)) + } +} + +// CreateAction godoc +// +// @ID CreateAction +// @Summary Create an action +// @Description Creates a new admin-configured action. +// @Tags Actions +// @Accept json +// @Produce json +// @Param body body dto.CreateActionRequest true "payload" +// @Success 201 {object} dto.ActionResponse +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "db error" +// @Router /admin/actions [post] +// @Security BearerAuth +func CreateAction(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var in dto.CreateActionRequest + if err := json.NewDecoder(r.Body).Decode(&in); err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_json", err.Error()) + return + } + + label := strings.TrimSpace(in.Label) + desc := strings.TrimSpace(in.Description) + target := strings.TrimSpace(in.MakeTarget) + + if label == "" { + utils.WriteError(w, http.StatusBadRequest, "validation_error", "label is required") + return + } + if desc == "" { + utils.WriteError(w, http.StatusBadRequest, "validation_error", "description is required") + return + } + if target == "" { + utils.WriteError(w, http.StatusBadRequest, "validation_error", "make_target is required") + return + } + + row := models.Action{ + Label: label, + Description: desc, + MakeTarget: target, + } + + if err := db.Create(&row).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + utils.WriteJSON(w, http.StatusCreated, actionToDTO(row)) + } +} + +// UpdateAction godoc +// +// @ID UpdateAction +// @Summary Update an action +// @Description Updates an action. Only provided fields are modified. +// @Tags Actions +// @Accept json +// @Produce json +// @Param actionID path string true "Action ID" +// @Param body body dto.UpdateActionRequest true "payload" +// @Success 200 {object} dto.ActionResponse +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "db error" +// @Router /admin/actions/{actionID} [patch] +// @Security BearerAuth +func UpdateAction(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + actionID, err := uuid.Parse(chi.URLParam(r, "actionID")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_action_id", "invalid action id") + return + } + + var in dto.UpdateActionRequest + if err := json.NewDecoder(r.Body).Decode(&in); err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_json", err.Error()) + return + } + + var row models.Action + if err := db.Where("id = ?", actionID).First(&row).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + utils.WriteError(w, http.StatusNotFound, "not_found", "action not found") + return + } + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + if in.Label != nil { + v := strings.TrimSpace(*in.Label) + if v == "" { + utils.WriteError(w, http.StatusBadRequest, "validation_error", "label cannot be empty") + return + } + row.Label = v + } + if in.Description != nil { + v := strings.TrimSpace(*in.Description) + if v == "" { + utils.WriteError(w, http.StatusBadRequest, "validation_error", "description cannot be empty") + return + } + row.Description = v + } + if in.MakeTarget != nil { + v := strings.TrimSpace(*in.MakeTarget) + if v == "" { + utils.WriteError(w, http.StatusBadRequest, "validation_error", "make_target cannot be empty") + return + } + row.MakeTarget = v + } + + if err := db.Save(&row).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + utils.WriteJSON(w, http.StatusOK, actionToDTO(row)) + } +} + +// DeleteAction godoc +// +// @ID DeleteAction +// @Summary Delete an action +// @Description Deletes an action. +// @Tags Actions +// @Produce json +// @Param actionID path string true "Action ID" +// @Success 204 {string} string "deleted" +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "db error" +// @Router /admin/actions/{actionID} [delete] +// @Security BearerAuth +func DeleteAction(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + actionID, err := uuid.Parse(chi.URLParam(r, "actionID")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_action_id", "invalid action id") + return + } + + tx := db.Where("id = ?", actionID).Delete(&models.Action{}) + if tx.Error != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + if tx.RowsAffected == 0 { + utils.WriteError(w, http.StatusNotFound, "not_found", "action not found") + return + } + + w.WriteHeader(http.StatusNoContent) + } +} + +func actionToDTO(a models.Action) dto.ActionResponse { + return dto.ActionResponse{ + ID: a.ID, + Label: a.Label, + Description: a.Description, + MakeTarget: a.MakeTarget, + CreatedAt: a.CreatedAt, + UpdatedAt: a.UpdatedAt, + } +} diff --git a/internal/handlers/cluster_runs.go b/internal/handlers/cluster_runs.go new file mode 100644 index 0000000..6a22f38 --- /dev/null +++ b/internal/handlers/cluster_runs.go @@ -0,0 +1,257 @@ +package handlers + +import ( + "errors" + "net/http" + "time" + + "github.com/dyaksa/archer" + "github.com/glueops/autoglue/internal/api/httpmiddleware" + "github.com/glueops/autoglue/internal/bg" + "github.com/glueops/autoglue/internal/handlers/dto" + "github.com/glueops/autoglue/internal/models" + "github.com/glueops/autoglue/internal/utils" + "github.com/go-chi/chi/v5" + "github.com/google/uuid" + "gorm.io/gorm" +) + +// ListClusterRuns godoc +// +// @ID ListClusterRuns +// @Summary List cluster runs (org scoped) +// @Description Returns runs for a cluster within the organization in X-Org-ID. +// @Tags ClusterRuns +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param clusterID path string true "Cluster ID" +// @Success 200 {array} dto.ClusterRunResponse +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "cluster not found" +// @Failure 500 {string} string "db error" +// @Router /clusters/{clusterID}/runs [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth +func ListClusterRuns(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) + if !ok { + utils.WriteError(w, http.StatusForbidden, "org_required", "specify X-Org-ID") + return + } + + clusterID, err := uuid.Parse(chi.URLParam(r, "clusterID")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_cluster_id", "invalid cluster id") + return + } + + // Ensure cluster exists + org scoped + if err := db.Select("id"). + Where("id = ? AND organization_id = ?", clusterID, orgID). + First(&models.Cluster{}).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + utils.WriteError(w, http.StatusNotFound, "not_found", "cluster not found") + return + } + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + var rows []models.ClusterRun + if err := db. + Where("organization_id = ? AND cluster_id = ?", orgID, clusterID). + Order("created_at DESC"). + Find(&rows).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + out := make([]dto.ClusterRunResponse, 0, len(rows)) + for _, cr := range rows { + out = append(out, clusterRunToDTO(cr)) + } + utils.WriteJSON(w, http.StatusOK, out) + } +} + +// GetClusterRun godoc +// +// @ID GetClusterRun +// @Summary Get a cluster run (org scoped) +// @Description Returns a single run for a cluster within the organization in X-Org-ID. +// @Tags ClusterRuns +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param clusterID path string true "Cluster ID" +// @Param runID path string true "Run ID" +// @Success 200 {object} dto.ClusterRunResponse +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "db error" +// @Router /clusters/{clusterID}/runs/{runID} [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth +func GetClusterRun(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) + if !ok { + utils.WriteError(w, http.StatusForbidden, "org_required", "specify X-Org-ID") + return + } + + clusterID, err := uuid.Parse(chi.URLParam(r, "clusterID")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_cluster_id", "invalid cluster id") + return + } + + runID, err := uuid.Parse(chi.URLParam(r, "runID")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_run_id", "invalid run id") + return + } + + var row models.ClusterRun + if err := db. + Where("id = ? AND organization_id = ? AND cluster_id = ?", runID, orgID, clusterID). + First(&row).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + utils.WriteError(w, http.StatusNotFound, "not_found", "run not found") + return + } + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + utils.WriteJSON(w, http.StatusOK, clusterRunToDTO(row)) + } +} + +// RunClusterAction godoc +// +// @ID RunClusterAction +// @Summary Run an admin-configured action on a cluster (org scoped) +// @Description Creates a ClusterRun record for the cluster/action. Execution is handled asynchronously by workers. +// @Tags ClusterRuns +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param clusterID path string true "Cluster ID" +// @Param actionID path string true "Action ID" +// @Success 201 {object} dto.ClusterRunResponse +// @Failure 400 {string} string "bad request" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "cluster or action not found" +// @Failure 500 {string} string "db error" +// @Router /clusters/{clusterID}/actions/{actionID}/runs [post] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth +func RunClusterAction(db *gorm.DB, jobs *bg.Jobs) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) + if !ok { + utils.WriteError(w, http.StatusForbidden, "org_required", "specify X-Org-ID") + return + } + + clusterID, err := uuid.Parse(chi.URLParam(r, "clusterID")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_cluster_id", "invalid cluster id") + return + } + + actionID, err := uuid.Parse(chi.URLParam(r, "actionID")) + if err != nil { + utils.WriteError(w, http.StatusBadRequest, "bad_action_id", "invalid action id") + return + } + + // cluster must exist + org scoped + var cluster models.Cluster + if err := db.Select("id", "organization_id"). + Where("id = ? AND organization_id = ?", clusterID, orgID). + First(&cluster).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + utils.WriteError(w, http.StatusNotFound, "not_found", "cluster not found") + return + } + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + // action is global/admin-configured (not org scoped) + var action models.Action + if err := db.Where("id = ?", actionID).First(&action).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + utils.WriteError(w, http.StatusNotFound, "action_not_found", "action not found") + return + } + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + run := models.ClusterRun{ + OrganizationID: orgID, + ClusterID: clusterID, + Action: action.MakeTarget, // this is what you actually execute + Status: models.ClusterRunStatusQueued, + Error: "", + FinishedAt: time.Time{}, + } + + if err := db.Create(&run).Error; err != nil { + utils.WriteError(w, http.StatusInternalServerError, "db_error", "db error") + return + } + + // Enqueue with run.ID as the job ID so the worker can look it up. + _, enqueueErr := jobs.Enqueue( + r.Context(), + run.ID.String(), + "cluster_action", + bg.ClusterActionWorker, + archer.WithMaxRetries(3), + ) + + if enqueueErr != nil { + _ = db.Model(&models.ClusterRun{}). + Where("id = ?", run.ID). + Updates(map[string]any{ + "status": models.ClusterRunStatusFailed, + "error": "failed to enqueue job", + "finished_at": time.Now().UTC(), + }).Error + + utils.WriteError(w, http.StatusInternalServerError, "job_error", "failed to enqueue cluster action") + return + } + utils.WriteJSON(w, http.StatusCreated, clusterRunToDTO(run)) + + } +} + +func clusterRunToDTO(cr models.ClusterRun) dto.ClusterRunResponse { + var finished *time.Time + if !cr.FinishedAt.IsZero() { + t := cr.FinishedAt + finished = &t + } + return dto.ClusterRunResponse{ + ID: cr.ID, + OrganizationID: cr.OrganizationID, + ClusterID: cr.ClusterID, + Action: cr.Action, + Status: cr.Status, + Error: cr.Error, + CreatedAt: cr.CreatedAt, + UpdatedAt: cr.UpdatedAt, + FinishedAt: finished, + } +} diff --git a/internal/handlers/dto/actions.go b/internal/handlers/dto/actions.go new file mode 100644 index 0000000..4baeb7f --- /dev/null +++ b/internal/handlers/dto/actions.go @@ -0,0 +1,28 @@ +package dto + +import ( + "time" + + "github.com/google/uuid" +) + +type ActionResponse struct { + ID uuid.UUID `json:"id" format:"uuid"` + Label string `json:"label"` + Description string `json:"description"` + MakeTarget string `json:"make_target"` + CreatedAt time.Time `json:"created_at" format:"date-time"` + UpdatedAt time.Time `json:"updated_at" format:"date-time"` +} + +type CreateActionRequest struct { + Label string `json:"label"` + Description string `json:"description"` + MakeTarget string `json:"make_target"` +} + +type UpdateActionRequest struct { + Label *string `json:"label,omitempty"` + Description *string `json:"description,omitempty"` + MakeTarget *string `json:"make_target,omitempty"` +} diff --git a/internal/handlers/dto/cluster_runs.go b/internal/handlers/dto/cluster_runs.go new file mode 100644 index 0000000..7309c80 --- /dev/null +++ b/internal/handlers/dto/cluster_runs.go @@ -0,0 +1,19 @@ +package dto + +import ( + "time" + + "github.com/google/uuid" +) + +type ClusterRunResponse struct { + ID uuid.UUID `json:"id" format:"uuid"` + OrganizationID uuid.UUID `json:"organization_id" format:"uuid"` + ClusterID uuid.UUID `json:"cluster_id" format:"uuid"` + Action string `json:"action"` + Status string `json:"status"` + Error string `json:"error"` + CreatedAt time.Time `json:"created_at" format:"date-time"` + UpdatedAt time.Time `json:"updated_at" format:"date-time"` + FinishedAt *time.Time `json:"finished_at,omitempty" format:"date-time"` +} diff --git a/internal/models/action.go b/internal/models/action.go new file mode 100644 index 0000000..f8a6b33 --- /dev/null +++ b/internal/models/action.go @@ -0,0 +1,16 @@ +package models + +import ( + "time" + + "github.com/google/uuid" +) + +type Action struct { + ID uuid.UUID `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id" format:"uuid"` + Label string `gorm:"type:varchar(255);not null;uniqueIndex" json:"label"` + Description string `gorm:"type:text;not null" json:"description"` + MakeTarget string `gorm:"type:varchar(255);not null;uniqueIndex" json:"make_target"` + CreatedAt time.Time `json:"created_at,omitempty" gorm:"type:timestamptz;column:created_at;not null;default:now()" format:"date-time"` + UpdatedAt time.Time `json:"updated_at,omitempty" gorm:"type:timestamptz;autoUpdateTime;column:updated_at;not null;default:now()" format:"date-time"` +} diff --git a/internal/models/cluster_runs.go b/internal/models/cluster_runs.go new file mode 100644 index 0000000..35e851e --- /dev/null +++ b/internal/models/cluster_runs.go @@ -0,0 +1,27 @@ +package models + +import ( + "time" + + "github.com/google/uuid" +) + +const ( + ClusterRunStatusQueued = "queued" + ClusterRunStatusRunning = "running" + ClusterRunStatusSuccess = "success" + ClusterRunStatusFailed = "failed" + ClusterRunStatusCanceled = "canceled" +) + +type ClusterRun struct { + ID uuid.UUID `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id" format:"uuid"` + OrganizationID uuid.UUID `json:"organization_id" gorm:"type:uuid;index"` + ClusterID uuid.UUID `json:"cluster_id" gorm:"type:uuid;index"` + Action string `json:"action" gorm:"type:text;not null"` + Status string `json:"status" gorm:"type:text;not null"` + Error string `json:"error" gorm:"type:text;not null"` + CreatedAt time.Time `json:"created_at,omitempty" gorm:"type:timestamptz;column:created_at;not null;default:now()" format:"date-time"` + UpdatedAt time.Time `json:"updated_at,omitempty" gorm:"type:timestamptz;autoUpdateTime;column:updated_at;not null;default:now()" format:"date-time"` + FinishedAt time.Time `json:"finished_at,omitempty" gorm:"type:timestamptz" format:"date-time"` +} diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 65bb33e..5f8f5a6 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -2,6 +2,7 @@ import { AppShell } from "@/layouts/app-shell.tsx" import { Route, Routes } from "react-router-dom" import { ProtectedRoute } from "@/components/protected-route.tsx" +import { ActionsPage } from "@/pages/actions-page.tsx" import { AnnotationPage } from "@/pages/annotation-page.tsx" import { ClustersPage } from "@/pages/cluster-page" import { CredentialPage } from "@/pages/credential-page.tsx" @@ -46,6 +47,7 @@ export default function App() { } /> } /> + } /> } /> diff --git a/ui/src/api/actions.ts b/ui/src/api/actions.ts new file mode 100644 index 0000000..40a55b0 --- /dev/null +++ b/ui/src/api/actions.ts @@ -0,0 +1,30 @@ +import { withRefresh } from "@/api/with-refresh.ts" +import type { DtoCreateActionRequest, DtoUpdateActionRequest } from "@/sdk" +import { makeActionsApi } from "@/sdkClient.ts" + +const actions = makeActionsApi() +export const actionsApi = { + listActions: () => + withRefresh(async () => { + return await actions.listActions() + }), + createAction: (body: DtoCreateActionRequest) => + withRefresh(async () => { + return await actions.createAction({ + dtoCreateActionRequest: body, + }) + }), + updateAction: (id: string, body: DtoUpdateActionRequest) => + withRefresh(async () => { + return await actions.updateAction({ + actionID: id, + dtoUpdateActionRequest: body, + }) + }), + deleteAction: (id: string) => + withRefresh(async () => { + await actions.deleteAction({ + actionID: id, + }) + }), +} diff --git a/ui/src/api/clusters.ts b/ui/src/api/clusters.ts index 520ee38..a6713b4 100644 --- a/ui/src/api/clusters.ts +++ b/ui/src/api/clusters.ts @@ -8,9 +8,10 @@ import type { DtoSetKubeconfigRequest, DtoUpdateClusterRequest, } from "@/sdk" -import { makeClusterApi } from "@/sdkClient" +import { makeClusterApi, makeClusterRunsApi } from "@/sdkClient" const clusters = makeClusterApi() +const clusterRuns = makeClusterRunsApi() export const clustersApi = { // --- basic CRUD --- @@ -147,4 +148,20 @@ export const clustersApi = { withRefresh(async () => { return await clusters.detachNodePool({ clusterID, nodePoolID }) }), + + // --- cluster runs / actions --- + listClusterRuns: (clusterID: string) => + withRefresh(async () => { + return await clusterRuns.listClusterRuns({ clusterID }) + }), + + getClusterRun: (clusterID: string, runID: string) => + withRefresh(async () => { + return await clusterRuns.getClusterRun({ clusterID, runID }) + }), + + runClusterAction: (clusterID: string, actionID: string) => + withRefresh(async () => { + return await clusterRuns.runClusterAction({ clusterID, actionID }) + }), } diff --git a/ui/src/layouts/nav-config.ts b/ui/src/layouts/nav-config.ts index 6ec6487..5add3a2 100644 --- a/ui/src/layouts/nav-config.ts +++ b/ui/src/layouts/nav-config.ts @@ -6,6 +6,7 @@ import { FileKey2Icon, KeyRound, LockKeyholeIcon, + PickaxeIcon, ServerIcon, SprayCanIcon, TagsIcon, @@ -49,5 +50,6 @@ export const userNav: NavItem[] = [{ to: "/me", label: "Profile", icon: User2 }] export const adminNav: NavItem[] = [ { to: "/admin/users", label: "Users Admin", icon: Users }, { to: "/admin/jobs", label: "Jobs Admin", icon: GrUserWorker }, + { to: "/admin/actions", label: "Actions Admin", icon: PickaxeIcon}, { to: "/docs", label: "API Docs ", icon: SiSwagger, target: "_blank" }, ] diff --git a/ui/src/pages/actions-page.tsx b/ui/src/pages/actions-page.tsx new file mode 100644 index 0000000..c24b1af --- /dev/null +++ b/ui/src/pages/actions-page.tsx @@ -0,0 +1,433 @@ +import { useMemo, useState } from "react" +import { actionsApi } from "@/api/actions.ts" +import type { DtoActionResponse } from "@/sdk" +import { zodResolver } from "@hookform/resolvers/zod" +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" +import { AlertCircle, CircleSlash2, Loader2, Pencil, Plus, Search, Trash2 } from "lucide-react" +import { useForm } from "react-hook-form" +import { toast } from "sonner" +import { z } from "zod" + +import { Badge } from "@/components/ui/badge.tsx" +import { Button } from "@/components/ui/button.tsx" +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog.tsx" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form.tsx" +import { Input } from "@/components/ui/input.tsx" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table.tsx" +import { Textarea } from "@/components/ui/textarea.tsx" + +const createActionSchema = z.object({ + label: z.string().trim().min(1, "Label is required").max(255, "Max 255 chars"), + description: z.string().trim().min(1, "Description is required"), + make_target: z + .string() + .trim() + .min(1, "Make target is required") + .max(255, "Max 255 chars") + // keep client-side fairly strict to avoid surprises; server should also validate + .regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/, "Invalid make target (allowed: a-z A-Z 0-9 . _ -)"), +}) +type CreateActionInput = z.input + +const updateActionSchema = createActionSchema.partial() +type UpdateActionInput = z.input + +function TargetBadge({ target }: { target?: string | null }) { + if (!target) { + return ( + + — + + ) + } + return ( + + {target} + + ) +} + +export const ActionsPage = () => { + const qc = useQueryClient() + + const [filter, setFilter] = useState("") + const [createOpen, setCreateOpen] = useState(false) + const [updateOpen, setUpdateOpen] = useState(false) + const [deleteId, setDeleteId] = useState(null) + const [editing, setEditing] = useState(null) + + const actionsQ = useQuery({ + queryKey: ["admin-actions"], + queryFn: () => actionsApi.listActions(), + }) + + const filtered = useMemo(() => { + const data: DtoActionResponse[] = actionsQ.data ?? [] + const q = filter.trim().toLowerCase() + if (!q) return data + + return data.filter((a) => { + return ( + (a.label ?? "").toLowerCase().includes(q) || + (a.description ?? "").toLowerCase().includes(q) || + (a.make_target ?? "").toLowerCase().includes(q) + ) + }) + }, [filter, actionsQ.data]) + + const createForm = useForm({ + resolver: zodResolver(createActionSchema), + defaultValues: { + label: "", + description: "", + make_target: "", + }, + }) + + const createMut = useMutation({ + mutationFn: (values: CreateActionInput) => actionsApi.createAction(values), + onSuccess: async () => { + await qc.invalidateQueries({ queryKey: ["admin-actions"] }) + createForm.reset() + setCreateOpen(false) + toast.success("Action created.") + }, + onError: (err: any) => { + toast.error(err?.message ?? "Failed to create action.") + }, + }) + + const updateForm = useForm({ + resolver: zodResolver(updateActionSchema), + defaultValues: {}, + }) + + const updateMut = useMutation({ + mutationFn: ({ id, values }: { id: string; values: UpdateActionInput }) => + actionsApi.updateAction(id, values), + onSuccess: async () => { + await qc.invalidateQueries({ queryKey: ["admin-actions"] }) + updateForm.reset() + setUpdateOpen(false) + setEditing(null) + toast.success("Action updated.") + }, + onError: (err: any) => { + toast.error(err?.message ?? "Failed to update action.") + }, + }) + + const openEdit = (a: DtoActionResponse) => { + if (!a.id) return + setEditing(a) + updateForm.reset({ + label: a.label ?? "", + description: a.description ?? "", + make_target: a.make_target ?? "", + }) + setUpdateOpen(true) + } + + const deleteMut = useMutation({ + mutationFn: (id: string) => actionsApi.deleteAction(id), + onSuccess: async () => { + await qc.invalidateQueries({ queryKey: ["admin-actions"] }) + setDeleteId(null) + toast.success("Action deleted.") + }, + onError: (err: any) => { + toast.error(err?.message ?? "Failed to delete action.") + }, + }) + + if (actionsQ.isLoading) return
Loading actions…
+ if (actionsQ.error) return
Error loading actions.
+ + return ( +
+
+

Admin Actions

+ +
+
+ + setFilter(e.target.value)} + placeholder="Search actions" + className="w-72 pl-8" + /> +
+ + + + + + + + + Create Action + + +
+ createMut.mutate(v))} + > + ( + + Label + + + + + + )} + /> + + ( + + Make Target + + + + + + )} + /> + + ( + + Description + +