diff --git a/.claude/rules/app-classes.md b/.claude/rules/app-classes.md index 562b233d..b2642a54 100644 --- a/.claude/rules/app-classes.md +++ b/.claude/rules/app-classes.md @@ -112,6 +112,12 @@ Env-scoped read-path controllers (`AlertController`, `AlertRuleController`, `Ale - `DatabaseAdminController` — GET `/api/v1/admin/database/**` (conditional on `infrastructureendpoints` flag). - `ServerMetricsAdminController` — `/api/v1/admin/server-metrics/**`. GET `/catalog`, GET `/instances`, POST `/query`. Generic read API over the `server_metrics` ClickHouse table so SaaS dashboards don't need direct CH access. Delegates to `ServerMetricsQueryStore` (impl `ClickHouseServerMetricsQueryStore`). Visibility matches ClickHouse/Database admin: `@ConditionalOnProperty(infrastructureendpoints, matchIfMissing=true)` + class-level `@PreAuthorize("hasRole('ADMIN')")`. Validation: metric/tag regex `^[a-zA-Z0-9._]+$`, statistic regex `^[a-z_]+$`, `to - from ≤ 31 days`, stepSeconds ∈ [10, 3600], response capped at 500 series. `IllegalArgumentException` → 400. `/query` supports `raw` + `delta` modes (delta does per-`server_instance_id` positive-clipped differences, then aggregates across instances). Derived `statistic=mean` for timers computes `sum(total|total_time)/sum(count)` per bucket. +### Auth (flat) + +- `UiAuthController` — `/api/v1/auth` (login, refresh, me). Local username/password against env-var admin or DB BCrypt hash. Lockout after 5 failed attempts. +- `OidcAuthController` — `/api/v1/auth/oidc` (config, callback). Code → token exchange. Roles via custom JWT claim, claim mapping rules, or default roles. +- `AuthCapabilitiesController` — `GET /api/v1/auth/capabilities` (unauthenticated). Reports `{oidc:{enabled, providerName, primary}, localAccounts:{enabled, adminRecoveryOnly}}` so the SPA renders the login page deterministically. `oidc.primary == oidc.enabled`; `localAccounts.adminRecoveryOnly == oidc.primary`. `providerName` is best-effort label via `OidcProviderNameDeriver` (Logto / Keycloak / Auth0 / Okta / Single Sign-On). The SPA hides the local form behind `?local` when `adminRecoveryOnly` is true. + ### Other (flat) - `DetailController` — GET `/api/v1/executions/{executionId}` + processor snapshot endpoints. diff --git a/CLAUDE.md b/CLAUDE.md index 288b1058..b27217d2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -59,6 +59,7 @@ java -jar cameleer-server-app/target/cameleer-server-app-1.0-SNAPSHOT.jar - Log processor correlation: The agent sets `cameleer.processorId` in MDC, identifying which processor node emitted a log line. - Logging: ClickHouse JDBC set to INFO (`com.clickhouse`), HTTP client to WARN (`org.apache.hc.client5`) in application.yml - Security: JWT auth with RBAC (AGENT/VIEWER/OPERATOR/ADMIN roles), Ed25519 config signing (key derived deterministically from JWT secret via HMAC-SHA256), bootstrap token for registration. CORS: `CAMELEER_SERVER_SECURITY_CORSALLOWEDORIGINS` (comma-separated) overrides `CAMELEER_SERVER_SECURITY_UIORIGIN` for multi-origin setups. Infrastructure access: `CAMELEER_SERVER_SECURITY_INFRASTRUCTUREENDPOINTS=false` disables Database and ClickHouse admin endpoints. Last-ADMIN guard: system prevents removal of the last ADMIN role (409 Conflict). Password policy: min 12 chars, 3-of-4 character classes, no username match. Brute-force protection: 5 failed attempts -> 15 min lockout. Token revocation: `token_revoked_before` column on users, checked in `JwtAuthenticationFilter`, set on password change. +- Login routing: `GET /api/v1/auth/capabilities` (unauthenticated) tells the SPA whether OIDC is the primary entry point. When OIDC is configured, the SSO button is the primary CTA and the local form is hidden behind `?local` (admin-recovery escape hatch). Per RFC 9700 §4.4 we do **not** use `prompt=none` for primary login — that returns `login_required` for first-time users and traps them on a local form. - OIDC: Optional external identity provider support (token exchange pattern). Configured via admin API/UI, stored in database (`server_config` table). Resource server mode: accepts external access tokens (Logto M2M) via JWKS validation when `CAMELEER_SERVER_SECURITY_OIDCISSUERURI` is set. Scope-based role mapping via `SystemRole.normalizeScope()`. System roles synced on every OIDC login via `applyClaimMappings()` in `OidcAuthController` (calls `clearManagedAssignments` + `assignManagedRole` on `RbacService`) — always overwrites managed role assignments; uses managed assignment origin to avoid touching group-inherited or directly-assigned roles. Supports ES384, ES256, RS256. - OIDC role extraction: `OidcTokenExchanger` reads roles from the **access_token** first (JWT with `at+jwt` type), then falls back to id_token. `OidcConfig` includes `audience` (RFC 8707 resource indicator) and `additionalScopes`. All provider-specific configuration is external — no provider-specific code in the server. - Sensitive keys: Global enforced baseline for masking sensitive data in agent payloads. Merge rule: `final = global UNION per-app` (case-insensitive dedup, per-app can only add, never remove global keys). @@ -96,7 +97,7 @@ When adding, removing, or renaming classes, controllers, endpoints, UI component # GitNexus — Code Intelligence -This project is indexed by GitNexus as **cameleer-server** (9731 symbols, 24987 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. +This project is indexed by GitNexus as **cameleer-server** (10530 symbols, 27383 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. > If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. diff --git a/cameleer-server-app/src/main/java/com/cameleer/server/app/dto/AuthCapabilitiesResponse.java b/cameleer-server-app/src/main/java/com/cameleer/server/app/dto/AuthCapabilitiesResponse.java index ef2c4b0a..7466af68 100644 --- a/cameleer-server-app/src/main/java/com/cameleer/server/app/dto/AuthCapabilitiesResponse.java +++ b/cameleer-server-app/src/main/java/com/cameleer/server/app/dto/AuthCapabilitiesResponse.java @@ -1,7 +1,6 @@ package com.cameleer.server.app.dto; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; @Schema(description = "Authentication capabilities reported to the SPA so it can render the login page deterministically") public record AuthCapabilitiesResponse( @@ -12,7 +11,7 @@ public record AuthCapabilitiesResponse( @Schema(description = "OIDC interactive login") public record Oidc( @Schema(description = "Whether OIDC is configured AND enabled") boolean enabled, - @Schema(description = "Best-effort display label, e.g. \"Logto\", \"Keycloak\", \"Single Sign-On\"") @NotNull String providerName, + @Schema(description = "Best-effort display label, e.g. \"Logto\", \"Keycloak\", \"Single Sign-On\"") String providerName, @Schema(description = "When true, OIDC is the canonical entry point and the SPA hides the local form unless ?local is set") boolean primary ) {} diff --git a/cameleer-server-app/src/main/java/com/cameleer/server/app/security/AuthCapabilitiesController.java b/cameleer-server-app/src/main/java/com/cameleer/server/app/security/AuthCapabilitiesController.java new file mode 100644 index 00000000..3f08b5ab --- /dev/null +++ b/cameleer-server-app/src/main/java/com/cameleer/server/app/security/AuthCapabilitiesController.java @@ -0,0 +1,52 @@ +package com.cameleer.server.app.security; + +import com.cameleer.server.app.dto.AuthCapabilitiesResponse; +import com.cameleer.server.core.security.OidcConfig; +import com.cameleer.server.core.security.OidcConfigRepository; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Optional; + +/** + * Reports auth capabilities so the SPA renders the login page deterministically + * instead of inferring from {@code GET /api/v1/auth/oidc/config} 200/404. + * + *

Unauthenticated by design — the SPA calls this before any sign-in attempt. + * Inherits permit-all from the {@code /api/v1/auth/**} matcher in + * {@link SecurityConfig}. + * + *

Future deferred work (issue #154) extends this same payload with MFA + * enrollment URL and password-reset URL fields. + */ +@RestController +@RequestMapping("/api/v1/auth") +@Tag(name = "Authentication", description = "Login and token refresh endpoints") +public class AuthCapabilitiesController { + + private final OidcConfigRepository oidcConfigRepository; + + public AuthCapabilitiesController(OidcConfigRepository oidcConfigRepository) { + this.oidcConfigRepository = oidcConfigRepository; + } + + @GetMapping("/capabilities") + @Operation(summary = "Auth capabilities for the SPA login page") + @ApiResponse(responseCode = "200", description = "Capabilities resolved") + public ResponseEntity getCapabilities() { + Optional config = oidcConfigRepository.find(); + boolean oidcEnabled = config.isPresent() && config.get().enabled(); + String providerName = oidcEnabled + ? OidcProviderNameDeriver.deriveName(config.get().issuerUri()) + : ""; + + var oidc = new AuthCapabilitiesResponse.Oidc(oidcEnabled, providerName, oidcEnabled); + var local = new AuthCapabilitiesResponse.LocalAccounts(true, oidcEnabled); + return ResponseEntity.ok(new AuthCapabilitiesResponse(oidc, local)); + } +} diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AuthCapabilitiesControllerIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AuthCapabilitiesControllerIT.java new file mode 100644 index 00000000..369d8fb3 --- /dev/null +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AuthCapabilitiesControllerIT.java @@ -0,0 +1,96 @@ +package com.cameleer.server.app.controller; + +import com.cameleer.server.app.AbstractPostgresIT; +import com.cameleer.server.app.dto.AuthCapabilitiesResponse; +import com.cameleer.server.core.security.OidcConfig; +import com.cameleer.server.core.security.OidcConfigRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.client.TestRestTemplate; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +/** + * Integration tests for {@link com.cameleer.server.app.security.AuthCapabilitiesController}. + * Mocks {@link OidcConfigRepository} so each test controls the OIDC state it observes. + */ +class AuthCapabilitiesControllerIT extends AbstractPostgresIT { + + @Autowired private TestRestTemplate restTemplate; + @MockBean private OidcConfigRepository oidcConfigRepository; + + @BeforeEach + void resetMock() { + when(oidcConfigRepository.find()).thenReturn(Optional.empty()); + } + + @Test + void noOidcConfig_returnsLocalOnlyCaps() { + var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", AuthCapabilitiesResponse.class); + + assertThat(resp.getStatusCode().value()).isEqualTo(200); + assertThat(resp.getBody()).isNotNull(); + assertThat(resp.getBody().oidc().enabled()).isFalse(); + assertThat(resp.getBody().oidc().providerName()).isEqualTo(""); + assertThat(resp.getBody().oidc().primary()).isFalse(); + assertThat(resp.getBody().localAccounts().enabled()).isTrue(); + assertThat(resp.getBody().localAccounts().adminRecoveryOnly()).isFalse(); + } + + @Test + void oidcDisabledRow_behavesLikeAbsent() { + OidcConfig disabled = new OidcConfig(false, "https://auth.logto.example/", "client-id", "secret", + "roles", List.of("VIEWER"), true, "name", "sub", "", List.of()); + when(oidcConfigRepository.find()).thenReturn(Optional.of(disabled)); + + var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", AuthCapabilitiesResponse.class); + + assertThat(resp.getStatusCode().value()).isEqualTo(200); + assertThat(resp.getBody().oidc().enabled()).isFalse(); + assertThat(resp.getBody().oidc().providerName()).isEqualTo(""); + assertThat(resp.getBody().oidc().primary()).isFalse(); + assertThat(resp.getBody().localAccounts().adminRecoveryOnly()).isFalse(); + } + + @Test + void oidcEnabledLogto_returnsOidcPrimaryWithProviderName() { + OidcConfig enabled = new OidcConfig(true, "https://auth.logto.example/", "client-id", "secret", + "roles", List.of("VIEWER"), true, "name", "sub", "", List.of()); + when(oidcConfigRepository.find()).thenReturn(Optional.of(enabled)); + + var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", AuthCapabilitiesResponse.class); + + assertThat(resp.getStatusCode().value()).isEqualTo(200); + assertThat(resp.getBody().oidc().enabled()).isTrue(); + assertThat(resp.getBody().oidc().providerName()).isEqualTo("Logto"); + assertThat(resp.getBody().oidc().primary()).isTrue(); + assertThat(resp.getBody().localAccounts().enabled()).isTrue(); + assertThat(resp.getBody().localAccounts().adminRecoveryOnly()).isTrue(); + } + + @Test + void oidcEnabledUnknownProvider_returnsGenericProviderName() { + OidcConfig enabled = new OidcConfig(true, "https://idp.example.com/", "client-id", "secret", + "roles", List.of("VIEWER"), true, "name", "sub", "", List.of()); + when(oidcConfigRepository.find()).thenReturn(Optional.of(enabled)); + + var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", AuthCapabilitiesResponse.class); + + assertThat(resp.getStatusCode().value()).isEqualTo(200); + assertThat(resp.getBody().oidc().providerName()).isEqualTo("Single Sign-On"); + assertThat(resp.getBody().oidc().primary()).isTrue(); + assertThat(resp.getBody().localAccounts().adminRecoveryOnly()).isTrue(); + } + + @Test + void endpointIsUnauthenticated() { + var resp = restTemplate.getForEntity("/api/v1/auth/capabilities", String.class); + assertThat(resp.getStatusCode().value()).isEqualTo(200); + } +} diff --git a/ui/src/api/openapi.json b/ui/src/api/openapi.json index a873069e..915dcc4e 100644 --- a/ui/src/api/openapi.json +++ b/ui/src/api/openapi.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"Cameleer Server API","version":"1.0"},"servers":[{"url":"/api/v1","description":"Relative"}],"security":[{"bearer":[]}],"tags":[{"name":"Route Metrics","description":"Route performance metrics (env-scoped)"},{"name":"Database Admin","description":"Database monitoring and management (ADMIN only)"},{"name":"Threshold Admin","description":"Monitoring threshold configuration (ADMIN only)"},{"name":"Agent Commands","description":"Command push endpoints for agent communication"},{"name":"Agent List","description":"List registered agents in an environment"},{"name":"Sensitive Keys Admin","description":"Global sensitive key masking configuration (ADMIN only)"},{"name":"License Admin","description":"License management"},{"name":"Role Admin","description":"Role management (ADMIN only)"},{"name":"RBAC Stats","description":"RBAC statistics (ADMIN only)"},{"name":"OIDC Config Admin","description":"OIDC provider configuration (ADMIN only)"},{"name":"Alerts Inbox","description":"In-app alert inbox, ack and read tracking (env-scoped)"},{"name":"Application Config","description":"Per-application observability configuration (user-facing)"},{"name":"App Management","description":"Application lifecycle and JAR uploads (env-scoped)"},{"name":"Catalog","description":"Unified application catalog"},{"name":"ClickHouse Admin","description":"ClickHouse monitoring and diagnostics (ADMIN only)"},{"name":"Alert Silences","description":"Alert silence management (env-scoped)"},{"name":"Ingestion","description":"Data ingestion endpoints"},{"name":"Group Admin","description":"Group management (ADMIN only)"},{"name":"Usage Analytics","description":"UI usage pattern analytics"},{"name":"Alert Notifications","description":"Outbound webhook notification management"},{"name":"Deployment Management","description":"Deploy, stop, promote, and view logs"},{"name":"Detail","description":"Execution detail and processor snapshot endpoints"},{"name":"Server Self-Metrics","description":"Read API over the server's own Micrometer registry snapshots (ADMIN only)"},{"name":"Outbound Connections Admin","description":"Admin-managed outbound HTTPS destinations"},{"name":"Agent Config","description":"Agent-authoritative config read (AGENT only)"},{"name":"User Admin","description":"User management (ADMIN only)"},{"name":"Agent Management","description":"Agent registration and lifecycle endpoints"},{"name":"Authentication","description":"Login and token refresh endpoints"},{"name":"Agent Events","description":"Agent lifecycle event log (env-scoped)"},{"name":"Route Catalog","description":"Route catalog and discovery (env-scoped)"},{"name":"Application Logs","description":"Query application logs (env-scoped)"},{"name":"Agent SSE","description":"Server-Sent Events endpoint for agent communication"},{"name":"Search","description":"Transaction search and stats (env-scoped)"},{"name":"Audit Log","description":"Audit log viewer (ADMIN only)"},{"name":"Claim Mapping Admin","description":"Manage OIDC claim-to-role/group mapping rules"},{"name":"Diagrams","description":"Diagram rendering endpoints"},{"name":"Environment Admin","description":"Environment management (ADMIN only)"},{"name":"App Settings","description":"Per-application dashboard settings (ADMIN/OPERATOR)"},{"name":"Alert Rules","description":"Alert rule management (env-scoped)"}],"paths":{"/environments/{envSlug}/apps/{appSlug}/settings":{"get":{"tags":["App Settings"],"summary":"Get settings for an application in this environment (returns defaults if not configured)","operationId":"getByAppId","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppSettings"}}}}}},"put":{"tags":["App Settings"],"summary":"Create or update settings for an application in this environment","operationId":"update","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppSettings"}}}}}},"delete":{"tags":["App Settings"],"summary":"Delete application settings for this environment (reverts to defaults)","operationId":"delete","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/apps/{appSlug}/container-config":{"put":{"tags":["App Management"],"summary":"Update container config for this app","operationId":"updateContainerConfig","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}},"required":true},"responses":{"200":{"description":"Container config updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid configuration","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"App not found in this environment","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/config":{"get":{"tags":["Application Config"],"summary":"Get application config for this environment","description":"Returns stored config merged with global sensitive keys. Falls back to defaults if no row is persisted yet.","operationId":"getConfig","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Config returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppConfigResponse"}}}}}},"put":{"tags":["Application Config"],"summary":"Update application config for this environment","description":"Saves config. When apply=live (default), also pushes CONFIG_UPDATE to LIVE agents. When apply=staged, persists without a live push — the next successful deploy applies it.","operationId":"updateConfig","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"apply","in":"query","description":"When to apply: 'live' (default) saves and pushes CONFIG_UPDATE to live agents immediately; 'staged' saves without pushing — the next successful deploy applies it.","required":false,"schema":{"type":"string","default":"live"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationConfig"}}},"required":true},"responses":{"200":{"description":"Config saved (and pushed if apply=live)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ConfigUpdateResponse"}}}},"400":{"description":"Unknown apply value (must be 'staged' or 'live')","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ConfigUpdateResponse"}}}}}}},"/environments/{envSlug}/alerts/silences/{id}":{"put":{"tags":["Alert Silences"],"operationId":"update_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertSilenceRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertSilenceResponse"}}}}}},"delete":{"tags":["Alert Silences"],"operationId":"delete_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/rules/{id}":{"get":{"tags":["Alert Rules"],"operationId":"get","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}},"put":{"tags":["Alert Rules"],"operationId":"update_2","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}},"delete":{"tags":["Alert Rules"],"operationId":"delete_2","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/admin/users/{userId}":{"get":{"tags":["User Admin"],"summary":"Get user by ID with RBAC detail","operationId":"getUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}}}},"put":{"tags":["User Admin"],"summary":"Update user display name or email","operationId":"updateUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated"},"404":{"description":"User not found"}}},"delete":{"tags":["User Admin"],"summary":"Delete user","operationId":"deleteUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"User deleted"},"409":{"description":"Cannot delete the last admin user"}}}},"/admin/thresholds":{"get":{"tags":["Threshold Admin"],"summary":"Get current threshold configuration","operationId":"getThresholds","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ThresholdConfig"}}}}}},"put":{"tags":["Threshold Admin"],"summary":"Update threshold configuration","operationId":"updateThresholds","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThresholdConfigRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ThresholdConfig"}}}}}}},"/admin/sensitive-keys":{"get":{"tags":["Sensitive Keys Admin"],"summary":"Get global sensitive keys configuration","operationId":"getSensitiveKeys","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SensitiveKeysConfig"}}}}}},"put":{"tags":["Sensitive Keys Admin"],"summary":"Update global sensitive keys configuration","description":"Saves the global sensitive keys. Optionally fans out merged keys to all live agents.","operationId":"updateSensitiveKeys","parameters":[{"name":"pushToAgents","in":"query","required":false,"schema":{"type":"boolean","default":false}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveKeysRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SensitiveKeysResponse"}}}}}}},"/admin/roles/{id}":{"get":{"tags":["Role Admin"],"summary":"Get role by ID with effective principals","operationId":"getRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RoleDetail"}}}},"404":{"description":"Role not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RoleDetail"}}}}}},"put":{"tags":["Role Admin"],"summary":"Update a custom role","operationId":"updateRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role updated"},"403":{"description":"Cannot modify system role"},"404":{"description":"Role not found"}}},"delete":{"tags":["Role Admin"],"summary":"Delete a custom role","operationId":"deleteRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role deleted"},"403":{"description":"Cannot delete system role"},"404":{"description":"Role not found"}}}},"/admin/outbound-connections/{id}":{"get":{"tags":["Outbound Connections Admin"],"operationId":"get_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OutboundConnectionDto"}}}}}},"put":{"tags":["Outbound Connections Admin"],"operationId":"update_3","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundConnectionRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OutboundConnectionDto"}}}}}},"delete":{"tags":["Outbound Connections Admin"],"operationId":"delete_3","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/admin/oidc":{"get":{"tags":["OIDC Config Admin"],"summary":"Get OIDC configuration","operationId":"getConfig_1","responses":{"200":{"description":"Current OIDC configuration (client_secret masked)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcAdminConfigResponse"}}}}}},"put":{"tags":["OIDC Config Admin"],"summary":"Save OIDC configuration","operationId":"saveConfig","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcAdminConfigRequest"}}},"required":true},"responses":{"200":{"description":"Configuration saved","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcAdminConfigResponse"}}}},"400":{"description":"Invalid configuration","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["OIDC Config Admin"],"summary":"Delete OIDC configuration","operationId":"deleteConfig","responses":{"204":{"description":"Configuration deleted"}}}},"/admin/groups/{id}":{"get":{"tags":["Group Admin"],"summary":"Get group by ID with effective roles","operationId":"getGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Group found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupDetail"}}}},"404":{"description":"Group not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupDetail"}}}}}},"put":{"tags":["Group Admin"],"summary":"Update group name or parent","operationId":"updateGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroupRequest"}}},"required":true},"responses":{"200":{"description":"Group updated"},"404":{"description":"Group not found"},"409":{"description":"Cycle detected in group hierarchy"}}},"delete":{"tags":["Group Admin"],"summary":"Delete group","operationId":"deleteGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Group deleted"},"404":{"description":"Group not found"}}}},"/admin/environments/{envSlug}":{"get":{"tags":["Environment Admin"],"summary":"Get environment by slug","operationId":"getEnvironment","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Environment"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Environment"}}}}}},"put":{"tags":["Environment Admin"],"summary":"Update an environment's mutable fields (displayName, production, enabled, color)","description":"Slug is immutable after creation and cannot be changed. Any slug field in the request body is ignored. If color is null or absent, the existing color is preserved.","operationId":"updateEnvironment","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown color value","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"type":"object"}}}}}},"delete":{"tags":["Environment Admin"],"summary":"Delete an environment","operationId":"deleteEnvironment","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Environment deleted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot delete default environment","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/environments/{envSlug}/jar-retention":{"put":{"tags":["Environment Admin"],"summary":"Update JAR retention policy for an environment","operationId":"updateJarRetention","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JarRetentionRequest"}}},"required":true},"responses":{"200":{"description":"Retention policy updated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/environments/{envSlug}/default-container-config":{"put":{"tags":["Environment Admin"],"summary":"Update default container config for an environment","operationId":"updateDefaultContainerConfig","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}},"required":true},"responses":{"200":{"description":"Default container config updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid configuration","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/claim-mappings/{id}":{"get":{"tags":["Claim Mapping Admin"],"summary":"Get a claim mapping rule by ID","operationId":"get_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClaimMappingRule"}}}}}},"put":{"tags":["Claim Mapping Admin"],"summary":"Update a claim mapping rule","operationId":"update_4","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRuleRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClaimMappingRule"}}}}}},"delete":{"tags":["Claim Mapping Admin"],"summary":"Delete a claim mapping rule","operationId":"delete_4","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/executions/search":{"post":{"tags":["Search"],"summary":"Advanced search with all filters","description":"Env from the path overrides any environment field in the body.","operationId":"searchPost","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SearchResultExecutionSummary"}}}}}}},"/environments/{envSlug}/apps":{"get":{"tags":["App Management"],"summary":"List apps in this environment","operationId":"listApps","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"App list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/App"}}}}}}},"post":{"tags":["App Management"],"summary":"Create a new app in this environment","description":"Slug must match ^[a-z0-9][a-z0-9-]{0,63}$ and be unique within the environment. Slug is immutable after creation.","operationId":"createApp","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAppRequest"}}},"required":true},"responses":{"201":{"description":"App created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid slug, or slug already exists in this environment","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/versions":{"get":{"tags":["App Management"],"summary":"List versions for this app","operationId":"listVersions","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Version list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AppVersion"}}}}}}},"post":{"tags":["App Management"],"summary":"Upload a JAR for a new version of this app","operationId":"uploadJar","parameters":[{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"env":{"$ref":"#/components/schemas/Environment"},"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"201":{"description":"JAR uploaded and version created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppVersion"}}}},"404":{"description":"App not found in this environment","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppVersion"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments":{"get":{"tags":["Deployment Management"],"summary":"List deployments for this app in this environment","operationId":"listDeployments","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deployment list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Deployment"}}}}}}},"post":{"tags":["Deployment Management"],"summary":"Create and start a new deployment for this app in this environment","operationId":"deploy","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployRequest"}}},"required":true},"responses":{"202":{"description":"Deployment accepted and starting","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments/{deploymentId}/stop":{"post":{"tags":["Deployment Management"],"summary":"Stop a running deployment","operationId":"stop","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deployment stopped","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}},"404":{"description":"Deployment not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments/{deploymentId}/promote":{"post":{"tags":["Deployment Management"],"summary":"Promote this deployment to a different environment","description":"Target environment is specified by slug in the request body. The same app slug must exist in the target environment (or be created separately first).","operationId":"promote","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteRequest"}}},"required":true},"responses":{"202":{"description":"Promotion accepted and starting","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Deployment or target environment not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/config/test-expression":{"post":{"tags":["Application Config"],"summary":"Test a tap expression against sample data via a live agent in this environment","operationId":"testExpression","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestExpressionRequest"}}},"required":true},"responses":{"200":{"description":"Expression evaluated successfully","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestExpressionResponse"}}}},"404":{"description":"No live agent available for this application in this environment","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestExpressionResponse"}}}},"504":{"description":"Agent did not respond in time","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestExpressionResponse"}}}}}}},"/environments/{envSlug}/alerts/{id}/restore":{"post":{"tags":["Alerts Inbox"],"operationId":"restore","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/{id}/read":{"post":{"tags":["Alerts Inbox"],"operationId":"read","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/{id}/ack":{"post":{"tags":["Alerts Inbox"],"operationId":"ack","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertDto"}}}}}}},"/environments/{envSlug}/alerts/silences":{"get":{"tags":["Alert Silences"],"operationId":"list","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertSilenceResponse"}}}}}}},"post":{"tags":["Alert Silences"],"operationId":"create","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertSilenceRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertSilenceResponse"}}}}}}},"/environments/{envSlug}/alerts/rules":{"get":{"tags":["Alert Rules"],"operationId":"list_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}}},"post":{"tags":["Alert Rules"],"operationId":"create_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}}},"/environments/{envSlug}/alerts/rules/{id}/test-evaluate":{"post":{"tags":["Alert Rules"],"operationId":"testEvaluate","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEvaluateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestEvaluateResponse"}}}}}}},"/environments/{envSlug}/alerts/rules/{id}/render-preview":{"post":{"tags":["Alert Rules"],"operationId":"renderPreview","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderPreviewRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RenderPreviewResponse"}}}}}}},"/environments/{envSlug}/alerts/rules/{id}/enable":{"post":{"tags":["Alert Rules"],"operationId":"enable","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}}},"/environments/{envSlug}/alerts/rules/{id}/disable":{"post":{"tags":["Alert Rules"],"operationId":"disable","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}}},"/environments/{envSlug}/alerts/bulk-read":{"post":{"tags":["Alerts Inbox"],"operationId":"bulkRead","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIdsRequest"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/bulk-delete":{"post":{"tags":["Alerts Inbox"],"operationId":"bulkDelete","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIdsRequest"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/bulk-ack":{"post":{"tags":["Alerts Inbox"],"operationId":"bulkAck","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIdsRequest"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/data/metrics":{"post":{"tags":["Ingestion"],"summary":"Ingest agent metrics","description":"Accepts an array of MetricsSnapshot objects","operationId":"ingestMetrics","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"202":{"description":"Data accepted for processing"},"400":{"description":"Invalid payload"},"503":{"description":"Buffer full, retry later"}}}},"/data/logs":{"post":{"tags":["Ingestion"],"summary":"Ingest application log entries","description":"Accepts a batch of log entries from an agent. Entries are buffered and flushed periodically.","operationId":"ingestLogs","requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LogEntry"}}}},"required":true},"responses":{"202":{"description":"Logs accepted for indexing"}}}},"/data/executions":{"post":{"tags":["Ingestion"],"summary":"Ingest execution chunk","operationId":"ingestChunks","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/data/events":{"post":{"tags":["Ingestion"],"summary":"Ingest agent events","operationId":"ingestEvents","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/data/diagrams":{"post":{"tags":["Ingestion"],"summary":"Ingest route diagram data","description":"Accepts a single RouteGraph or an array of RouteGraphs","operationId":"ingestDiagrams","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"202":{"description":"Data accepted for processing"}}}},"/auth/refresh":{"post":{"tags":["Authentication"],"summary":"Refresh access token","operationId":"refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"Token refreshed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"Invalid refresh token","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/oidc/callback":{"post":{"tags":["Authentication"],"summary":"Exchange OIDC authorization code for JWTs","operationId":"callback","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallbackRequest"}}},"required":true},"responses":{"200":{"description":"Authentication successful","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"OIDC authentication failed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Account not provisioned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"OIDC not configured or disabled","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}}}}},"/auth/login":{"post":{"tags":["Authentication"],"summary":"Login with local credentials","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"Invalid credentials","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Account locked due to too many failed attempts","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}}}}},"/alerts/notifications/{id}/retry":{"post":{"tags":["Alert Notifications"],"operationId":"retry","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertNotificationDto"}}}}}}},"/agents/{id}/replay":{"post":{"tags":["Agent Commands"],"summary":"Replay an exchange on a specific agent (synchronous)","description":"Sends a replay command and waits for the agent to complete the replay. Returns the replay result including status, replayExchangeId, and duration.","operationId":"replayExchange","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplayRequest"}}},"required":true},"responses":{"200":{"description":"Replay completed (check status for success/failure)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ReplayResponse"}}}},"404":{"description":"Agent not found or not connected","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ReplayResponse"}}}},"504":{"description":"Agent did not respond in time","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ReplayResponse"}}}}}}},"/agents/{id}/refresh":{"post":{"tags":["Agent Management"],"summary":"Refresh access token","description":"Issues a new access JWT from a valid refresh token","operationId":"refresh_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRefreshRequest"}}},"required":true},"responses":{"200":{"description":"New access token issued","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRefreshResponse"}}}},"401":{"description":"Invalid or expired refresh token","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRefreshResponse"}}}},"404":{"description":"Agent not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRefreshResponse"}}}}}}},"/agents/{id}/heartbeat":{"post":{"tags":["Agent Management"],"summary":"Agent heartbeat ping","description":"Updates the agent's last heartbeat timestamp. Auto-registers the agent if not in registry (e.g. after server restart).","operationId":"heartbeat","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatRequest"}}}},"responses":{"200":{"description":"Heartbeat accepted"}}}},"/agents/{id}/deregister":{"post":{"tags":["Agent Management"],"summary":"Deregister agent","description":"Removes the agent from the registry. Called by agents during graceful shutdown.","operationId":"deregister","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent deregistered"},"404":{"description":"Agent not registered"}}}},"/agents/{id}/commands":{"post":{"tags":["Agent Commands"],"summary":"Send command to a specific agent","description":"Sends a command to the specified agent via SSE","operationId":"sendCommand","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"}}},"required":true},"responses":{"202":{"description":"Command accepted","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandSingleResponse"}}}},"400":{"description":"Invalid command payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandSingleResponse"}}}},"404":{"description":"Agent not registered","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandSingleResponse"}}}}}}},"/agents/{id}/commands/{commandId}/ack":{"post":{"tags":["Agent Commands"],"summary":"Acknowledge command receipt","description":"Agent acknowledges that it has received and processed a command, with result status and message","operationId":"acknowledgeCommand","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"commandId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandAckRequest"}}}},"responses":{"200":{"description":"Command acknowledged"},"404":{"description":"Command not found"}}}},"/agents/register":{"post":{"tags":["Agent Management"],"summary":"Register an agent","description":"Registers a new agent or re-registers an existing one. Requires bootstrap token in Authorization header.","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRegistrationRequest"}}},"required":true},"responses":{"200":{"description":"Agent registered successfully","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRegistrationResponse"}}}},"400":{"description":"Invalid registration payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid bootstrap token","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRegistrationResponse"}}}}}}},"/agents/groups/{group}/commands":{"post":{"tags":["Agent Commands"],"summary":"Send command to all agents in a group","description":"Sends a command to all LIVE agents in the specified group and waits for responses","operationId":"sendGroupCommand","parameters":[{"name":"group","in":"path","required":true,"schema":{"type":"string"}},{"name":"environment","in":"query","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"}}},"required":true},"responses":{"200":{"description":"Commands dispatched and responses collected","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandGroupResponse"}}}},"400":{"description":"Invalid command payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandGroupResponse"}}}}}}},"/agents/commands":{"post":{"tags":["Agent Commands"],"summary":"Broadcast command to all live agents","description":"Sends a command to all agents currently in LIVE state","operationId":"broadcastCommand","parameters":[{"name":"environment","in":"query","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"}}},"required":true},"responses":{"202":{"description":"Commands accepted","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandBroadcastResponse"}}}},"400":{"description":"Invalid command payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandBroadcastResponse"}}}}}}},"/admin/users":{"get":{"tags":["User Admin"],"summary":"List all users with RBAC detail","operationId":"listUsers","responses":{"200":{"description":"User list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserDetail"}}}}}}},"post":{"tags":["User Admin"],"summary":"Create a local user","operationId":"createUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"200":{"description":"User created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Disabled in OIDC mode","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/users/{userId}/roles/{roleId}":{"post":{"tags":["User Admin"],"summary":"Assign a role to a user","operationId":"assignRoleToUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role assigned"},"404":{"description":"User or role not found"}}},"delete":{"tags":["User Admin"],"summary":"Remove a role from a user","operationId":"removeRoleFromUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role removed"}}}},"/admin/users/{userId}/password":{"post":{"tags":["User Admin"],"summary":"Reset user password","operationId":"resetPassword","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password reset"},"400":{"description":"Disabled in OIDC mode or policy violation"}}}},"/admin/users/{userId}/groups/{groupId}":{"post":{"tags":["User Admin"],"summary":"Add a user to a group","operationId":"addUserToGroup","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User added to group"}}},"delete":{"tags":["User Admin"],"summary":"Remove a user from a group","operationId":"removeUserFromGroup","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"User removed from group"}}}},"/admin/server-metrics/query":{"post":{"tags":["Server Self-Metrics"],"summary":"Generic time-series query","description":"Returns bucketed series for a single metric_name. Supports aggregation (avg/sum/max/min/latest), group-by-tag, filter-by-tag, counter delta mode, and a derived 'mean' statistic for timers.","operationId":"query","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryBody"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ServerMetricQueryResponse"}}}}}}},"/admin/roles":{"get":{"tags":["Role Admin"],"summary":"List all roles (system and custom)","operationId":"listRoles","responses":{"200":{"description":"Role list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RoleDetail"}}}}}}},"post":{"tags":["Role Admin"],"summary":"Create a custom role","operationId":"createRole","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role created","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string","format":"uuid"}}}}}}}},"/admin/outbound-connections":{"get":{"tags":["Outbound Connections Admin"],"operationId":"list_2","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OutboundConnectionDto"}}}}}}},"post":{"tags":["Outbound Connections Admin"],"operationId":"create_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundConnectionRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OutboundConnectionDto"}}}}}}},"/admin/outbound-connections/{id}/test":{"post":{"tags":["Outbound Connections Admin"],"operationId":"test","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OutboundConnectionTestResult"}}}}}}},"/admin/oidc/test":{"post":{"tags":["OIDC Config Admin"],"summary":"Test OIDC provider connectivity","operationId":"testConnection","responses":{"200":{"description":"Provider reachable","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcTestResult"}}}},"400":{"description":"Provider unreachable or misconfigured","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/license":{"get":{"tags":["License Admin"],"summary":"Get current license info","operationId":"getCurrent","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/LicenseInfo"}}}}}},"post":{"tags":["License Admin"],"summary":"Update license token at runtime","operationId":"update_5","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLicenseRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/groups":{"get":{"tags":["Group Admin"],"summary":"List all groups with hierarchy and effective roles","operationId":"listGroups","responses":{"200":{"description":"Group list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GroupDetail"}}}}}}},"post":{"tags":["Group Admin"],"summary":"Create a new group","operationId":"createGroup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroupRequest"}}},"required":true},"responses":{"200":{"description":"Group created","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string","format":"uuid"}}}}}}}},"/admin/groups/{id}/roles/{roleId}":{"post":{"tags":["Group Admin"],"summary":"Assign a role to a group","operationId":"assignRoleToGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role assigned to group"},"404":{"description":"Group not found"}}},"delete":{"tags":["Group Admin"],"summary":"Remove a role from a group","operationId":"removeRoleFromGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role removed from group"},"404":{"description":"Group not found"}}}},"/admin/environments":{"get":{"tags":["Environment Admin"],"summary":"List all environments","operationId":"listEnvironments","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Environment"}}}}}}},"post":{"tags":["Environment Admin"],"summary":"Create a new environment","operationId":"createEnvironment","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid slug or slug already exists","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/database/queries/{pid}/kill":{"post":{"tags":["Database Admin"],"summary":"Terminate a query by PID","operationId":"killQuery","parameters":[{"name":"pid","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"}}}},"/admin/claim-mappings":{"get":{"tags":["Claim Mapping Admin"],"summary":"List all claim mapping rules","operationId":"list_3","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClaimMappingRule"}}}}}}},"post":{"tags":["Claim Mapping Admin"],"summary":"Create a claim mapping rule","operationId":"create_3","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRuleRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClaimMappingRule"}}}}}}},"/admin/claim-mappings/test":{"post":{"tags":["Claim Mapping Admin"],"summary":"Test claim mapping rules against a set of claims (accepts unsaved rules)","operationId":"test_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestResponse"}}}}}}},"/executions/{executionId}":{"get":{"tags":["Detail"],"summary":"Get execution detail with nested processor tree","operationId":"getDetail","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Execution detail found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExecutionDetail"}}}},"404":{"description":"Execution not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExecutionDetail"}}}}}}},"/executions/{executionId}/processors/{index}/snapshot":{"get":{"tags":["Detail"],"summary":"Get exchange snapshot for a specific processor by index","operationId":"getProcessorSnapshot","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"index","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Snapshot data","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"404":{"description":"Snapshot not found","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/executions/{executionId}/processors/by-seq/{seq}/snapshot":{"get":{"tags":["Detail"],"summary":"Get exchange snapshot for a processor by seq number","operationId":"processorSnapshotBySeq","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"seq","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Snapshot data","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"404":{"description":"Snapshot not found","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/executions/{executionId}/processors/by-id/{processorId}/snapshot":{"get":{"tags":["Detail"],"summary":"Get exchange snapshot for a specific processor by processorId","operationId":"processorSnapshotById","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"processorId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Snapshot data","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"404":{"description":"Snapshot not found","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/environments/{envSlug}/stats":{"get":{"tags":["Search"],"summary":"Aggregate execution stats (P99 latency, active count, SLA compliance)","operationId":"stats","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExecutionStats"}}}}}}},"/environments/{envSlug}/stats/timeseries":{"get":{"tags":["Search"],"summary":"Bucketed time-series stats over a time window","operationId":"timeseries","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":24}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/StatsTimeseries"}}}}}}},"/environments/{envSlug}/stats/timeseries/by-route":{"get":{"tags":["Search"],"summary":"Timeseries grouped by route for an application","operationId":"timeseriesByRoute","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":24}},{"name":"application","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/StatsTimeseries"}}}}}}}},"/environments/{envSlug}/stats/timeseries/by-app":{"get":{"tags":["Search"],"summary":"Timeseries grouped by application","operationId":"timeseriesByApp","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":24}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/StatsTimeseries"}}}}}}}},"/environments/{envSlug}/stats/punchcard":{"get":{"tags":["Search"],"summary":"Transaction punchcard: weekday x hour grid (rolling 7 days)","operationId":"punchcard","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PunchcardCell"}}}}}}}},"/environments/{envSlug}/routes":{"get":{"tags":["Route Catalog"],"summary":"Get route catalog for this environment","description":"Returns all applications with their routes, agents, and health status — filtered to this environment","operationId":"getCatalog","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Catalog returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AppCatalogEntry"}}}}}}}},"/environments/{envSlug}/routes/metrics":{"get":{"tags":["Route Metrics"],"summary":"Get route metrics for this environment","description":"Returns aggregated performance metrics per route for the given time window. Optional appId filter narrows to a single application.","operationId":"getMetrics","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"appId","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteMetrics"}}}}}}}},"/environments/{envSlug}/routes/metrics/processors":{"get":{"tags":["Route Metrics"],"summary":"Get processor metrics for this environment","description":"Returns aggregated performance metrics per processor for the given route and time window","operationId":"getProcessorMetrics","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"routeId","in":"query","required":true,"schema":{"type":"string"}},{"name":"appId","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Metrics returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProcessorMetrics"}}}}}}}},"/environments/{envSlug}/logs":{"get":{"tags":["Application Logs"],"summary":"Search application log entries in this environment","description":"Cursor-paginated log search scoped to the env in the path. Supports free-text search, multi-level filtering, and optional application/agent scoping.","operationId":"searchLogs","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"q","in":"query","required":false,"schema":{"type":"string"}},{"name":"query","in":"query","required":false,"schema":{"type":"string"}},{"name":"level","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"schema":{"type":"string"}},{"name":"exchangeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"logger","in":"query","required":false,"schema":{"type":"string"}},{"name":"source","in":"query","required":false,"schema":{"type":"string"}},{"name":"instanceIds","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":100}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"desc"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/LogSearchPageResponse"}}}}}}},"/environments/{envSlug}/executions":{"get":{"tags":["Search"],"summary":"Search executions with basic filters (env from path)","operationId":"searchGet","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"timeFrom","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"timeTo","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"correlationId","in":"query","required":false,"schema":{"type":"string"}},{"name":"text","in":"query","required":false,"schema":{"type":"string"}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"schema":{"type":"string"}},{"name":"processorType","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}},{"name":"attr","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}},{"name":"sortField","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortDir","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SearchResultExecutionSummary"}}}}}}},"/environments/{envSlug}/errors/top":{"get":{"tags":["Search"],"summary":"Top N errors with velocity trend","operationId":"topErrors","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":5}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TopError"}}}}}}}},"/environments/{envSlug}/config":{"get":{"tags":["Application Config"],"summary":"List application configs in this environment","operationId":"listConfigs","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"Configs returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApplicationConfig"}}}}}}}},"/environments/{envSlug}/attributes/keys":{"get":{"tags":["Search"],"summary":"Distinct attribute key names for this environment","operationId":"attributeKeys","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"type":"string"}}}}}}}},"/environments/{envSlug}/apps/{appSlug}":{"get":{"tags":["App Management"],"summary":"Get app by env + slug","operationId":"getApp","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"App found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/App"}}}},"404":{"description":"App not found in this environment","content":{"*/*":{"schema":{"$ref":"#/components/schemas/App"}}}}}},"delete":{"tags":["App Management"],"summary":"Delete this app","operationId":"deleteApp","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"App deleted"}}}},"/environments/{envSlug}/apps/{appSlug}/routes/{routeId}/diagram":{"get":{"tags":["Diagrams"],"summary":"Find the latest diagram for this app's route in this environment","description":"Returns the most recently stored diagram for (app, env, route). Independent of the agent registry, so routes removed from the current app version still resolve.","operationId":"findByAppAndRoute","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"routeId","in":"path","required":true,"schema":{"type":"string"}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","default":"LR"}}],"responses":{"200":{"description":"Diagram layout returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DiagramLayout"}}}},"404":{"description":"No diagram found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DiagramLayout"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/processor-routes":{"get":{"tags":["Application Config"],"summary":"Get processor to route mapping for this environment","description":"Returns a map of processorId → routeId for all processors seen in this application + environment","operationId":"getProcessorRouteMapping","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Mapping returned","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/environments/{envSlug}/apps/{appSlug}/dirty-state":{"get":{"tags":["App Management"],"summary":"Check whether the app's current config differs from the last successful deploy","description":"Returns dirty=true when the desired state (current JAR + agent config + container config) would produce a changed deployment. When no successful deploy exists yet, dirty=true.","operationId":"getDirtyState","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Dirty-state computed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DirtyStateResponse"}}}},"404":{"description":"App not found in this environment","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DirtyStateResponse"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments/{deploymentId}":{"get":{"tags":["Deployment Management"],"summary":"Get deployment by ID","operationId":"getDeployment","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deployment found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}},"404":{"description":"Deployment not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments/{deploymentId}/logs":{"get":{"tags":["Deployment Management"],"summary":"Get container logs for this deployment","operationId":"getLogs","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Logs returned","content":{"*/*":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Deployment not found or no container","content":{"*/*":{"schema":{"type":"array","items":{"type":"string"}}}}}}}},"/environments/{envSlug}/app-settings":{"get":{"tags":["App Settings"],"summary":"List application settings in this environment","operationId":"getAll","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AppSettings"}}}}}}}},"/environments/{envSlug}/alerts":{"get":{"tags":["Alerts Inbox"],"operationId":"list_4","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}},{"name":"state","in":"query","required":false,"schema":{"type":"array","items":{"type":"string","enum":["PENDING","FIRING","RESOLVED"]}}},{"name":"severity","in":"query","required":false,"schema":{"type":"array","items":{"type":"string","enum":["CRITICAL","WARNING","INFO"]}}},{"name":"acked","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"read","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertDto"}}}}}}}},"/environments/{envSlug}/alerts/{id}":{"get":{"tags":["Alerts Inbox"],"operationId":"get_3","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertDto"}}}}}},"delete":{"tags":["Alerts Inbox"],"operationId":"delete_5","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/{alertId}/notifications":{"get":{"tags":["Alert Notifications"],"operationId":"listForInstance","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"alertId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertNotificationDto"}}}}}}}},"/environments/{envSlug}/alerts/unread-count":{"get":{"tags":["Alerts Inbox"],"operationId":"unreadCount","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UnreadCountResponse"}}}}}}},"/environments/{envSlug}/agents":{"get":{"tags":["Agent List"],"summary":"List all agents in this environment","description":"Returns registered agents with runtime metrics, optionally filtered by status and/or application","operationId":"listAgents","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AgentInstanceResponse"}}}}},"400":{"description":"Invalid status filter","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/environments/{envSlug}/agents/{agentId}/metrics":{"get":{"tags":["agent-metrics-controller"],"operationId":"getMetrics_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"agentId","in":"path","required":true,"schema":{"type":"string"}},{"name":"names","in":"query","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":60}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","default":"gauge"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentMetricsResponse"}}}}}}},"/environments/{envSlug}/agents/events":{"get":{"tags":["Agent Events"],"summary":"Query agent events in this environment","description":"Cursor-paginated. Returns newest first. Pass nextCursor back as ?cursor= for the next page.","operationId":"getEvents","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appId","in":"query","required":false,"schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"Event page returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentEventPageResponse"}}}}}}},"/diagrams/{contentHash}/render":{"get":{"tags":["Diagrams"],"summary":"Render a route diagram by content hash","description":"Returns SVG (default) or JSON layout based on Accept header. Content hashes are globally unique, so this endpoint is intentionally flat (no env).","operationId":"renderDiagram","parameters":[{"name":"contentHash","in":"path","required":true,"schema":{"type":"string"}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","default":"LR"}}],"responses":{"200":{"description":"Diagram rendered successfully","content":{"image/svg+xml":{"schema":{"type":"string"}},"application/json":{"schema":{"$ref":"#/components/schemas/DiagramLayout"}}}},"404":{"description":"Diagram not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/catalog":{"get":{"tags":["Catalog"],"summary":"Get unified catalog","description":"Returns all applications (managed + unmanaged) with live agent data, routes, and deployment status","operationId":"getCatalog_1","parameters":[{"name":"environment","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Catalog returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CatalogApp"}}}}}}}},"/auth/oidc/config":{"get":{"tags":["Authentication"],"summary":"Get OIDC config for SPA login flow","operationId":"getConfig_2","responses":{"200":{"description":"OIDC configuration","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcPublicConfigResponse"}}}},"404":{"description":"OIDC not configured or disabled","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcPublicConfigResponse"}}}},"500":{"description":"Failed to retrieve OIDC provider metadata","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/me":{"get":{"tags":["Authentication"],"summary":"Get current user details","operationId":"me","responses":{"200":{"description":"Current user details","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}},"401":{"description":"Not authenticated","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}}}}},"/agents/{id}/events":{"get":{"tags":["Agent SSE"],"summary":"Open SSE event stream","description":"Opens a Server-Sent Events stream for the specified agent. Commands (config-update, deep-trace, replay) are pushed as events. Ping keepalive comments sent every 15 seconds.","operationId":"events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Last-Event-ID","in":"header","description":"Last received event ID (no replay, acknowledged only)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream opened","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}},"404":{"description":"Agent not registered and cannot be auto-registered","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}}}}},"/agents/config":{"get":{"tags":["Agent Config"],"summary":"Get application config for the calling agent","description":"Resolves (application, environment) from the agent's JWT + registry. Prefers the registry entry (heartbeat-authoritative); falls back to the JWT env claim. Returns 404 if neither identifies a valid agent.","operationId":"getConfigForAgent","responses":{"200":{"description":"Config returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppConfigResponse"}}}},"404":{"description":"Calling agent could not be resolved","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppConfigResponse"}}}}}}},"/admin/usage":{"get":{"tags":["Usage Analytics"],"summary":"Query usage statistics","description":"Returns aggregated API usage stats grouped by endpoint, user, or hour","operationId":"getUsage","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"username","in":"query","required":false,"schema":{"type":"string"}},{"name":"groupBy","in":"query","required":false,"schema":{"type":"string","default":"endpoint"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageStats"}}}}}}}},"/admin/server-metrics/instances":{"get":{"tags":["Server Self-Metrics"],"summary":"List server_instance_id values observed in the window","description":"Returns first/last seen timestamps — use to partition counter-delta computations.","operationId":"instances","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServerInstanceInfo"}}}}}}}},"/admin/server-metrics/catalog":{"get":{"tags":["Server Self-Metrics"],"summary":"List metric names observed in the window","description":"For each metric_name, returns metric_type, the set of statistics emitted, and the union of tag keys.","operationId":"catalog","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServerMetricCatalogEntry"}}}}}}}},"/admin/rbac/stats":{"get":{"tags":["RBAC Stats"],"summary":"Get RBAC statistics for the dashboard","operationId":"getStats","responses":{"200":{"description":"RBAC stats returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RbacStats"}}}}}}},"/admin/outbound-connections/{id}/usage":{"get":{"tags":["Outbound Connections Admin"],"operationId":"usage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}}},"/admin/database/tables":{"get":{"tags":["Database Admin"],"summary":"Get table sizes and row counts","operationId":"getTables","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TableSizeResponse"}}}}}}}},"/admin/database/status":{"get":{"tags":["Database Admin"],"summary":"Get database connection status and version","operationId":"getStatus","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DatabaseStatusResponse"}}}}}}},"/admin/database/queries":{"get":{"tags":["Database Admin"],"summary":"Get active queries","operationId":"getQueries","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ActiveQueryResponse"}}}}}}}},"/admin/database/pool":{"get":{"tags":["Database Admin"],"summary":"Get HikariCP connection pool stats","operationId":"getPool","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ConnectionPoolResponse"}}}}}}},"/admin/clickhouse/tables":{"get":{"tags":["ClickHouse Admin"],"summary":"List ClickHouse tables with sizes","operationId":"getTables_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClickHouseTableInfo"}}}}}}}},"/admin/clickhouse/status":{"get":{"tags":["ClickHouse Admin"],"summary":"ClickHouse cluster status","operationId":"getStatus_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClickHouseStatusResponse"}}}}}}},"/admin/clickhouse/queries":{"get":{"tags":["ClickHouse Admin"],"summary":"Active ClickHouse queries","operationId":"getQueries_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClickHouseQueryInfo"}}}}}}}},"/admin/clickhouse/performance":{"get":{"tags":["ClickHouse Admin"],"summary":"ClickHouse storage and performance metrics","operationId":"getPerformance","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClickHousePerformanceResponse"}}}}}}},"/admin/audit":{"get":{"tags":["Audit Log"],"summary":"Search audit log entries with pagination","operationId":"getAuditLog","parameters":[{"name":"username","in":"query","required":false,"schema":{"type":"string"}},{"name":"category","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"timestamp"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":25}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuditLogPageResponse"}}}}}}},"/catalog/{applicationId}":{"delete":{"tags":["Catalog"],"summary":"Dismiss application and purge all data","operationId":"dismissApplication","parameters":[{"name":"applicationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Application dismissed"},"409":{"description":"Cannot dismiss — live agents connected"}}}}},"components":{"schemas":{"Environment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"displayName":{"type":"string"},"production":{"type":"boolean"},"enabled":{"type":"boolean"},"defaultContainerConfig":{"type":"object","additionalProperties":{"type":"object"}},"jarRetentionCount":{"type":"integer","format":"int32"},"color":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"AppSettingsRequest":{"type":"object","description":"Per-application dashboard settings","properties":{"slaThresholdMs":{"type":"integer","format":"int32","description":"SLA duration threshold in milliseconds","minimum":1},"healthErrorWarn":{"type":"number","format":"double","description":"Error rate % threshold for warning (yellow) health dot","maximum":100,"minimum":0},"healthErrorCrit":{"type":"number","format":"double","description":"Error rate % threshold for critical (red) health dot","maximum":100,"minimum":0},"healthSlaWarn":{"type":"number","format":"double","description":"SLA compliance % threshold for warning (yellow) health dot","maximum":100,"minimum":0},"healthSlaCrit":{"type":"number","format":"double","description":"SLA compliance % threshold for critical (red) health dot","maximum":100,"minimum":0}},"required":["healthErrorCrit","healthErrorWarn","healthSlaCrit","healthSlaWarn","slaThresholdMs"]},"AppSettings":{"type":"object","properties":{"applicationId":{"type":"string"},"environment":{"type":"string"},"slaThresholdMs":{"type":"integer","format":"int32"},"healthErrorWarn":{"type":"number","format":"double"},"healthErrorCrit":{"type":"number","format":"double"},"healthSlaWarn":{"type":"number","format":"double"},"healthSlaCrit":{"type":"number","format":"double"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ApplicationConfig":{"type":"object","properties":{"application":{"type":"string"},"environment":{"type":"string"},"version":{"type":"integer","format":"int32"},"updatedAt":{"type":"string","format":"date-time"},"engineLevel":{"type":"string"},"payloadCaptureMode":{"type":"string"},"metricsEnabled":{"type":"boolean"},"samplingRate":{"type":"number","format":"double"},"tracedProcessors":{"type":"object","additionalProperties":{"type":"string"}},"applicationLogLevel":{"type":"string"},"taps":{"type":"array","items":{"$ref":"#/components/schemas/TapDefinition"}},"tapVersion":{"type":"integer","format":"int32"},"routeRecording":{"type":"object","additionalProperties":{"type":"boolean"}},"compressSuccess":{"type":"boolean"},"agentLogLevel":{"type":"string"},"routeSamplingRates":{"type":"object","additionalProperties":{"type":"number","format":"double"}},"sensitiveKeys":{"type":"array","items":{"type":"string"}},"exportBatchSize":{"type":"integer","format":"int32"},"exportQueueSize":{"type":"integer","format":"int32"},"exportFlushIntervalMs":{"type":"integer","format":"int64"},"exportOverflowMode":{"type":"string"},"exportBlockTimeoutMs":{"type":"integer","format":"int64"},"flushRecordThreshold":{"type":"integer","format":"int32"}}},"TapDefinition":{"type":"object","properties":{"tapId":{"type":"string"},"processorId":{"type":"string"},"target":{"type":"string"},"expression":{"type":"string"},"language":{"type":"string"},"attributeName":{"type":"string"},"attributeType":{"type":"string"},"enabled":{"type":"boolean"},"version":{"type":"integer","format":"int32"}}},"AgentResponse":{"type":"object","properties":{"agentId":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"}}},"CommandGroupResponse":{"type":"object","properties":{"success":{"type":"boolean"},"total":{"type":"integer","format":"int32"},"responded":{"type":"integer","format":"int32"},"responses":{"type":"array","items":{"$ref":"#/components/schemas/AgentResponse"}},"timedOut":{"type":"array","items":{"type":"string"}}}},"ConfigUpdateResponse":{"type":"object","properties":{"config":{"$ref":"#/components/schemas/ApplicationConfig"},"pushResult":{"$ref":"#/components/schemas/CommandGroupResponse"}}},"AlertSilenceRequest":{"type":"object","properties":{"matcher":{"$ref":"#/components/schemas/SilenceMatcher"},"reason":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"}},"required":["endsAt","matcher","startsAt"]},"SilenceMatcher":{"type":"object","properties":{"ruleId":{"type":"string","format":"uuid"},"appSlug":{"type":"string"},"routeId":{"type":"string"},"agentId":{"type":"string"},"severity":{"type":"string","enum":["CRITICAL","WARNING","INFO"]},"wildcard":{"type":"boolean"}}},"AlertSilenceResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"matcher":{"$ref":"#/components/schemas/SilenceMatcher"},"reason":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"AgentLifecycleCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"eventTypes":{"type":"array","items":{"type":"string","enum":["REGISTERED","RE_REGISTERED","DEREGISTERED","WENT_STALE","WENT_DEAD","RECOVERED"]}},"withinSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"AgentStateCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"state":{"type":"string"},"forSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"AlertCondition":{"type":"object","discriminator":{"propertyName":"kind"},"properties":{"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"]}}},"AlertRuleRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1},"description":{"type":"string"},"severity":{"type":"string","enum":["CRITICAL","WARNING","INFO"]},"conditionKind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"]},"condition":{"oneOf":[{"$ref":"#/components/schemas/AgentLifecycleCondition"},{"$ref":"#/components/schemas/AgentStateCondition"},{"$ref":"#/components/schemas/DeploymentStateCondition"},{"$ref":"#/components/schemas/ExchangeMatchCondition"},{"$ref":"#/components/schemas/JvmMetricCondition"},{"$ref":"#/components/schemas/LogPatternCondition"},{"$ref":"#/components/schemas/RouteMetricCondition"}]},"evaluationIntervalSeconds":{"type":"integer","format":"int32"},"forDurationSeconds":{"type":"integer","format":"int32"},"reNotifyMinutes":{"type":"integer","format":"int32"},"notificationTitleTmpl":{"type":"string"},"notificationMessageTmpl":{"type":"string"},"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/WebhookBindingRequest"}},"targets":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleTarget"}}},"required":["condition","conditionKind","severity"]},"AlertRuleTarget":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ruleId":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["USER","GROUP","ROLE"]},"targetId":{"type":"string"}}},"AlertScope":{"type":"object","properties":{"appSlug":{"type":"string"},"routeId":{"type":"string"},"agentId":{"type":"string"}}},"DeploymentStateCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"states":{"type":"array","items":{"type":"string"}},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"ExchangeFilter":{"type":"object","properties":{"status":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}}}},"ExchangeMatchCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"filter":{"$ref":"#/components/schemas/ExchangeFilter"},"fireMode":{"type":"string","enum":["PER_EXCHANGE","COUNT_IN_WINDOW"]},"threshold":{"type":"integer","format":"int32"},"windowSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"JvmMetricCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"metric":{"type":"string"},"aggregation":{"type":"string","enum":["MAX","MIN","AVG","LATEST"]},"comparator":{"type":"string","enum":["GT","GTE","LT","LTE","EQ"]},"threshold":{"type":"number","format":"double"},"windowSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"LogPatternCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"level":{"type":"string"},"pattern":{"type":"string"},"threshold":{"type":"integer","format":"int32"},"windowSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"RouteMetricCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"metric":{"type":"string","enum":["ERROR_RATE","AVG_DURATION_MS","P99_LATENCY_MS","THROUGHPUT","ERROR_COUNT"]},"comparator":{"type":"string","enum":["GT","GTE","LT","LTE","EQ"]},"threshold":{"type":"number","format":"double"},"windowSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"WebhookBindingRequest":{"type":"object","properties":{"outboundConnectionId":{"type":"string","format":"uuid"},"bodyOverride":{"type":"string"},"headerOverrides":{"type":"object","additionalProperties":{"type":"string"}}},"required":["outboundConnectionId"]},"AlertRuleResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"severity":{"type":"string","enum":["CRITICAL","WARNING","INFO"]},"enabled":{"type":"boolean"},"conditionKind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"]},"condition":{"oneOf":[{"$ref":"#/components/schemas/AgentLifecycleCondition"},{"$ref":"#/components/schemas/AgentStateCondition"},{"$ref":"#/components/schemas/DeploymentStateCondition"},{"$ref":"#/components/schemas/ExchangeMatchCondition"},{"$ref":"#/components/schemas/JvmMetricCondition"},{"$ref":"#/components/schemas/LogPatternCondition"},{"$ref":"#/components/schemas/RouteMetricCondition"}]},"evaluationIntervalSeconds":{"type":"integer","format":"int32"},"forDurationSeconds":{"type":"integer","format":"int32"},"reNotifyMinutes":{"type":"integer","format":"int32"},"notificationTitleTmpl":{"type":"string"},"notificationMessageTmpl":{"type":"string"},"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/WebhookBindingResponse"}},"targets":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleTarget"}},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"}}},"WebhookBindingResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"outboundConnectionId":{"type":"string","format":"uuid"},"bodyOverride":{"type":"string"},"headerOverrides":{"type":"object","additionalProperties":{"type":"string"}}}},"UpdateUserRequest":{"type":"object","properties":{"displayName":{"type":"string"},"email":{"type":"string"}}},"DatabaseThresholdsRequest":{"type":"object","description":"Database monitoring thresholds","properties":{"connectionPoolWarning":{"type":"integer","format":"int32","description":"Connection pool usage warning threshold (percentage)","maximum":100,"minimum":0},"connectionPoolCritical":{"type":"integer","format":"int32","description":"Connection pool usage critical threshold (percentage)","maximum":100,"minimum":0},"queryDurationWarning":{"type":"number","format":"double","description":"Query duration warning threshold (seconds)"},"queryDurationCritical":{"type":"number","format":"double","description":"Query duration critical threshold (seconds)"}}},"ThresholdConfigRequest":{"type":"object","description":"Threshold configuration for admin monitoring","properties":{"database":{"$ref":"#/components/schemas/DatabaseThresholdsRequest"}},"required":["database"]},"DatabaseThresholds":{"type":"object","properties":{"connectionPoolWarning":{"type":"integer","format":"int32"},"connectionPoolCritical":{"type":"integer","format":"int32"},"queryDurationWarning":{"type":"number","format":"double"},"queryDurationCritical":{"type":"number","format":"double"}}},"ThresholdConfig":{"type":"object","properties":{"database":{"$ref":"#/components/schemas/DatabaseThresholds"}}},"SensitiveKeysRequest":{"type":"object","description":"Global sensitive keys configuration","properties":{"keys":{"type":"array","description":"List of key names or glob patterns to mask","items":{"type":"string"}}},"required":["keys"]},"SensitiveKeysResponse":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"string"}},"pushResult":{"$ref":"#/components/schemas/CommandGroupResponse"}}},"UpdateRoleRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"scope":{"type":"string"}}},"Basic":{"allOf":[{"$ref":"#/components/schemas/OutboundAuth"},{"type":"object","properties":{"username":{"type":"string"},"passwordCiphertext":{"type":"string"}}}]},"Bearer":{"allOf":[{"$ref":"#/components/schemas/OutboundAuth"},{"type":"object","properties":{"tokenCiphertext":{"type":"string"}}}]},"None":{"allOf":[{"$ref":"#/components/schemas/OutboundAuth"}]},"OutboundAuth":{"type":"object"},"OutboundConnectionRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"minLength":0},"description":{"type":"string","maxLength":2000,"minLength":0},"url":{"type":"string","minLength":1,"pattern":"^https://.+"},"method":{"type":"string","enum":["POST","PUT","PATCH"]},"defaultHeaders":{"type":"object","additionalProperties":{"type":"string"}},"defaultBodyTmpl":{"type":"string"},"tlsTrustMode":{"type":"string","enum":["SYSTEM_DEFAULT","TRUST_ALL","TRUST_PATHS"]},"tlsCaPemPaths":{"type":"array","items":{"type":"string"}},"hmacSecret":{"type":"string"},"auth":{"oneOf":[{"$ref":"#/components/schemas/Basic"},{"$ref":"#/components/schemas/Bearer"},{"$ref":"#/components/schemas/None"}]},"allowedEnvironmentIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["auth","method","tlsTrustMode"]},"OutboundConnectionDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"method":{"type":"string","enum":["POST","PUT","PATCH"]},"defaultHeaders":{"type":"object","additionalProperties":{"type":"string"}},"defaultBodyTmpl":{"type":"string"},"tlsTrustMode":{"type":"string","enum":["SYSTEM_DEFAULT","TRUST_ALL","TRUST_PATHS"]},"tlsCaPemPaths":{"type":"array","items":{"type":"string"}},"hmacSecretSet":{"type":"boolean"},"authKind":{"type":"string","enum":["NONE","BEARER","BASIC"]},"allowedEnvironmentIds":{"type":"array","items":{"type":"string","format":"uuid"}},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"}}},"OidcAdminConfigRequest":{"type":"object","description":"OIDC configuration update request","properties":{"enabled":{"type":"boolean"},"issuerUri":{"type":"string"},"clientId":{"type":"string"},"clientSecret":{"type":"string"},"rolesClaim":{"type":"string"},"defaultRoles":{"type":"array","items":{"type":"string"}},"autoSignup":{"type":"boolean"},"displayNameClaim":{"type":"string"},"userIdClaim":{"type":"string"},"audience":{"type":"string"},"additionalScopes":{"type":"array","items":{"type":"string"}}}},"ErrorResponse":{"type":"object","description":"Error response","properties":{"message":{"type":"string"}},"required":["message"]},"OidcAdminConfigResponse":{"type":"object","description":"OIDC configuration for admin management","properties":{"configured":{"type":"boolean"},"enabled":{"type":"boolean"},"issuerUri":{"type":"string"},"clientId":{"type":"string"},"clientSecretSet":{"type":"boolean"},"rolesClaim":{"type":"string"},"defaultRoles":{"type":"array","items":{"type":"string"}},"autoSignup":{"type":"boolean"},"displayNameClaim":{"type":"string"},"userIdClaim":{"type":"string"},"audience":{"type":"string"},"additionalScopes":{"type":"array","items":{"type":"string"}}}},"UpdateGroupRequest":{"type":"object","properties":{"name":{"type":"string"},"parentGroupId":{"type":"string","format":"uuid"}}},"UpdateEnvironmentRequest":{"type":"object","properties":{"displayName":{"type":"string"},"production":{"type":"boolean"},"enabled":{"type":"boolean"},"color":{"type":"string"}}},"JarRetentionRequest":{"type":"object","properties":{"jarRetentionCount":{"type":"integer","format":"int32"}}},"CreateRuleRequest":{"type":"object","properties":{"claim":{"type":"string"},"matchType":{"type":"string"},"matchValue":{"type":"string"},"action":{"type":"string"},"target":{"type":"string"},"priority":{"type":"integer","format":"int32"}}},"ClaimMappingRule":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"claim":{"type":"string"},"matchType":{"type":"string"},"matchValue":{"type":"string"},"action":{"type":"string"},"target":{"type":"string"},"priority":{"type":"integer","format":"int32"},"createdAt":{"type":"string","format":"date-time"}}},"AttributeFilter":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"},"keyOnly":{"type":"boolean"},"wildcard":{"type":"boolean"}}},"SearchRequest":{"type":"object","properties":{"status":{"type":"string"},"timeFrom":{"type":"string","format":"date-time"},"timeTo":{"type":"string","format":"date-time"},"durationMin":{"type":"integer","format":"int64"},"durationMax":{"type":"integer","format":"int64"},"correlationId":{"type":"string"},"text":{"type":"string"},"textInBody":{"type":"string"},"textInHeaders":{"type":"string"},"textInErrors":{"type":"string"},"routeId":{"type":"string"},"instanceId":{"type":"string"},"processorType":{"type":"string"},"applicationId":{"type":"string"},"instanceIds":{"type":"array","items":{"type":"string"}},"offset":{"type":"integer","format":"int32"},"limit":{"type":"integer","format":"int32"},"sortField":{"type":"string"},"sortDir":{"type":"string"},"afterExecutionId":{"type":"string"},"environment":{"type":"string"},"attributeFilters":{"type":"array","items":{"$ref":"#/components/schemas/AttributeFilter"}}}},"ExecutionSummary":{"type":"object","properties":{"executionId":{"type":"string"},"routeId":{"type":"string"},"instanceId":{"type":"string"},"applicationId":{"type":"string"},"status":{"type":"string"},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"},"correlationId":{"type":"string"},"errorMessage":{"type":"string"},"diagramContentHash":{"type":"string"},"highlight":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}},"hasTraceData":{"type":"boolean"},"isReplay":{"type":"boolean"}},"required":["applicationId","attributes","correlationId","diagramContentHash","durationMs","endTime","errorMessage","executionId","hasTraceData","highlight","instanceId","isReplay","routeId","startTime","status"]},"SearchResultExecutionSummary":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExecutionSummary"}},"total":{"type":"integer","format":"int64"},"offset":{"type":"integer","format":"int32"},"limit":{"type":"integer","format":"int32"}},"required":["data","limit","offset","total"]},"CreateAppRequest":{"type":"object","properties":{"slug":{"type":"string"},"displayName":{"type":"string"}}},"AppVersion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"version":{"type":"integer","format":"int32"},"jarPath":{"type":"string"},"jarChecksum":{"type":"string"},"jarFilename":{"type":"string"},"jarSizeBytes":{"type":"integer","format":"int64"},"detectedRuntimeType":{"type":"string"},"detectedMainClass":{"type":"string"},"uploadedAt":{"type":"string","format":"date-time"}}},"DeployRequest":{"type":"object","properties":{"appVersionId":{"type":"string","format":"uuid"}}},"Deployment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"appVersionId":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["STOPPED","STARTING","RUNNING","DEGRADED","STOPPING","FAILED"]},"targetState":{"type":"string"},"deploymentStrategy":{"type":"string"},"replicaStates":{"type":"array","items":{"type":"object","additionalProperties":{"type":"object"}}},"deployStage":{"type":"string"},"containerId":{"type":"string"},"containerName":{"type":"string"},"errorMessage":{"type":"string"},"resolvedConfig":{"type":"object","additionalProperties":{"type":"object"}},"deployedConfigSnapshot":{"$ref":"#/components/schemas/DeploymentConfigSnapshot"},"deployedAt":{"type":"string","format":"date-time"},"stoppedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"DeploymentConfigSnapshot":{"type":"object","properties":{"jarVersionId":{"type":"string","format":"uuid"},"agentConfig":{"$ref":"#/components/schemas/ApplicationConfig"},"containerConfig":{"type":"object","additionalProperties":{"type":"object"}},"sensitiveKeys":{"type":"array","items":{"type":"string"}}}},"PromoteRequest":{"type":"object","properties":{"targetEnvironment":{"type":"string"}}},"TestExpressionRequest":{"type":"object","properties":{"expression":{"type":"string"},"language":{"type":"string"},"body":{"type":"string"},"target":{"type":"string"}}},"TestExpressionResponse":{"type":"object","properties":{"result":{"type":"string"},"error":{"type":"string"}}},"AlertDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ruleId":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["PENDING","FIRING","RESOLVED"]},"severity":{"type":"string","enum":["CRITICAL","WARNING","INFO"]},"title":{"type":"string"},"message":{"type":"string"},"firedAt":{"type":"string","format":"date-time"},"ackedAt":{"type":"string","format":"date-time"},"ackedBy":{"type":"string"},"resolvedAt":{"type":"string","format":"date-time"},"readAt":{"type":"string","format":"date-time"},"silenced":{"type":"boolean"},"currentValue":{"type":"number","format":"double"},"threshold":{"type":"number","format":"double"},"context":{"type":"object","additionalProperties":{"type":"object"}}}},"TestEvaluateRequest":{"type":"object"},"TestEvaluateResponse":{"type":"object","properties":{"resultKind":{"type":"string"},"detail":{"type":"string"}}},"RenderPreviewRequest":{"type":"object","properties":{"context":{"type":"object","additionalProperties":{"type":"object"}}}},"RenderPreviewResponse":{"type":"object","properties":{"title":{"type":"string"},"message":{"type":"string"}}},"BulkIdsRequest":{"type":"object","properties":{"instanceIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"minItems":1}},"required":["instanceIds"]},"LogEntry":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"level":{"type":"string"},"loggerName":{"type":"string"},"message":{"type":"string"},"threadName":{"type":"string"},"stackTrace":{"type":"string"},"mdc":{"type":"object","additionalProperties":{"type":"string"}},"source":{"type":"string"}}},"RefreshRequest":{"type":"object","properties":{"refreshToken":{"type":"string"}}},"AuthTokenResponse":{"type":"object","description":"JWT token pair","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"displayName":{"type":"string"},"idToken":{"type":"string","description":"OIDC id_token for end-session logout (only present after OIDC login)"}},"required":["accessToken","displayName","refreshToken"]},"CallbackRequest":{"type":"object","properties":{"code":{"type":"string"},"redirectUri":{"type":"string"}}},"LoginRequest":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}}},"AlertNotificationDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"alertInstanceId":{"type":"string","format":"uuid"},"webhookId":{"type":"string","format":"uuid"},"outboundConnectionId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["PENDING","DELIVERED","FAILED"]},"attempts":{"type":"integer","format":"int32"},"nextAttemptAt":{"type":"string","format":"date-time"},"lastResponseStatus":{"type":"integer","format":"int32"},"lastResponseSnippet":{"type":"string"},"deliveredAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"ReplayRequest":{"type":"object","description":"Request to replay an exchange on an agent","properties":{"routeId":{"type":"string","description":"Camel route ID to replay on"},"body":{"type":"string","description":"Message body for the replayed exchange"},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Message headers for the replayed exchange"},"originalExchangeId":{"type":"string","description":"Exchange ID of the original execution being replayed (for audit trail)"}},"required":["routeId"]},"ReplayResponse":{"type":"object","description":"Result of a replay command","properties":{"status":{"type":"string","description":"Replay outcome: SUCCESS or FAILURE"},"message":{"type":"string","description":"Human-readable result message"},"data":{"type":"string","description":"Structured result data from the agent (JSON)"}}},"AgentRefreshRequest":{"type":"object","description":"Agent token refresh request","properties":{"refreshToken":{"type":"string"}},"required":["refreshToken"]},"AgentRefreshResponse":{"type":"object","description":"Refreshed access and refresh tokens","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"}},"required":["accessToken","refreshToken"]},"HeartbeatRequest":{"type":"object","properties":{"routeStates":{"type":"object","additionalProperties":{"type":"string"}},"capabilities":{"type":"object","additionalProperties":{"type":"object"}},"environmentId":{"type":"string"}}},"CommandRequest":{"type":"object","description":"Command to send to agent(s)","properties":{"type":{"type":"string","description":"Command type: config-update, deep-trace, or replay"},"payload":{"type":"object","description":"Command payload JSON"}},"required":["type"]},"CommandSingleResponse":{"type":"object","description":"Result of sending a command to a single agent","properties":{"commandId":{"type":"string"},"status":{"type":"string"}},"required":["commandId","status"]},"CommandAckRequest":{"type":"object","properties":{"status":{"type":"string"},"message":{"type":"string"},"data":{"type":"string"}}},"AgentRegistrationRequest":{"type":"object","description":"Agent registration payload","properties":{"instanceId":{"type":"string"},"applicationId":{"type":"string","default":"default"},"environmentId":{"type":"string","default":"default"},"version":{"type":"string"},"routeIds":{"type":"array","items":{"type":"string"}},"capabilities":{"type":"object","additionalProperties":{"type":"object"}}},"required":["instanceId"]},"AgentRegistrationResponse":{"type":"object","description":"Agent registration result with JWT tokens and SSE endpoint","properties":{"instanceId":{"type":"string"},"sseEndpoint":{"type":"string"},"heartbeatIntervalMs":{"type":"integer","format":"int64"},"serverPublicKey":{"type":"string"},"accessToken":{"type":"string"},"refreshToken":{"type":"string"}},"required":["accessToken","instanceId","refreshToken","serverPublicKey","sseEndpoint"]},"CommandBroadcastResponse":{"type":"object","description":"Result of broadcasting a command to multiple agents","properties":{"commandIds":{"type":"array","items":{"type":"string"}},"targetCount":{"type":"integer","format":"int32"}},"required":["commandIds"]},"CreateUserRequest":{"type":"object","properties":{"username":{"type":"string"},"displayName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"}}},"SetPasswordRequest":{"type":"object","properties":{"password":{"type":"string","minLength":1}}},"QueryBody":{"type":"object","properties":{"metric":{"type":"string"},"statistic":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"stepSeconds":{"type":"integer","format":"int32"},"groupByTags":{"type":"array","items":{"type":"string"}},"filterTags":{"type":"object","additionalProperties":{"type":"string"}},"aggregation":{"type":"string"},"mode":{"type":"string"},"serverInstanceIds":{"type":"array","items":{"type":"string"}}}},"ServerMetricPoint":{"type":"object","properties":{"t":{"type":"string","format":"date-time"},"v":{"type":"number","format":"double"}}},"ServerMetricQueryResponse":{"type":"object","properties":{"metric":{"type":"string"},"statistic":{"type":"string"},"aggregation":{"type":"string"},"mode":{"type":"string"},"stepSeconds":{"type":"integer","format":"int32"},"series":{"type":"array","items":{"$ref":"#/components/schemas/ServerMetricSeries"}}}},"ServerMetricSeries":{"type":"object","properties":{"tags":{"type":"object","additionalProperties":{"type":"string"}},"points":{"type":"array","items":{"$ref":"#/components/schemas/ServerMetricPoint"}}}},"CreateRoleRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"scope":{"type":"string"}}},"OutboundConnectionTestResult":{"type":"object","properties":{"status":{"type":"integer","format":"int32"},"latencyMs":{"type":"integer","format":"int64"},"responseSnippet":{"type":"string"},"tlsProtocol":{"type":"string"},"tlsCipherSuite":{"type":"string"},"peerCertificateSubject":{"type":"string"},"peerCertificateExpiresAtEpochMs":{"type":"integer","format":"int64"},"error":{"type":"string"}}},"OidcTestResult":{"type":"object","description":"OIDC provider connectivity test result","properties":{"status":{"type":"string"},"authorizationEndpoint":{"type":"string"}},"required":["authorizationEndpoint","status"]},"UpdateLicenseRequest":{"type":"object","properties":{"token":{"type":"string"}}},"CreateGroupRequest":{"type":"object","properties":{"name":{"type":"string"},"parentGroupId":{"type":"string","format":"uuid"}}},"CreateEnvironmentRequest":{"type":"object","properties":{"slug":{"type":"string"},"displayName":{"type":"string"},"production":{"type":"boolean"}}},"TestRequest":{"type":"object","properties":{"rules":{"type":"array","items":{"$ref":"#/components/schemas/TestRuleRequest"}},"claims":{"type":"object","additionalProperties":{"type":"object"}}}},"TestRuleRequest":{"type":"object","properties":{"id":{"type":"string"},"claim":{"type":"string"},"matchType":{"type":"string"},"matchValue":{"type":"string"},"action":{"type":"string"},"target":{"type":"string"},"priority":{"type":"integer","format":"int32"}}},"MatchedRuleResponse":{"type":"object","properties":{"ruleId":{"type":"string"},"priority":{"type":"integer","format":"int32"},"claim":{"type":"string"},"matchType":{"type":"string"},"matchValue":{"type":"string"},"action":{"type":"string"},"target":{"type":"string"}}},"TestResponse":{"type":"object","properties":{"matchedRules":{"type":"array","items":{"$ref":"#/components/schemas/MatchedRuleResponse"}},"effectiveRoles":{"type":"array","items":{"type":"string"}},"effectiveGroups":{"type":"array","items":{"type":"string"}},"fallback":{"type":"boolean"}}},"ExecutionDetail":{"type":"object","properties":{"executionId":{"type":"string"},"routeId":{"type":"string"},"instanceId":{"type":"string"},"applicationId":{"type":"string"},"environment":{"type":"string"},"status":{"type":"string"},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"},"correlationId":{"type":"string"},"exchangeId":{"type":"string"},"errorMessage":{"type":"string"},"errorStackTrace":{"type":"string"},"diagramContentHash":{"type":"string"},"processors":{"type":"array","items":{"$ref":"#/components/schemas/ProcessorNode"}},"inputBody":{"type":"string"},"outputBody":{"type":"string"},"inputHeaders":{"type":"string"},"outputHeaders":{"type":"string"},"inputProperties":{"type":"string"},"outputProperties":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}},"errorType":{"type":"string"},"errorCategory":{"type":"string"},"rootCauseType":{"type":"string"},"rootCauseMessage":{"type":"string"},"traceId":{"type":"string"},"spanId":{"type":"string"}},"required":["applicationId","attributes","correlationId","diagramContentHash","durationMs","endTime","environment","errorCategory","errorMessage","errorStackTrace","errorType","exchangeId","executionId","inputBody","inputHeaders","inputProperties","instanceId","outputBody","outputHeaders","outputProperties","processors","rootCauseMessage","rootCauseType","routeId","spanId","startTime","status","traceId"]},"ProcessorNode":{"type":"object","properties":{"processorId":{"type":"string"},"processorType":{"type":"string"},"status":{"type":"string"},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"},"errorMessage":{"type":"string"},"errorStackTrace":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}},"iteration":{"type":"integer","format":"int32"},"iterationSize":{"type":"integer","format":"int32"},"loopIndex":{"type":"integer","format":"int32"},"loopSize":{"type":"integer","format":"int32"},"splitIndex":{"type":"integer","format":"int32"},"splitSize":{"type":"integer","format":"int32"},"multicastIndex":{"type":"integer","format":"int32"},"resolvedEndpointUri":{"type":"string"},"errorType":{"type":"string"},"errorCategory":{"type":"string"},"rootCauseType":{"type":"string"},"rootCauseMessage":{"type":"string"},"errorHandlerType":{"type":"string"},"circuitBreakerState":{"type":"string"},"fallbackTriggered":{"type":"boolean"},"filterMatched":{"type":"boolean"},"duplicateMessage":{"type":"boolean"},"hasTraceData":{"type":"boolean"},"children":{"type":"array","items":{"$ref":"#/components/schemas/ProcessorNode"}}},"required":["attributes","children","circuitBreakerState","duplicateMessage","durationMs","endTime","errorCategory","errorHandlerType","errorMessage","errorStackTrace","errorType","fallbackTriggered","filterMatched","hasTraceData","iteration","iterationSize","loopIndex","loopSize","multicastIndex","processorId","processorType","resolvedEndpointUri","rootCauseMessage","rootCauseType","splitIndex","splitSize","startTime","status"]},"ExecutionStats":{"type":"object","properties":{"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"integer","format":"int64"},"p99LatencyMs":{"type":"integer","format":"int64"},"activeCount":{"type":"integer","format":"int64"},"totalToday":{"type":"integer","format":"int64"},"prevTotalCount":{"type":"integer","format":"int64"},"prevFailedCount":{"type":"integer","format":"int64"},"prevAvgDurationMs":{"type":"integer","format":"int64"},"prevP99LatencyMs":{"type":"integer","format":"int64"},"slaCompliance":{"type":"number","format":"double"}},"required":["activeCount","avgDurationMs","failedCount","p99LatencyMs","prevAvgDurationMs","prevFailedCount","prevP99LatencyMs","prevTotalCount","slaCompliance","totalCount","totalToday"]},"StatsTimeseries":{"type":"object","properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}},"required":["buckets"]},"TimeseriesBucket":{"type":"object","properties":{"time":{"type":"string","format":"date-time"},"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"integer","format":"int64"},"p99DurationMs":{"type":"integer","format":"int64"},"activeCount":{"type":"integer","format":"int64"}},"required":["activeCount","avgDurationMs","failedCount","p99DurationMs","time","totalCount"]},"PunchcardCell":{"type":"object","properties":{"weekday":{"type":"integer","format":"int32"},"hour":{"type":"integer","format":"int32"},"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"}}},"AgentSummary":{"type":"object","description":"Summary of an agent instance for sidebar display","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"tps":{"type":"number","format":"double"}},"required":["id","name","status","tps"]},"AppCatalogEntry":{"type":"object","description":"Application catalog entry with routes and agents","properties":{"appId":{"type":"string"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/RouteSummary"}},"agents":{"type":"array","items":{"$ref":"#/components/schemas/AgentSummary"}},"agentCount":{"type":"integer","format":"int32"},"health":{"type":"string"},"exchangeCount":{"type":"integer","format":"int64"}},"required":["agentCount","agents","appId","exchangeCount","health","routes"]},"RouteSummary":{"type":"object","description":"Summary of a route within an application","properties":{"routeId":{"type":"string"},"exchangeCount":{"type":"integer","format":"int64"},"lastSeen":{"type":"string","format":"date-time"},"fromEndpointUri":{"type":"string","description":"The from() endpoint URI, e.g. 'direct:processOrder'"},"routeState":{"type":"string","description":"Operational state of the route: stopped, suspended, or null (started/default)"}},"required":["exchangeCount","fromEndpointUri","lastSeen","routeId","routeState"]},"RouteMetrics":{"type":"object","description":"Aggregated route performance metrics","properties":{"routeId":{"type":"string"},"appId":{"type":"string"},"exchangeCount":{"type":"integer","format":"int64"},"successRate":{"type":"number","format":"double"},"avgDurationMs":{"type":"number","format":"double"},"p99DurationMs":{"type":"number","format":"double"},"errorRate":{"type":"number","format":"double"},"throughputPerSec":{"type":"number","format":"double"},"sparkline":{"type":"array","items":{"type":"number","format":"double"}},"slaCompliance":{"type":"number","format":"double"}},"required":["appId","avgDurationMs","errorRate","exchangeCount","p99DurationMs","routeId","slaCompliance","sparkline","successRate","throughputPerSec"]},"ProcessorMetrics":{"type":"object","properties":{"processorId":{"type":"string"},"processorType":{"type":"string"},"routeId":{"type":"string"},"appId":{"type":"string"},"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"number","format":"double"},"p99DurationMs":{"type":"number","format":"double"},"errorRate":{"type":"number","format":"double"}},"required":["appId","avgDurationMs","errorRate","failedCount","p99DurationMs","processorId","processorType","routeId","totalCount"]},"LogEntryResponse":{"type":"object","description":"Application log entry","properties":{"timestamp":{"type":"string","description":"Log timestamp (ISO-8601)"},"level":{"type":"string","description":"Log level (INFO, WARN, ERROR, DEBUG, TRACE)"},"loggerName":{"type":"string","description":"Logger name"},"message":{"type":"string","description":"Log message"},"threadName":{"type":"string","description":"Thread name"},"stackTrace":{"type":"string","description":"Stack trace (if present)"},"exchangeId":{"type":"string","description":"Camel exchange ID (if present)"},"instanceId":{"type":"string","description":"Agent instance ID"},"application":{"type":"string","description":"Application ID"},"mdc":{"type":"object","additionalProperties":{"type":"string"},"description":"MDC context map"},"source":{"type":"string","description":"Log source: app or agent"}}},"LogSearchPageResponse":{"type":"object","description":"Log search response with cursor pagination and level counts","properties":{"data":{"type":"array","description":"Log entries for the current page","items":{"$ref":"#/components/schemas/LogEntryResponse"}},"nextCursor":{"type":"string","description":"Cursor for next page (null if no more results)"},"hasMore":{"type":"boolean","description":"Whether more results exist beyond this page"},"levelCounts":{"type":"object","additionalProperties":{"type":"integer","format":"int64"},"description":"Count of logs per level (unaffected by level filter)"}}},"TopError":{"type":"object","properties":{"errorType":{"type":"string"},"routeId":{"type":"string"},"processorId":{"type":"string"},"count":{"type":"integer","format":"int64"},"velocity":{"type":"number","format":"double"},"trend":{"type":"string"},"lastSeen":{"type":"string","format":"date-time"}}},"App":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"slug":{"type":"string"},"displayName":{"type":"string"},"containerConfig":{"type":"object","additionalProperties":{"type":"object"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"DiagramLayout":{"type":"object","properties":{"width":{"type":"number","format":"double"},"height":{"type":"number","format":"double"},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/PositionedNode"}},"edges":{"type":"array","items":{"$ref":"#/components/schemas/PositionedEdge"}}}},"PositionedEdge":{"type":"object","properties":{"sourceId":{"type":"string"},"targetId":{"type":"string"},"label":{"type":"string"},"points":{"type":"array","items":{"type":"array","items":{"type":"number","format":"double"}}}}},"PositionedNode":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"type":{"type":"string"},"x":{"type":"number","format":"double"},"y":{"type":"number","format":"double"},"width":{"type":"number","format":"double"},"height":{"type":"number","format":"double"},"endpointUri":{"type":"string"}}},"Difference":{"type":"object","properties":{"field":{"type":"string"},"staged":{"type":"string"},"deployed":{"type":"string"}}},"DirtyStateResponse":{"type":"object","properties":{"dirty":{"type":"boolean"},"lastSuccessfulDeploymentId":{"type":"string"},"differences":{"type":"array","items":{"$ref":"#/components/schemas/Difference"}}}},"AppConfigResponse":{"type":"object","properties":{"config":{"$ref":"#/components/schemas/ApplicationConfig"},"globalSensitiveKeys":{"type":"array","items":{"type":"string"}},"mergedSensitiveKeys":{"type":"array","items":{"type":"string"}}}},"UnreadCountResponse":{"type":"object","properties":{"total":{"type":"integer","format":"int64"},"bySeverity":{"type":"object","additionalProperties":{"type":"integer","format":"int64"}}}},"AgentInstanceResponse":{"type":"object","description":"Agent instance summary with runtime metrics","properties":{"instanceId":{"type":"string"},"displayName":{"type":"string"},"applicationId":{"type":"string"},"environmentId":{"type":"string"},"status":{"type":"string"},"routeIds":{"type":"array","items":{"type":"string"}},"registeredAt":{"type":"string","format":"date-time"},"lastHeartbeat":{"type":"string","format":"date-time"},"version":{"type":"string"},"capabilities":{"type":"object","additionalProperties":{"type":"object"}},"tps":{"type":"number","format":"double"},"errorRate":{"type":"number","format":"double"},"activeRoutes":{"type":"integer","format":"int32"},"totalRoutes":{"type":"integer","format":"int32"},"uptimeSeconds":{"type":"integer","format":"int64"},"cpuUsage":{"type":"number","format":"double","description":"Recent average CPU usage (0.0–1.0), -1 if unavailable"}},"required":["activeRoutes","applicationId","capabilities","cpuUsage","displayName","environmentId","errorRate","instanceId","lastHeartbeat","registeredAt","routeIds","status","totalRoutes","tps","uptimeSeconds","version"]},"AgentMetricsResponse":{"type":"object","properties":{"metrics":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"required":["metrics"]},"MetricBucket":{"type":"object","properties":{"time":{"type":"string","format":"date-time"},"value":{"type":"number","format":"double"}},"required":["time","value"]},"AgentEventPageResponse":{"type":"object","description":"Cursor-paginated agent event list","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AgentEventResponse"}},"nextCursor":{"type":"string"},"hasMore":{"type":"boolean"}}},"AgentEventResponse":{"type":"object","description":"Agent lifecycle event","properties":{"id":{"type":"integer","format":"int64"},"instanceId":{"type":"string"},"applicationId":{"type":"string"},"eventType":{"type":"string"},"detail":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}},"required":["applicationId","detail","eventType","id","instanceId","timestamp"]},"CatalogApp":{"type":"object","description":"Unified catalog entry combining app records with live agent data","properties":{"slug":{"type":"string","description":"Application slug (universal identifier)"},"displayName":{"type":"string","description":"Display name"},"managed":{"type":"boolean","description":"True if a managed App record exists in the database"},"environmentSlug":{"type":"string","description":"Environment slug"},"health":{"type":"string","description":"Composite health: deployment status + agent health"},"healthTooltip":{"type":"string","description":"Human-readable tooltip explaining the health state"},"agentCount":{"type":"integer","format":"int32","description":"Number of connected agents"},"routes":{"type":"array","description":"Live routes from agents","items":{"$ref":"#/components/schemas/RouteSummary"}},"agents":{"type":"array","description":"Connected agent summaries","items":{"$ref":"#/components/schemas/AgentSummary"}},"exchangeCount":{"type":"integer","format":"int64","description":"Total exchange count from ClickHouse"},"deployment":{"$ref":"#/components/schemas/DeploymentSummary","description":"Active deployment info, null if no deployment"}}},"DeploymentSummary":{"type":"object","properties":{"status":{"type":"string"},"replicas":{"type":"string"},"version":{"type":"integer","format":"int32"}}},"OidcPublicConfigResponse":{"type":"object","description":"OIDC configuration for SPA login flow","properties":{"issuer":{"type":"string"},"clientId":{"type":"string"},"authorizationEndpoint":{"type":"string"},"endSessionEndpoint":{"type":"string","description":"Present if the provider supports RP-initiated logout"},"resource":{"type":"string","description":"RFC 8707 resource indicator for the authorization request"},"additionalScopes":{"type":"array","description":"Additional scopes to request beyond openid email profile","items":{"type":"string"}}},"required":["authorizationEndpoint","clientId","issuer"]},"GroupSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"RoleSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"system":{"type":"boolean"},"source":{"type":"string"}}},"UserDetail":{"type":"object","properties":{"userId":{"type":"string"},"provider":{"type":"string"},"email":{"type":"string"},"displayName":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"directRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"directGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}},"effectiveRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"effectiveGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}}}},"SseEmitter":{"type":"object","properties":{"timeout":{"type":"integer","format":"int64"}}},"UsageStats":{"type":"object","properties":{"key":{"type":"string"},"count":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"integer","format":"int64"}}},"ServerInstanceInfo":{"type":"object","properties":{"serverInstanceId":{"type":"string"},"firstSeen":{"type":"string","format":"date-time"},"lastSeen":{"type":"string","format":"date-time"}}},"ServerMetricCatalogEntry":{"type":"object","properties":{"metricName":{"type":"string"},"metricType":{"type":"string"},"statistics":{"type":"array","items":{"type":"string"}},"tagKeys":{"type":"array","items":{"type":"string"}}}},"SensitiveKeysConfig":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"string"}}}},"RoleDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"scope":{"type":"string"},"system":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"assignedGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}},"directUsers":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"}},"effectivePrincipals":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"}}}},"UserSummary":{"type":"object","properties":{"userId":{"type":"string"},"displayName":{"type":"string"},"provider":{"type":"string"}}},"RbacStats":{"type":"object","properties":{"userCount":{"type":"integer","format":"int32"},"activeUserCount":{"type":"integer","format":"int32"},"groupCount":{"type":"integer","format":"int32"},"maxGroupDepth":{"type":"integer","format":"int32"},"roleCount":{"type":"integer","format":"int32"}}},"LicenseInfo":{"type":"object","properties":{"tier":{"type":"string"},"features":{"type":"array","items":{"type":"string","enum":["topology","lineage","correlation","debugger","replay"]},"uniqueItems":true},"limits":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}},"issuedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"expired":{"type":"boolean"}}},"GroupDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"parentGroupId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"directRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"effectiveRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"members":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"}},"childGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}}}},"TableSizeResponse":{"type":"object","description":"Table size and row count information","properties":{"tableName":{"type":"string","description":"Table name"},"rowCount":{"type":"integer","format":"int64","description":"Approximate row count"},"dataSize":{"type":"string","description":"Human-readable data size"},"indexSize":{"type":"string","description":"Human-readable index size"},"dataSizeBytes":{"type":"integer","format":"int64","description":"Data size in bytes"},"indexSizeBytes":{"type":"integer","format":"int64","description":"Index size in bytes"}}},"DatabaseStatusResponse":{"type":"object","description":"Database connection and version status","properties":{"connected":{"type":"boolean","description":"Whether the database is reachable"},"version":{"type":"string","description":"PostgreSQL version string"},"host":{"type":"string","description":"Database host"},"schema":{"type":"string","description":"Current schema"}}},"ActiveQueryResponse":{"type":"object","description":"Currently running database query","properties":{"pid":{"type":"integer","format":"int32","description":"Backend process ID"},"durationSeconds":{"type":"number","format":"double","description":"Query duration in seconds"},"state":{"type":"string","description":"Backend state (active, idle, etc.)"},"query":{"type":"string","description":"SQL query text"}}},"ConnectionPoolResponse":{"type":"object","description":"HikariCP connection pool statistics","properties":{"activeConnections":{"type":"integer","format":"int32","description":"Number of currently active connections"},"idleConnections":{"type":"integer","format":"int32","description":"Number of idle connections"},"pendingThreads":{"type":"integer","format":"int32","description":"Number of threads waiting for a connection"},"maxWaitMs":{"type":"integer","format":"int64","description":"Maximum wait time in milliseconds"},"maxPoolSize":{"type":"integer","format":"int32","description":"Maximum pool size"}}},"ClickHouseTableInfo":{"type":"object","description":"ClickHouse table information","properties":{"name":{"type":"string"},"engine":{"type":"string"},"rowCount":{"type":"integer","format":"int64"},"dataSize":{"type":"string"},"dataSizeBytes":{"type":"integer","format":"int64"},"partitionCount":{"type":"integer","format":"int32"}}},"ClickHouseStatusResponse":{"type":"object","description":"ClickHouse cluster status","properties":{"reachable":{"type":"boolean"},"version":{"type":"string"},"uptime":{"type":"string"},"host":{"type":"string"}}},"ClickHouseQueryInfo":{"type":"object","description":"Active ClickHouse query information","properties":{"queryId":{"type":"string"},"elapsedSeconds":{"type":"number","format":"double"},"memory":{"type":"string"},"readRows":{"type":"integer","format":"int64"},"query":{"type":"string"}}},"ClickHousePerformanceResponse":{"type":"object","description":"ClickHouse storage and performance metrics","properties":{"diskSize":{"type":"string"},"uncompressedSize":{"type":"string"},"compressionRatio":{"type":"number","format":"double"},"totalRows":{"type":"integer","format":"int64"},"partCount":{"type":"integer","format":"int32"},"memoryUsage":{"type":"string"},"currentQueries":{"type":"integer","format":"int32"}}},"AuditLogPageResponse":{"type":"object","description":"Paginated audit log entries","properties":{"items":{"type":"array","description":"Audit log entries","items":{"$ref":"#/components/schemas/AuditRecord"}},"totalCount":{"type":"integer","format":"int64","description":"Total number of matching entries"},"page":{"type":"integer","format":"int32","description":"Current page number (0-based)"},"pageSize":{"type":"integer","format":"int32","description":"Page size"},"totalPages":{"type":"integer","format":"int32","description":"Total number of pages"}}},"AuditRecord":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"timestamp":{"type":"string","format":"date-time"},"username":{"type":"string"},"action":{"type":"string"},"category":{"type":"string","enum":["INFRA","AUTH","USER_MGMT","CONFIG","RBAC","AGENT","OUTBOUND_CONNECTION_CHANGE","OUTBOUND_HTTP_TRUST_CHANGE","ALERT_RULE_CHANGE","ALERT_SILENCE_CHANGE","DEPLOYMENT"]},"target":{"type":"string"},"detail":{"type":"object","additionalProperties":{"type":"object"}},"result":{"type":"string","enum":["SUCCESS","FAILURE"]},"ipAddress":{"type":"string"},"userAgent":{"type":"string"}}}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}}} \ No newline at end of file +{"openapi":"3.1.0","info":{"title":"Cameleer Server API","version":"1.0"},"servers":[{"url":"/api/v1","description":"Relative"}],"security":[{"bearer":[]}],"tags":[{"name":"Route Metrics","description":"Route performance metrics (env-scoped)"},{"name":"Database Admin","description":"Database monitoring and management (ADMIN only)"},{"name":"Threshold Admin","description":"Monitoring threshold configuration (ADMIN only)"},{"name":"Agent Commands","description":"Command push endpoints for agent communication"},{"name":"Agent List","description":"List registered agents in an environment"},{"name":"Sensitive Keys Admin","description":"Global sensitive key masking configuration (ADMIN only)"},{"name":"License Admin","description":"License management"},{"name":"Role Admin","description":"Role management (ADMIN only)"},{"name":"RBAC Stats","description":"RBAC statistics (ADMIN only)"},{"name":"OIDC Config Admin","description":"OIDC provider configuration (ADMIN only)"},{"name":"Alerts Inbox","description":"In-app alert inbox, ack and read tracking (env-scoped)"},{"name":"Application Config","description":"Per-application observability configuration (user-facing)"},{"name":"App Management","description":"Application lifecycle and JAR uploads (env-scoped)"},{"name":"Catalog","description":"Unified application catalog"},{"name":"ClickHouse Admin","description":"ClickHouse monitoring and diagnostics (ADMIN only)"},{"name":"Alert Silences","description":"Alert silence management (env-scoped)"},{"name":"Ingestion","description":"Data ingestion endpoints"},{"name":"Group Admin","description":"Group management (ADMIN only)"},{"name":"Usage Analytics","description":"UI usage pattern analytics"},{"name":"Alert Notifications","description":"Outbound webhook notification management"},{"name":"Deployment Management","description":"Deploy, stop, promote, and view logs"},{"name":"Detail","description":"Execution detail and processor snapshot endpoints"},{"name":"Server Self-Metrics","description":"Read API over the server's own Micrometer registry snapshots (ADMIN only)"},{"name":"Outbound Connections Admin","description":"Admin-managed outbound HTTPS destinations"},{"name":"Agent Config","description":"Agent-authoritative config read (AGENT only)"},{"name":"User Admin","description":"User management (ADMIN only)"},{"name":"Agent Management","description":"Agent registration and lifecycle endpoints"},{"name":"Authentication","description":"Login and token refresh endpoints"},{"name":"Agent Events","description":"Agent lifecycle event log (env-scoped)"},{"name":"Route Catalog","description":"Route catalog and discovery (env-scoped)"},{"name":"Application Logs","description":"Query application logs (env-scoped)"},{"name":"Agent SSE","description":"Server-Sent Events endpoint for agent communication"},{"name":"Search","description":"Transaction search and stats (env-scoped)"},{"name":"Audit Log","description":"Audit log viewer (ADMIN only)"},{"name":"Claim Mapping Admin","description":"Manage OIDC claim-to-role/group mapping rules"},{"name":"Diagrams","description":"Diagram rendering endpoints"},{"name":"Environment Admin","description":"Environment management (ADMIN only)"},{"name":"App Settings","description":"Per-application dashboard settings (ADMIN/OPERATOR)"},{"name":"Alert Rules","description":"Alert rule management (env-scoped)"}],"paths":{"/environments/{envSlug}/apps/{appSlug}/settings":{"get":{"tags":["App Settings"],"summary":"Get settings for an application in this environment (returns defaults if not configured)","operationId":"getByAppId","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppSettings"}}}}}},"put":{"tags":["App Settings"],"summary":"Create or update settings for an application in this environment","operationId":"update","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppSettings"}}}}}},"delete":{"tags":["App Settings"],"summary":"Delete application settings for this environment (reverts to defaults)","operationId":"delete","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/apps/{appSlug}/container-config":{"put":{"tags":["App Management"],"summary":"Update container config for this app","operationId":"updateContainerConfig","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}},"required":true},"responses":{"200":{"description":"Container config updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid configuration","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"App not found in this environment","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/config":{"get":{"tags":["Application Config"],"summary":"Get application config for this environment","description":"Returns stored config merged with global sensitive keys. Falls back to defaults if no row is persisted yet.","operationId":"getConfig","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Config returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppConfigResponse"}}}}}},"put":{"tags":["Application Config"],"summary":"Update application config for this environment","description":"Saves config. When apply=live (default), also pushes CONFIG_UPDATE to LIVE agents. When apply=staged, persists without a live push — the next successful deploy applies it.","operationId":"updateConfig","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"apply","in":"query","description":"When to apply: 'live' (default) saves and pushes CONFIG_UPDATE to live agents immediately; 'staged' saves without pushing — the next successful deploy applies it.","required":false,"schema":{"type":"string","default":"live"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationConfig"}}},"required":true},"responses":{"200":{"description":"Config saved (and pushed if apply=live)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ConfigUpdateResponse"}}}},"400":{"description":"Unknown apply value (must be 'staged' or 'live')","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ConfigUpdateResponse"}}}}}}},"/environments/{envSlug}/alerts/silences/{id}":{"put":{"tags":["Alert Silences"],"operationId":"update_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertSilenceRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertSilenceResponse"}}}}}},"delete":{"tags":["Alert Silences"],"operationId":"delete_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/rules/{id}":{"get":{"tags":["Alert Rules"],"operationId":"get","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}},"put":{"tags":["Alert Rules"],"operationId":"update_2","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}},"delete":{"tags":["Alert Rules"],"operationId":"delete_2","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/admin/users/{userId}":{"get":{"tags":["User Admin"],"summary":"Get user by ID with RBAC detail","operationId":"getUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}},"404":{"description":"User not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}}}},"put":{"tags":["User Admin"],"summary":"Update user display name or email","operationId":"updateUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated"},"404":{"description":"User not found"}}},"delete":{"tags":["User Admin"],"summary":"Delete user","operationId":"deleteUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"User deleted"},"409":{"description":"Cannot delete the last admin user"}}}},"/admin/thresholds":{"get":{"tags":["Threshold Admin"],"summary":"Get current threshold configuration","operationId":"getThresholds","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ThresholdConfig"}}}}}},"put":{"tags":["Threshold Admin"],"summary":"Update threshold configuration","operationId":"updateThresholds","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThresholdConfigRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ThresholdConfig"}}}}}}},"/admin/sensitive-keys":{"get":{"tags":["Sensitive Keys Admin"],"summary":"Get global sensitive keys configuration","operationId":"getSensitiveKeys","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SensitiveKeysConfig"}}}}}},"put":{"tags":["Sensitive Keys Admin"],"summary":"Update global sensitive keys configuration","description":"Saves the global sensitive keys. Optionally fans out merged keys to all live agents.","operationId":"updateSensitiveKeys","parameters":[{"name":"pushToAgents","in":"query","required":false,"schema":{"type":"boolean","default":false}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveKeysRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SensitiveKeysResponse"}}}}}}},"/admin/roles/{id}":{"get":{"tags":["Role Admin"],"summary":"Get role by ID with effective principals","operationId":"getRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RoleDetail"}}}},"404":{"description":"Role not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RoleDetail"}}}}}},"put":{"tags":["Role Admin"],"summary":"Update a custom role","operationId":"updateRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role updated"},"403":{"description":"Cannot modify system role"},"404":{"description":"Role not found"}}},"delete":{"tags":["Role Admin"],"summary":"Delete a custom role","operationId":"deleteRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role deleted"},"403":{"description":"Cannot delete system role"},"404":{"description":"Role not found"}}}},"/admin/outbound-connections/{id}":{"get":{"tags":["Outbound Connections Admin"],"operationId":"get_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OutboundConnectionDto"}}}}}},"put":{"tags":["Outbound Connections Admin"],"operationId":"update_3","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundConnectionRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OutboundConnectionDto"}}}}}},"delete":{"tags":["Outbound Connections Admin"],"operationId":"delete_3","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/admin/oidc":{"get":{"tags":["OIDC Config Admin"],"summary":"Get OIDC configuration","operationId":"getConfig_1","responses":{"200":{"description":"Current OIDC configuration (client_secret masked)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcAdminConfigResponse"}}}}}},"put":{"tags":["OIDC Config Admin"],"summary":"Save OIDC configuration","operationId":"saveConfig","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcAdminConfigRequest"}}},"required":true},"responses":{"200":{"description":"Configuration saved","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcAdminConfigResponse"}}}},"400":{"description":"Invalid configuration","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["OIDC Config Admin"],"summary":"Delete OIDC configuration","operationId":"deleteConfig","responses":{"204":{"description":"Configuration deleted"}}}},"/admin/groups/{id}":{"get":{"tags":["Group Admin"],"summary":"Get group by ID with effective roles","operationId":"getGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Group found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupDetail"}}}},"404":{"description":"Group not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupDetail"}}}}}},"put":{"tags":["Group Admin"],"summary":"Update group name or parent","operationId":"updateGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroupRequest"}}},"required":true},"responses":{"200":{"description":"Group updated"},"404":{"description":"Group not found"},"409":{"description":"Cycle detected in group hierarchy"}}},"delete":{"tags":["Group Admin"],"summary":"Delete group","operationId":"deleteGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Group deleted"},"404":{"description":"Group not found"}}}},"/admin/environments/{envSlug}":{"get":{"tags":["Environment Admin"],"summary":"Get environment by slug","operationId":"getEnvironment","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Environment"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Environment"}}}}}},"put":{"tags":["Environment Admin"],"summary":"Update an environment's mutable fields (displayName, production, enabled, color)","description":"Slug is immutable after creation and cannot be changed. Any slug field in the request body is ignored. If color is null or absent, the existing color is preserved.","operationId":"updateEnvironment","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Unknown color value","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"type":"object"}}}}}},"delete":{"tags":["Environment Admin"],"summary":"Delete an environment","operationId":"deleteEnvironment","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Environment deleted","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Cannot delete default environment","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/environments/{envSlug}/jar-retention":{"put":{"tags":["Environment Admin"],"summary":"Update JAR retention policy for an environment","operationId":"updateJarRetention","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JarRetentionRequest"}}},"required":true},"responses":{"200":{"description":"Retention policy updated","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"type":"object"}}}},"422":{"description":"jarRetentionCount exceeds license cap","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/environments/{envSlug}/default-container-config":{"put":{"tags":["Environment Admin"],"summary":"Update default container config for an environment","operationId":"updateDefaultContainerConfig","parameters":[{"name":"envSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}},"required":true},"responses":{"200":{"description":"Default container config updated","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid configuration","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Environment not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/claim-mappings/{id}":{"get":{"tags":["Claim Mapping Admin"],"summary":"Get a claim mapping rule by ID","operationId":"get_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClaimMappingRule"}}}}}},"put":{"tags":["Claim Mapping Admin"],"summary":"Update a claim mapping rule","operationId":"update_4","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRuleRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClaimMappingRule"}}}}}},"delete":{"tags":["Claim Mapping Admin"],"summary":"Delete a claim mapping rule","operationId":"delete_4","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/executions/search":{"post":{"tags":["Search"],"summary":"Advanced search with all filters","description":"Env from the path overrides any environment field in the body.","operationId":"searchPost","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SearchResultExecutionSummary"}}}}}}},"/environments/{envSlug}/apps":{"get":{"tags":["App Management"],"summary":"List apps in this environment","operationId":"listApps","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"App list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/App"}}}}}}},"post":{"tags":["App Management"],"summary":"Create a new app in this environment","description":"Slug must match ^[a-z0-9][a-z0-9-]{0,63}$ and be unique within the environment. Slug is immutable after creation.","operationId":"createApp","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAppRequest"}}},"required":true},"responses":{"201":{"description":"App created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid slug, or slug already exists in this environment","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/versions":{"get":{"tags":["App Management"],"summary":"List versions for this app","operationId":"listVersions","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Version list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AppVersion"}}}}}}},"post":{"tags":["App Management"],"summary":"Upload a JAR for a new version of this app","operationId":"uploadJar","parameters":[{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"env":{"$ref":"#/components/schemas/Environment"},"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"201":{"description":"JAR uploaded and version created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppVersion"}}}},"404":{"description":"App not found in this environment","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppVersion"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments":{"get":{"tags":["Deployment Management"],"summary":"List deployments for this app in this environment","operationId":"listDeployments","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deployment list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Deployment"}}}}}}},"post":{"tags":["Deployment Management"],"summary":"Create and start a new deployment for this app in this environment","operationId":"deploy","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployRequest"}}},"required":true},"responses":{"202":{"description":"Deployment accepted and starting","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments/{deploymentId}/stop":{"post":{"tags":["Deployment Management"],"summary":"Stop a running deployment","operationId":"stop","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deployment stopped","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}},"404":{"description":"Deployment not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments/{deploymentId}/promote":{"post":{"tags":["Deployment Management"],"summary":"Promote this deployment to a different environment","description":"Target environment is specified by slug in the request body. The same app slug must exist in the target environment (or be created separately first).","operationId":"promote","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteRequest"}}},"required":true},"responses":{"202":{"description":"Promotion accepted and starting","content":{"*/*":{"schema":{"type":"object"}}}},"404":{"description":"Deployment or target environment not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/config/test-expression":{"post":{"tags":["Application Config"],"summary":"Test a tap expression against sample data via a live agent in this environment","operationId":"testExpression","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestExpressionRequest"}}},"required":true},"responses":{"200":{"description":"Expression evaluated successfully","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestExpressionResponse"}}}},"404":{"description":"No live agent available for this application in this environment","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestExpressionResponse"}}}},"504":{"description":"Agent did not respond in time","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestExpressionResponse"}}}}}}},"/environments/{envSlug}/alerts/{id}/restore":{"post":{"tags":["Alerts Inbox"],"operationId":"restore","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/{id}/read":{"post":{"tags":["Alerts Inbox"],"operationId":"read","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/{id}/ack":{"post":{"tags":["Alerts Inbox"],"operationId":"ack","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertDto"}}}}}}},"/environments/{envSlug}/alerts/silences":{"get":{"tags":["Alert Silences"],"operationId":"list","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertSilenceResponse"}}}}}}},"post":{"tags":["Alert Silences"],"operationId":"create","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertSilenceRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertSilenceResponse"}}}}}}},"/environments/{envSlug}/alerts/rules":{"get":{"tags":["Alert Rules"],"operationId":"list_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}}},"post":{"tags":["Alert Rules"],"operationId":"create_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}}},"/environments/{envSlug}/alerts/rules/{id}/test-evaluate":{"post":{"tags":["Alert Rules"],"operationId":"testEvaluate","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEvaluateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestEvaluateResponse"}}}}}}},"/environments/{envSlug}/alerts/rules/{id}/render-preview":{"post":{"tags":["Alert Rules"],"operationId":"renderPreview","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderPreviewRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RenderPreviewResponse"}}}}}}},"/environments/{envSlug}/alerts/rules/{id}/enable":{"post":{"tags":["Alert Rules"],"operationId":"enable","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}}},"/environments/{envSlug}/alerts/rules/{id}/disable":{"post":{"tags":["Alert Rules"],"operationId":"disable","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}}}},"/environments/{envSlug}/alerts/bulk-read":{"post":{"tags":["Alerts Inbox"],"operationId":"bulkRead","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIdsRequest"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/bulk-delete":{"post":{"tags":["Alerts Inbox"],"operationId":"bulkDelete","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIdsRequest"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/bulk-ack":{"post":{"tags":["Alerts Inbox"],"operationId":"bulkAck","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIdsRequest"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/data/metrics":{"post":{"tags":["Ingestion"],"summary":"Ingest agent metrics","description":"Accepts an array of MetricsSnapshot objects","operationId":"ingestMetrics","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"202":{"description":"Data accepted for processing"},"400":{"description":"Invalid payload"},"503":{"description":"Buffer full, retry later"}}}},"/data/logs":{"post":{"tags":["Ingestion"],"summary":"Ingest application log entries","description":"Accepts a batch of log entries from an agent. Entries are buffered and flushed periodically.","operationId":"ingestLogs","requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LogEntry"}}}},"required":true},"responses":{"202":{"description":"Logs accepted for indexing"}}}},"/data/executions":{"post":{"tags":["Ingestion"],"summary":"Ingest execution chunk","operationId":"ingestChunks","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/data/events":{"post":{"tags":["Ingestion"],"summary":"Ingest agent events","operationId":"ingestEvents","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/data/diagrams":{"post":{"tags":["Ingestion"],"summary":"Ingest route diagram data","description":"Accepts a single RouteGraph or an array of RouteGraphs","operationId":"ingestDiagrams","requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"202":{"description":"Data accepted for processing"}}}},"/auth/refresh":{"post":{"tags":["Authentication"],"summary":"Refresh access token","operationId":"refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"Token refreshed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"Invalid refresh token","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/oidc/callback":{"post":{"tags":["Authentication"],"summary":"Exchange OIDC authorization code for JWTs","operationId":"callback","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallbackRequest"}}},"required":true},"responses":{"200":{"description":"Authentication successful","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"OIDC authentication failed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Account not provisioned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"OIDC not configured or disabled","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}}}}},"/auth/login":{"post":{"tags":["Authentication"],"summary":"Login with local credentials","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"Invalid credentials","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Account locked due to too many failed attempts","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}}}}},"/alerts/notifications/{id}/retry":{"post":{"tags":["Alert Notifications"],"operationId":"retry","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertNotificationDto"}}}}}}},"/agents/{id}/replay":{"post":{"tags":["Agent Commands"],"summary":"Replay an exchange on a specific agent (synchronous)","description":"Sends a replay command and waits for the agent to complete the replay. Returns the replay result including status, replayExchangeId, and duration.","operationId":"replayExchange","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplayRequest"}}},"required":true},"responses":{"200":{"description":"Replay completed (check status for success/failure)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ReplayResponse"}}}},"404":{"description":"Agent not found or not connected","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ReplayResponse"}}}},"504":{"description":"Agent did not respond in time","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ReplayResponse"}}}}}}},"/agents/{id}/refresh":{"post":{"tags":["Agent Management"],"summary":"Refresh access token","description":"Issues a new access JWT from a valid refresh token","operationId":"refresh_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRefreshRequest"}}},"required":true},"responses":{"200":{"description":"New access token issued","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRefreshResponse"}}}},"401":{"description":"Invalid or expired refresh token","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRefreshResponse"}}}},"404":{"description":"Agent not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRefreshResponse"}}}}}}},"/agents/{id}/heartbeat":{"post":{"tags":["Agent Management"],"summary":"Agent heartbeat ping","description":"Updates the agent's last heartbeat timestamp. Auto-registers the agent if not in registry (e.g. after server restart).","operationId":"heartbeat","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatRequest"}}}},"responses":{"200":{"description":"Heartbeat accepted"}}}},"/agents/{id}/deregister":{"post":{"tags":["Agent Management"],"summary":"Deregister agent","description":"Removes the agent from the registry. Called by agents during graceful shutdown.","operationId":"deregister","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent deregistered"},"404":{"description":"Agent not registered"}}}},"/agents/{id}/commands":{"post":{"tags":["Agent Commands"],"summary":"Send command to a specific agent","description":"Sends a command to the specified agent via SSE","operationId":"sendCommand","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"}}},"required":true},"responses":{"202":{"description":"Command accepted","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandSingleResponse"}}}},"400":{"description":"Invalid command payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandSingleResponse"}}}},"404":{"description":"Agent not registered","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandSingleResponse"}}}}}}},"/agents/{id}/commands/{commandId}/ack":{"post":{"tags":["Agent Commands"],"summary":"Acknowledge command receipt","description":"Agent acknowledges that it has received and processed a command, with result status and message","operationId":"acknowledgeCommand","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"commandId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandAckRequest"}}}},"responses":{"200":{"description":"Command acknowledged"},"404":{"description":"Command not found"}}}},"/agents/register":{"post":{"tags":["Agent Management"],"summary":"Register an agent","description":"Registers a new agent or re-registers an existing one. Requires bootstrap token in Authorization header.","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRegistrationRequest"}}},"required":true},"responses":{"200":{"description":"Agent registered successfully","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRegistrationResponse"}}}},"400":{"description":"Invalid registration payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid bootstrap token","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentRegistrationResponse"}}}}}}},"/agents/groups/{group}/commands":{"post":{"tags":["Agent Commands"],"summary":"Send command to all agents in a group","description":"Sends a command to all LIVE agents in the specified group and waits for responses","operationId":"sendGroupCommand","parameters":[{"name":"group","in":"path","required":true,"schema":{"type":"string"}},{"name":"environment","in":"query","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"}}},"required":true},"responses":{"200":{"description":"Commands dispatched and responses collected","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandGroupResponse"}}}},"400":{"description":"Invalid command payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandGroupResponse"}}}}}}},"/agents/commands":{"post":{"tags":["Agent Commands"],"summary":"Broadcast command to all live agents","description":"Sends a command to all agents currently in LIVE state","operationId":"broadcastCommand","parameters":[{"name":"environment","in":"query","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"}}},"required":true},"responses":{"202":{"description":"Commands accepted","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandBroadcastResponse"}}}},"400":{"description":"Invalid command payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CommandBroadcastResponse"}}}}}}},"/admin/users":{"get":{"tags":["User Admin"],"summary":"List all users with RBAC detail","operationId":"listUsers","responses":{"200":{"description":"User list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserDetail"}}}}}}},"post":{"tags":["User Admin"],"summary":"Create a local user","operationId":"createUser","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"200":{"description":"User created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Disabled in OIDC mode","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/users/{userId}/roles/{roleId}":{"post":{"tags":["User Admin"],"summary":"Assign a role to a user","operationId":"assignRoleToUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role assigned"},"404":{"description":"User or role not found"}}},"delete":{"tags":["User Admin"],"summary":"Remove a role from a user","operationId":"removeRoleFromUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role removed"}}}},"/admin/users/{userId}/password":{"post":{"tags":["User Admin"],"summary":"Reset user password","operationId":"resetPassword","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password reset"},"400":{"description":"Disabled in OIDC mode or policy violation"}}}},"/admin/users/{userId}/groups/{groupId}":{"post":{"tags":["User Admin"],"summary":"Add a user to a group","operationId":"addUserToGroup","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User added to group"}}},"delete":{"tags":["User Admin"],"summary":"Remove a user from a group","operationId":"removeUserFromGroup","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"User removed from group"}}}},"/admin/server-metrics/query":{"post":{"tags":["Server Self-Metrics"],"summary":"Generic time-series query","description":"Returns bucketed series for a single metric_name. Supports aggregation (avg/sum/max/min/latest), group-by-tag, filter-by-tag, counter delta mode, and a derived 'mean' statistic for timers.","operationId":"query","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryBody"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ServerMetricQueryResponse"}}}}}}},"/admin/roles":{"get":{"tags":["Role Admin"],"summary":"List all roles (system and custom)","operationId":"listRoles","responses":{"200":{"description":"Role list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RoleDetail"}}}}}}},"post":{"tags":["Role Admin"],"summary":"Create a custom role","operationId":"createRole","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role created","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string","format":"uuid"}}}}}}}},"/admin/outbound-connections":{"get":{"tags":["Outbound Connections Admin"],"operationId":"list_2","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OutboundConnectionDto"}}}}}}},"post":{"tags":["Outbound Connections Admin"],"operationId":"create_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundConnectionRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OutboundConnectionDto"}}}}}}},"/admin/outbound-connections/{id}/test":{"post":{"tags":["Outbound Connections Admin"],"operationId":"test","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OutboundConnectionTestResult"}}}}}}},"/admin/oidc/test":{"post":{"tags":["OIDC Config Admin"],"summary":"Test OIDC provider connectivity","operationId":"testConnection","responses":{"200":{"description":"Provider reachable","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcTestResult"}}}},"400":{"description":"Provider unreachable or misconfigured","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/license":{"get":{"tags":["License Admin"],"summary":"Get current license state, invalid reason, and parsed envelope","operationId":"getCurrent","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}}}},"post":{"tags":["License Admin"],"summary":"Install or replace the license token at runtime","operationId":"update_5","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLicenseRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/groups":{"get":{"tags":["Group Admin"],"summary":"List all groups with hierarchy and effective roles","operationId":"listGroups","responses":{"200":{"description":"Group list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GroupDetail"}}}}}}},"post":{"tags":["Group Admin"],"summary":"Create a new group","operationId":"createGroup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroupRequest"}}},"required":true},"responses":{"200":{"description":"Group created","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string","format":"uuid"}}}}}}}},"/admin/groups/{id}/roles/{roleId}":{"post":{"tags":["Group Admin"],"summary":"Assign a role to a group","operationId":"assignRoleToGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Role assigned to group"},"404":{"description":"Group not found"}}},"delete":{"tags":["Group Admin"],"summary":"Remove a role from a group","operationId":"removeRoleFromGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"roleId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Role removed from group"},"404":{"description":"Group not found"}}}},"/admin/environments":{"get":{"tags":["Environment Admin"],"summary":"List all environments","operationId":"listEnvironments","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Environment"}}}}}}},"post":{"tags":["Environment Admin"],"summary":"Create a new environment","operationId":"createEnvironment","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created","content":{"*/*":{"schema":{"type":"object"}}}},"400":{"description":"Invalid slug or slug already exists","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/admin/database/queries/{pid}/kill":{"post":{"tags":["Database Admin"],"summary":"Terminate a query by PID","operationId":"killQuery","parameters":[{"name":"pid","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"}}}},"/admin/claim-mappings":{"get":{"tags":["Claim Mapping Admin"],"summary":"List all claim mapping rules","operationId":"list_3","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClaimMappingRule"}}}}}}},"post":{"tags":["Claim Mapping Admin"],"summary":"Create a claim mapping rule","operationId":"create_3","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRuleRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClaimMappingRule"}}}}}}},"/admin/claim-mappings/test":{"post":{"tags":["Claim Mapping Admin"],"summary":"Test claim mapping rules against a set of claims (accepts unsaved rules)","operationId":"test_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestResponse"}}}}}}},"/executions/{executionId}":{"get":{"tags":["Detail"],"summary":"Get execution detail with nested processor tree","operationId":"getDetail","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Execution detail found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExecutionDetail"}}}},"404":{"description":"Execution not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExecutionDetail"}}}}}}},"/executions/{executionId}/processors/{index}/snapshot":{"get":{"tags":["Detail"],"summary":"Get exchange snapshot for a specific processor by index","operationId":"getProcessorSnapshot","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"index","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Snapshot data","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"404":{"description":"Snapshot not found","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/executions/{executionId}/processors/by-seq/{seq}/snapshot":{"get":{"tags":["Detail"],"summary":"Get exchange snapshot for a processor by seq number","operationId":"processorSnapshotBySeq","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"seq","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Snapshot data","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"404":{"description":"Snapshot not found","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/executions/{executionId}/processors/by-id/{processorId}/snapshot":{"get":{"tags":["Detail"],"summary":"Get exchange snapshot for a specific processor by processorId","operationId":"processorSnapshotById","parameters":[{"name":"executionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"processorId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Snapshot data","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"404":{"description":"Snapshot not found","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/environments/{envSlug}/stats":{"get":{"tags":["Search"],"summary":"Aggregate execution stats (P99 latency, active count, SLA compliance)","operationId":"stats","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExecutionStats"}}}}}}},"/environments/{envSlug}/stats/timeseries":{"get":{"tags":["Search"],"summary":"Bucketed time-series stats over a time window","operationId":"timeseries","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":24}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/StatsTimeseries"}}}}}}},"/environments/{envSlug}/stats/timeseries/by-route":{"get":{"tags":["Search"],"summary":"Timeseries grouped by route for an application","operationId":"timeseriesByRoute","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":24}},{"name":"application","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/StatsTimeseries"}}}}}}}},"/environments/{envSlug}/stats/timeseries/by-app":{"get":{"tags":["Search"],"summary":"Timeseries grouped by application","operationId":"timeseriesByApp","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":24}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/StatsTimeseries"}}}}}}}},"/environments/{envSlug}/stats/punchcard":{"get":{"tags":["Search"],"summary":"Transaction punchcard: weekday x hour grid (rolling 7 days)","operationId":"punchcard","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PunchcardCell"}}}}}}}},"/environments/{envSlug}/routes":{"get":{"tags":["Route Catalog"],"summary":"Get route catalog for this environment","description":"Returns all applications with their routes, agents, and health status — filtered to this environment","operationId":"getCatalog","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Catalog returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AppCatalogEntry"}}}}}}}},"/environments/{envSlug}/routes/metrics":{"get":{"tags":["Route Metrics"],"summary":"Get route metrics for this environment","description":"Returns aggregated performance metrics per route for the given time window. Optional appId filter narrows to a single application.","operationId":"getMetrics","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"appId","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteMetrics"}}}}}}}},"/environments/{envSlug}/routes/metrics/processors":{"get":{"tags":["Route Metrics"],"summary":"Get processor metrics for this environment","description":"Returns aggregated performance metrics per processor for the given route and time window","operationId":"getProcessorMetrics","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"routeId","in":"query","required":true,"schema":{"type":"string"}},{"name":"appId","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Metrics returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProcessorMetrics"}}}}}}}},"/environments/{envSlug}/logs":{"get":{"tags":["Application Logs"],"summary":"Search application log entries in this environment","description":"Cursor-paginated log search scoped to the env in the path. Supports free-text search, multi-level filtering, and optional application/agent scoping.","operationId":"searchLogs","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"q","in":"query","required":false,"schema":{"type":"string"}},{"name":"query","in":"query","required":false,"schema":{"type":"string"}},{"name":"level","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"schema":{"type":"string"}},{"name":"exchangeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"logger","in":"query","required":false,"schema":{"type":"string"}},{"name":"source","in":"query","required":false,"schema":{"type":"string"}},{"name":"instanceIds","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":100}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"desc"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/LogSearchPageResponse"}}}}}}},"/environments/{envSlug}/executions":{"get":{"tags":["Search"],"summary":"Search executions with basic filters (env from path)","operationId":"searchGet","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"timeFrom","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"timeTo","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"correlationId","in":"query","required":false,"schema":{"type":"string"}},{"name":"text","in":"query","required":false,"schema":{"type":"string"}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"schema":{"type":"string"}},{"name":"processorType","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}},{"name":"attr","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}},{"name":"sortField","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortDir","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SearchResultExecutionSummary"}}}}}}},"/environments/{envSlug}/errors/top":{"get":{"tags":["Search"],"summary":"Top N errors with velocity trend","operationId":"topErrors","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}},{"name":"routeId","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":5}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TopError"}}}}}}}},"/environments/{envSlug}/config":{"get":{"tags":["Application Config"],"summary":"List application configs in this environment","operationId":"listConfigs","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"Configs returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApplicationConfig"}}}}}}}},"/environments/{envSlug}/attributes/keys":{"get":{"tags":["Search"],"summary":"Distinct attribute key names for this environment","operationId":"attributeKeys","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"type":"string"}}}}}}}},"/environments/{envSlug}/apps/{appSlug}":{"get":{"tags":["App Management"],"summary":"Get app by env + slug","operationId":"getApp","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"App found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/App"}}}},"404":{"description":"App not found in this environment","content":{"*/*":{"schema":{"$ref":"#/components/schemas/App"}}}}}},"delete":{"tags":["App Management"],"summary":"Delete this app","operationId":"deleteApp","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"App deleted"}}}},"/environments/{envSlug}/apps/{appSlug}/routes/{routeId}/diagram":{"get":{"tags":["Diagrams"],"summary":"Find the latest diagram for this app's route in this environment","description":"Returns the most recently stored diagram for (app, env, route). Independent of the agent registry, so routes removed from the current app version still resolve.","operationId":"findByAppAndRoute","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"routeId","in":"path","required":true,"schema":{"type":"string"}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","default":"LR"}}],"responses":{"200":{"description":"Diagram layout returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DiagramLayout"}}}},"404":{"description":"No diagram found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DiagramLayout"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/processor-routes":{"get":{"tags":["Application Config"],"summary":"Get processor to route mapping for this environment","description":"Returns a map of processorId → routeId for all processors seen in this application + environment","operationId":"getProcessorRouteMapping","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Mapping returned","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/environments/{envSlug}/apps/{appSlug}/dirty-state":{"get":{"tags":["App Management"],"summary":"Check whether the app's current config differs from the last successful deploy","description":"Returns dirty=true when the desired state (current JAR + agent config + container config) would produce a changed deployment. When no successful deploy exists yet, dirty=true.","operationId":"getDirtyState","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Dirty-state computed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DirtyStateResponse"}}}},"404":{"description":"App not found in this environment","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DirtyStateResponse"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments/{deploymentId}":{"get":{"tags":["Deployment Management"],"summary":"Get deployment by ID","operationId":"getDeployment","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deployment found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}},"404":{"description":"Deployment not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Deployment"}}}}}}},"/environments/{envSlug}/apps/{appSlug}/deployments/{deploymentId}/logs":{"get":{"tags":["Deployment Management"],"summary":"Get container logs for this deployment","operationId":"getLogs","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Logs returned","content":{"*/*":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Deployment not found or no container","content":{"*/*":{"schema":{"type":"array","items":{"type":"string"}}}}}}}},"/environments/{envSlug}/app-settings":{"get":{"tags":["App Settings"],"summary":"List application settings in this environment","operationId":"getAll","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AppSettings"}}}}}}}},"/environments/{envSlug}/alerts":{"get":{"tags":["Alerts Inbox"],"operationId":"list_4","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}},{"name":"state","in":"query","required":false,"schema":{"type":"array","items":{"type":"string","enum":["PENDING","FIRING","RESOLVED"]}}},{"name":"severity","in":"query","required":false,"schema":{"type":"array","items":{"type":"string","enum":["CRITICAL","WARNING","INFO"]}}},{"name":"acked","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"read","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertDto"}}}}}}}},"/environments/{envSlug}/alerts/{id}":{"get":{"tags":["Alerts Inbox"],"operationId":"get_3","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AlertDto"}}}}}},"delete":{"tags":["Alerts Inbox"],"operationId":"delete_5","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/environments/{envSlug}/alerts/{alertId}/notifications":{"get":{"tags":["Alert Notifications"],"operationId":"listForInstance","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"alertId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertNotificationDto"}}}}}}}},"/environments/{envSlug}/alerts/unread-count":{"get":{"tags":["Alerts Inbox"],"operationId":"unreadCount","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UnreadCountResponse"}}}}}}},"/environments/{envSlug}/agents":{"get":{"tags":["Agent List"],"summary":"List all agents in this environment","description":"Returns registered agents with runtime metrics, optionally filtered by status and/or application","operationId":"listAgents","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"application","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent list returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AgentInstanceResponse"}}}}},"400":{"description":"Invalid status filter","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/environments/{envSlug}/agents/{agentId}/metrics":{"get":{"tags":["agent-metrics-controller"],"operationId":"getMetrics_1","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"agentId","in":"path","required":true,"schema":{"type":"string"}},{"name":"names","in":"query","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"buckets","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":60}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","default":"gauge"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentMetricsResponse"}}}}}}},"/environments/{envSlug}/agents/events":{"get":{"tags":["Agent Events"],"summary":"Query agent events in this environment","description":"Cursor-paginated. Returns newest first. Pass nextCursor back as ?cursor= for the next page.","operationId":"getEvents","parameters":[{"name":"env","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Environment"}},{"name":"appId","in":"query","required":false,"schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"Event page returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AgentEventPageResponse"}}}}}}},"/diagrams/{contentHash}/render":{"get":{"tags":["Diagrams"],"summary":"Render a route diagram by content hash","description":"Returns SVG (default) or JSON layout based on Accept header. Content hashes are globally unique, so this endpoint is intentionally flat (no env).","operationId":"renderDiagram","parameters":[{"name":"contentHash","in":"path","required":true,"schema":{"type":"string"}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","default":"LR"}}],"responses":{"200":{"description":"Diagram rendered successfully","content":{"image/svg+xml":{"schema":{"type":"string"}},"application/json":{"schema":{"$ref":"#/components/schemas/DiagramLayout"}}}},"404":{"description":"Diagram not found","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/catalog":{"get":{"tags":["Catalog"],"summary":"Get unified catalog","description":"Returns all applications (managed + unmanaged) with live agent data, routes, and deployment status","operationId":"getCatalog_1","parameters":[{"name":"environment","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Catalog returned","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CatalogApp"}}}}}}}},"/auth/oidc/config":{"get":{"tags":["Authentication"],"summary":"Get OIDC config for SPA login flow","operationId":"getConfig_2","responses":{"200":{"description":"OIDC configuration","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcPublicConfigResponse"}}}},"404":{"description":"OIDC not configured or disabled","content":{"*/*":{"schema":{"$ref":"#/components/schemas/OidcPublicConfigResponse"}}}},"500":{"description":"Failed to retrieve OIDC provider metadata","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/me":{"get":{"tags":["Authentication"],"summary":"Get current user details","operationId":"me","responses":{"200":{"description":"Current user details","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}},"401":{"description":"Not authenticated","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserDetail"}}}}}}},"/auth/capabilities":{"get":{"tags":["Authentication"],"summary":"Auth capabilities for the SPA login page","operationId":"getCapabilities","responses":{"200":{"description":"Capabilities resolved","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthCapabilitiesResponse"}}}}}}},"/agents/{id}/events":{"get":{"tags":["Agent SSE"],"summary":"Open SSE event stream","description":"Opens a Server-Sent Events stream for the specified agent. Commands (config-update, deep-trace, replay) are pushed as events. Ping keepalive comments sent every 15 seconds.","operationId":"events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Last-Event-ID","in":"header","description":"Last received event ID (no replay, acknowledged only)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream opened","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}},"404":{"description":"Agent not registered and cannot be auto-registered","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/SseEmitter"}}}}}}},"/agents/config":{"get":{"tags":["Agent Config"],"summary":"Get application config for the calling agent","description":"Resolves (application, environment) from the agent's JWT + registry. Prefers the registry entry (heartbeat-authoritative); falls back to the JWT env claim. Returns 404 if neither identifies a valid agent.","operationId":"getConfigForAgent","responses":{"200":{"description":"Config returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppConfigResponse"}}}},"404":{"description":"Calling agent could not be resolved","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AppConfigResponse"}}}}}}},"/admin/usage":{"get":{"tags":["Usage Analytics"],"summary":"Query usage statistics","description":"Returns aggregated API usage stats grouped by endpoint, user, or hour","operationId":"getUsage","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"username","in":"query","required":false,"schema":{"type":"string"}},{"name":"groupBy","in":"query","required":false,"schema":{"type":"string","default":"endpoint"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageStats"}}}}}}}},"/admin/server-metrics/instances":{"get":{"tags":["Server Self-Metrics"],"summary":"List server_instance_id values observed in the window","description":"Returns first/last seen timestamps — use to partition counter-delta computations.","operationId":"instances","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServerInstanceInfo"}}}}}}}},"/admin/server-metrics/catalog":{"get":{"tags":["Server Self-Metrics"],"summary":"List metric names observed in the window","description":"For each metric_name, returns metric_type, the set of statistics emitted, and the union of tag keys.","operationId":"catalog","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServerMetricCatalogEntry"}}}}}}}},"/admin/rbac/stats":{"get":{"tags":["RBAC Stats"],"summary":"Get RBAC statistics for the dashboard","operationId":"getStats","responses":{"200":{"description":"RBAC stats returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RbacStats"}}}}}}},"/admin/outbound-connections/{id}/usage":{"get":{"tags":["Outbound Connections Admin"],"operationId":"usage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}}},"/admin/license/usage":{"get":{"tags":["license-usage-controller"],"operationId":"get_4","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}}}}}},"/admin/database/tables":{"get":{"tags":["Database Admin"],"summary":"Get table sizes and row counts","operationId":"getTables","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TableSizeResponse"}}}}}}}},"/admin/database/status":{"get":{"tags":["Database Admin"],"summary":"Get database connection status and version","operationId":"getStatus","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DatabaseStatusResponse"}}}}}}},"/admin/database/queries":{"get":{"tags":["Database Admin"],"summary":"Get active queries","operationId":"getQueries","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ActiveQueryResponse"}}}}}}}},"/admin/database/pool":{"get":{"tags":["Database Admin"],"summary":"Get HikariCP connection pool stats","operationId":"getPool","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ConnectionPoolResponse"}}}}}}},"/admin/clickhouse/tables":{"get":{"tags":["ClickHouse Admin"],"summary":"List ClickHouse tables with sizes","operationId":"getTables_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClickHouseTableInfo"}}}}}}}},"/admin/clickhouse/status":{"get":{"tags":["ClickHouse Admin"],"summary":"ClickHouse cluster status","operationId":"getStatus_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClickHouseStatusResponse"}}}}}}},"/admin/clickhouse/queries":{"get":{"tags":["ClickHouse Admin"],"summary":"Active ClickHouse queries","operationId":"getQueries_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClickHouseQueryInfo"}}}}}}}},"/admin/clickhouse/performance":{"get":{"tags":["ClickHouse Admin"],"summary":"ClickHouse storage and performance metrics","operationId":"getPerformance","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ClickHousePerformanceResponse"}}}}}}},"/admin/audit":{"get":{"tags":["Audit Log"],"summary":"Search audit log entries with pagination","operationId":"getAuditLog","parameters":[{"name":"username","in":"query","required":false,"schema":{"type":"string"}},{"name":"category","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"timestamp"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","default":"desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":25}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuditLogPageResponse"}}}}}}},"/catalog/{applicationId}":{"delete":{"tags":["Catalog"],"summary":"Dismiss application and purge all data","operationId":"dismissApplication","parameters":[{"name":"applicationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Application dismissed"},"409":{"description":"Cannot dismiss — live agents connected"}}}}},"components":{"schemas":{"Environment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"displayName":{"type":"string"},"production":{"type":"boolean"},"enabled":{"type":"boolean"},"defaultContainerConfig":{"type":"object","additionalProperties":{"type":"object"}},"jarRetentionCount":{"type":"integer","format":"int32"},"color":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"executionRetentionDays":{"type":"integer","format":"int32"},"logRetentionDays":{"type":"integer","format":"int32"},"metricRetentionDays":{"type":"integer","format":"int32"}}},"AppSettingsRequest":{"type":"object","description":"Per-application dashboard settings","properties":{"slaThresholdMs":{"type":"integer","format":"int32","description":"SLA duration threshold in milliseconds","minimum":1},"healthErrorWarn":{"type":"number","format":"double","description":"Error rate % threshold for warning (yellow) health dot","maximum":100,"minimum":0},"healthErrorCrit":{"type":"number","format":"double","description":"Error rate % threshold for critical (red) health dot","maximum":100,"minimum":0},"healthSlaWarn":{"type":"number","format":"double","description":"SLA compliance % threshold for warning (yellow) health dot","maximum":100,"minimum":0},"healthSlaCrit":{"type":"number","format":"double","description":"SLA compliance % threshold for critical (red) health dot","maximum":100,"minimum":0}},"required":["healthErrorCrit","healthErrorWarn","healthSlaCrit","healthSlaWarn","slaThresholdMs"]},"AppSettings":{"type":"object","properties":{"applicationId":{"type":"string"},"environment":{"type":"string"},"slaThresholdMs":{"type":"integer","format":"int32"},"healthErrorWarn":{"type":"number","format":"double"},"healthErrorCrit":{"type":"number","format":"double"},"healthSlaWarn":{"type":"number","format":"double"},"healthSlaCrit":{"type":"number","format":"double"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ApplicationConfig":{"type":"object","properties":{"application":{"type":"string"},"environment":{"type":"string"},"version":{"type":"integer","format":"int32"},"updatedAt":{"type":"string","format":"date-time"},"engineLevel":{"type":"string"},"payloadCaptureMode":{"type":"string"},"metricsEnabled":{"type":"boolean"},"samplingRate":{"type":"number","format":"double"},"tracedProcessors":{"type":"object","additionalProperties":{"type":"string"}},"applicationLogLevel":{"type":"string"},"taps":{"type":"array","items":{"$ref":"#/components/schemas/TapDefinition"}},"tapVersion":{"type":"integer","format":"int32"},"routeRecording":{"type":"object","additionalProperties":{"type":"boolean"}},"compressSuccess":{"type":"boolean"},"agentLogLevel":{"type":"string"},"routeSamplingRates":{"type":"object","additionalProperties":{"type":"number","format":"double"}},"sensitiveKeys":{"type":"array","items":{"type":"string"}},"exportBatchSize":{"type":"integer","format":"int32"},"exportQueueSize":{"type":"integer","format":"int32"},"exportFlushIntervalMs":{"type":"integer","format":"int64"},"exportOverflowMode":{"type":"string"},"exportBlockTimeoutMs":{"type":"integer","format":"int64"},"flushRecordThreshold":{"type":"integer","format":"int32"}}},"TapDefinition":{"type":"object","properties":{"tapId":{"type":"string"},"processorId":{"type":"string"},"target":{"type":"string"},"expression":{"type":"string"},"language":{"type":"string"},"attributeName":{"type":"string"},"attributeType":{"type":"string"},"enabled":{"type":"boolean"},"version":{"type":"integer","format":"int32"}}},"AgentResponse":{"type":"object","properties":{"agentId":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"}}},"CommandGroupResponse":{"type":"object","properties":{"success":{"type":"boolean"},"total":{"type":"integer","format":"int32"},"responded":{"type":"integer","format":"int32"},"responses":{"type":"array","items":{"$ref":"#/components/schemas/AgentResponse"}},"timedOut":{"type":"array","items":{"type":"string"}}}},"ConfigUpdateResponse":{"type":"object","properties":{"config":{"$ref":"#/components/schemas/ApplicationConfig"},"pushResult":{"$ref":"#/components/schemas/CommandGroupResponse"}}},"AlertSilenceRequest":{"type":"object","properties":{"matcher":{"$ref":"#/components/schemas/SilenceMatcher"},"reason":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"}},"required":["endsAt","matcher","startsAt"]},"SilenceMatcher":{"type":"object","properties":{"ruleId":{"type":"string","format":"uuid"},"appSlug":{"type":"string"},"routeId":{"type":"string"},"agentId":{"type":"string"},"severity":{"type":"string","enum":["CRITICAL","WARNING","INFO"]},"wildcard":{"type":"boolean"}}},"AlertSilenceResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"matcher":{"$ref":"#/components/schemas/SilenceMatcher"},"reason":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"AgentLifecycleCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"eventTypes":{"type":"array","items":{"type":"string","enum":["REGISTERED","RE_REGISTERED","DEREGISTERED","WENT_STALE","WENT_DEAD","RECOVERED"]}},"withinSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"AgentStateCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"state":{"type":"string"},"forSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"AlertCondition":{"type":"object","discriminator":{"propertyName":"kind"},"properties":{"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"]}}},"AlertRuleRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1},"description":{"type":"string"},"severity":{"type":"string","enum":["CRITICAL","WARNING","INFO"]},"conditionKind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"]},"condition":{"oneOf":[{"$ref":"#/components/schemas/AgentLifecycleCondition"},{"$ref":"#/components/schemas/AgentStateCondition"},{"$ref":"#/components/schemas/DeploymentStateCondition"},{"$ref":"#/components/schemas/ExchangeMatchCondition"},{"$ref":"#/components/schemas/JvmMetricCondition"},{"$ref":"#/components/schemas/LogPatternCondition"},{"$ref":"#/components/schemas/RouteMetricCondition"}]},"evaluationIntervalSeconds":{"type":"integer","format":"int32"},"forDurationSeconds":{"type":"integer","format":"int32"},"reNotifyMinutes":{"type":"integer","format":"int32"},"notificationTitleTmpl":{"type":"string"},"notificationMessageTmpl":{"type":"string"},"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/WebhookBindingRequest"}},"targets":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleTarget"}}},"required":["condition","conditionKind","severity"]},"AlertRuleTarget":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ruleId":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["USER","GROUP","ROLE"]},"targetId":{"type":"string"}}},"AlertScope":{"type":"object","properties":{"appSlug":{"type":"string"},"routeId":{"type":"string"},"agentId":{"type":"string"}}},"DeploymentStateCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"states":{"type":"array","items":{"type":"string"}},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"ExchangeFilter":{"type":"object","properties":{"status":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}}}},"ExchangeMatchCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"filter":{"$ref":"#/components/schemas/ExchangeFilter"},"fireMode":{"type":"string","enum":["PER_EXCHANGE","COUNT_IN_WINDOW"]},"threshold":{"type":"integer","format":"int32"},"windowSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"JvmMetricCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"metric":{"type":"string"},"aggregation":{"type":"string","enum":["MAX","MIN","AVG","LATEST"]},"comparator":{"type":"string","enum":["GT","GTE","LT","LTE","EQ"]},"threshold":{"type":"number","format":"double"},"windowSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"LogPatternCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"level":{"type":"string"},"pattern":{"type":"string"},"threshold":{"type":"integer","format":"int32"},"windowSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"RouteMetricCondition":{"allOf":[{"$ref":"#/components/schemas/AlertCondition"},{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AlertScope"},"metric":{"type":"string","enum":["ERROR_RATE","AVG_DURATION_MS","P99_LATENCY_MS","THROUGHPUT","ERROR_COUNT"]},"comparator":{"type":"string","enum":["GT","GTE","LT","LTE","EQ"]},"threshold":{"type":"number","format":"double"},"windowSeconds":{"type":"integer","format":"int32"},"kind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"],"readOnly":true}}}]},"WebhookBindingRequest":{"type":"object","properties":{"outboundConnectionId":{"type":"string","format":"uuid"},"bodyOverride":{"type":"string"},"headerOverrides":{"type":"object","additionalProperties":{"type":"string"}}},"required":["outboundConnectionId"]},"AlertRuleResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"severity":{"type":"string","enum":["CRITICAL","WARNING","INFO"]},"enabled":{"type":"boolean"},"conditionKind":{"type":"string","enum":["ROUTE_METRIC","EXCHANGE_MATCH","AGENT_STATE","AGENT_LIFECYCLE","DEPLOYMENT_STATE","LOG_PATTERN","JVM_METRIC"]},"condition":{"oneOf":[{"$ref":"#/components/schemas/AgentLifecycleCondition"},{"$ref":"#/components/schemas/AgentStateCondition"},{"$ref":"#/components/schemas/DeploymentStateCondition"},{"$ref":"#/components/schemas/ExchangeMatchCondition"},{"$ref":"#/components/schemas/JvmMetricCondition"},{"$ref":"#/components/schemas/LogPatternCondition"},{"$ref":"#/components/schemas/RouteMetricCondition"}]},"evaluationIntervalSeconds":{"type":"integer","format":"int32"},"forDurationSeconds":{"type":"integer","format":"int32"},"reNotifyMinutes":{"type":"integer","format":"int32"},"notificationTitleTmpl":{"type":"string"},"notificationMessageTmpl":{"type":"string"},"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/WebhookBindingResponse"}},"targets":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleTarget"}},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"}}},"WebhookBindingResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"outboundConnectionId":{"type":"string","format":"uuid"},"bodyOverride":{"type":"string"},"headerOverrides":{"type":"object","additionalProperties":{"type":"string"}}}},"UpdateUserRequest":{"type":"object","properties":{"displayName":{"type":"string"},"email":{"type":"string"}}},"DatabaseThresholdsRequest":{"type":"object","description":"Database monitoring thresholds","properties":{"connectionPoolWarning":{"type":"integer","format":"int32","description":"Connection pool usage warning threshold (percentage)","maximum":100,"minimum":0},"connectionPoolCritical":{"type":"integer","format":"int32","description":"Connection pool usage critical threshold (percentage)","maximum":100,"minimum":0},"queryDurationWarning":{"type":"number","format":"double","description":"Query duration warning threshold (seconds)"},"queryDurationCritical":{"type":"number","format":"double","description":"Query duration critical threshold (seconds)"}}},"ThresholdConfigRequest":{"type":"object","description":"Threshold configuration for admin monitoring","properties":{"database":{"$ref":"#/components/schemas/DatabaseThresholdsRequest"}},"required":["database"]},"DatabaseThresholds":{"type":"object","properties":{"connectionPoolWarning":{"type":"integer","format":"int32"},"connectionPoolCritical":{"type":"integer","format":"int32"},"queryDurationWarning":{"type":"number","format":"double"},"queryDurationCritical":{"type":"number","format":"double"}}},"ThresholdConfig":{"type":"object","properties":{"database":{"$ref":"#/components/schemas/DatabaseThresholds"}}},"SensitiveKeysRequest":{"type":"object","description":"Global sensitive keys configuration","properties":{"keys":{"type":"array","description":"List of key names or glob patterns to mask","items":{"type":"string"}}},"required":["keys"]},"SensitiveKeysResponse":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"string"}},"pushResult":{"$ref":"#/components/schemas/CommandGroupResponse"}}},"UpdateRoleRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"scope":{"type":"string"}}},"Basic":{"allOf":[{"$ref":"#/components/schemas/OutboundAuth"},{"type":"object","properties":{"username":{"type":"string"},"passwordCiphertext":{"type":"string"}}}]},"Bearer":{"allOf":[{"$ref":"#/components/schemas/OutboundAuth"},{"type":"object","properties":{"tokenCiphertext":{"type":"string"}}}]},"None":{"allOf":[{"$ref":"#/components/schemas/OutboundAuth"}]},"OutboundAuth":{"type":"object"},"OutboundConnectionRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"minLength":0},"description":{"type":"string","maxLength":2000,"minLength":0},"url":{"type":"string","minLength":1,"pattern":"^https://.+"},"method":{"type":"string","enum":["POST","PUT","PATCH"]},"defaultHeaders":{"type":"object","additionalProperties":{"type":"string"}},"defaultBodyTmpl":{"type":"string"},"tlsTrustMode":{"type":"string","enum":["SYSTEM_DEFAULT","TRUST_ALL","TRUST_PATHS"]},"tlsCaPemPaths":{"type":"array","items":{"type":"string"}},"hmacSecret":{"type":"string"},"auth":{"oneOf":[{"$ref":"#/components/schemas/Basic"},{"$ref":"#/components/schemas/Bearer"},{"$ref":"#/components/schemas/None"}]},"allowedEnvironmentIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["auth","method","tlsTrustMode"]},"OutboundConnectionDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"url":{"type":"string"},"method":{"type":"string","enum":["POST","PUT","PATCH"]},"defaultHeaders":{"type":"object","additionalProperties":{"type":"string"}},"defaultBodyTmpl":{"type":"string"},"tlsTrustMode":{"type":"string","enum":["SYSTEM_DEFAULT","TRUST_ALL","TRUST_PATHS"]},"tlsCaPemPaths":{"type":"array","items":{"type":"string"}},"hmacSecretSet":{"type":"boolean"},"authKind":{"type":"string","enum":["NONE","BEARER","BASIC"]},"allowedEnvironmentIds":{"type":"array","items":{"type":"string","format":"uuid"}},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"}}},"OidcAdminConfigRequest":{"type":"object","description":"OIDC configuration update request","properties":{"enabled":{"type":"boolean"},"issuerUri":{"type":"string"},"clientId":{"type":"string"},"clientSecret":{"type":"string"},"rolesClaim":{"type":"string"},"defaultRoles":{"type":"array","items":{"type":"string"}},"autoSignup":{"type":"boolean"},"displayNameClaim":{"type":"string"},"userIdClaim":{"type":"string"},"audience":{"type":"string"},"additionalScopes":{"type":"array","items":{"type":"string"}}}},"ErrorResponse":{"type":"object","description":"Error response","properties":{"message":{"type":"string"}},"required":["message"]},"OidcAdminConfigResponse":{"type":"object","description":"OIDC configuration for admin management","properties":{"configured":{"type":"boolean"},"enabled":{"type":"boolean"},"issuerUri":{"type":"string"},"clientId":{"type":"string"},"clientSecretSet":{"type":"boolean"},"rolesClaim":{"type":"string"},"defaultRoles":{"type":"array","items":{"type":"string"}},"autoSignup":{"type":"boolean"},"displayNameClaim":{"type":"string"},"userIdClaim":{"type":"string"},"audience":{"type":"string"},"additionalScopes":{"type":"array","items":{"type":"string"}}}},"UpdateGroupRequest":{"type":"object","properties":{"name":{"type":"string"},"parentGroupId":{"type":"string","format":"uuid"}}},"UpdateEnvironmentRequest":{"type":"object","properties":{"displayName":{"type":"string"},"production":{"type":"boolean"},"enabled":{"type":"boolean"},"color":{"type":"string"}}},"JarRetentionRequest":{"type":"object","properties":{"jarRetentionCount":{"type":"integer","format":"int32"}}},"CreateRuleRequest":{"type":"object","properties":{"claim":{"type":"string"},"matchType":{"type":"string"},"matchValue":{"type":"string"},"action":{"type":"string"},"target":{"type":"string"},"priority":{"type":"integer","format":"int32"}}},"ClaimMappingRule":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"claim":{"type":"string"},"matchType":{"type":"string"},"matchValue":{"type":"string"},"action":{"type":"string"},"target":{"type":"string"},"priority":{"type":"integer","format":"int32"},"createdAt":{"type":"string","format":"date-time"}}},"AttributeFilter":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"},"keyOnly":{"type":"boolean"},"wildcard":{"type":"boolean"}}},"SearchRequest":{"type":"object","properties":{"status":{"type":"string"},"timeFrom":{"type":"string","format":"date-time"},"timeTo":{"type":"string","format":"date-time"},"durationMin":{"type":"integer","format":"int64"},"durationMax":{"type":"integer","format":"int64"},"correlationId":{"type":"string"},"text":{"type":"string"},"textInBody":{"type":"string"},"textInHeaders":{"type":"string"},"textInErrors":{"type":"string"},"routeId":{"type":"string"},"instanceId":{"type":"string"},"processorType":{"type":"string"},"applicationId":{"type":"string"},"instanceIds":{"type":"array","items":{"type":"string"}},"offset":{"type":"integer","format":"int32"},"limit":{"type":"integer","format":"int32"},"sortField":{"type":"string"},"sortDir":{"type":"string"},"afterExecutionId":{"type":"string"},"environment":{"type":"string"},"attributeFilters":{"type":"array","items":{"$ref":"#/components/schemas/AttributeFilter"}}}},"ExecutionSummary":{"type":"object","properties":{"executionId":{"type":"string"},"routeId":{"type":"string"},"instanceId":{"type":"string"},"applicationId":{"type":"string"},"status":{"type":"string"},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"},"correlationId":{"type":"string"},"errorMessage":{"type":"string"},"diagramContentHash":{"type":"string"},"highlight":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}},"hasTraceData":{"type":"boolean"},"isReplay":{"type":"boolean"}},"required":["applicationId","attributes","correlationId","diagramContentHash","durationMs","endTime","errorMessage","executionId","hasTraceData","highlight","instanceId","isReplay","routeId","startTime","status"]},"SearchResultExecutionSummary":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExecutionSummary"}},"total":{"type":"integer","format":"int64"},"offset":{"type":"integer","format":"int32"},"limit":{"type":"integer","format":"int32"}},"required":["data","limit","offset","total"]},"CreateAppRequest":{"type":"object","properties":{"slug":{"type":"string"},"displayName":{"type":"string"}}},"AppVersion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"version":{"type":"integer","format":"int32"},"jarPath":{"type":"string"},"jarChecksum":{"type":"string"},"jarFilename":{"type":"string"},"jarSizeBytes":{"type":"integer","format":"int64"},"detectedRuntimeType":{"type":"string"},"detectedMainClass":{"type":"string"},"uploadedAt":{"type":"string","format":"date-time"}}},"DeployRequest":{"type":"object","properties":{"appVersionId":{"type":"string","format":"uuid"}}},"Deployment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"appVersionId":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["STOPPED","STARTING","RUNNING","DEGRADED","STOPPING","FAILED"]},"targetState":{"type":"string"},"deploymentStrategy":{"type":"string"},"replicaStates":{"type":"array","items":{"type":"object","additionalProperties":{"type":"object"}}},"deployStage":{"type":"string"},"containerId":{"type":"string"},"containerName":{"type":"string"},"errorMessage":{"type":"string"},"resolvedConfig":{"type":"object","additionalProperties":{"type":"object"}},"deployedConfigSnapshot":{"$ref":"#/components/schemas/DeploymentConfigSnapshot"},"deployedAt":{"type":"string","format":"date-time"},"stoppedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"DeploymentConfigSnapshot":{"type":"object","properties":{"jarVersionId":{"type":"string","format":"uuid"},"agentConfig":{"$ref":"#/components/schemas/ApplicationConfig"},"containerConfig":{"type":"object","additionalProperties":{"type":"object"}},"sensitiveKeys":{"type":"array","items":{"type":"string"}}}},"PromoteRequest":{"type":"object","properties":{"targetEnvironment":{"type":"string"}}},"TestExpressionRequest":{"type":"object","properties":{"expression":{"type":"string"},"language":{"type":"string"},"body":{"type":"string"},"target":{"type":"string"}}},"TestExpressionResponse":{"type":"object","properties":{"result":{"type":"string"},"error":{"type":"string"}}},"AlertDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ruleId":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["PENDING","FIRING","RESOLVED"]},"severity":{"type":"string","enum":["CRITICAL","WARNING","INFO"]},"title":{"type":"string"},"message":{"type":"string"},"firedAt":{"type":"string","format":"date-time"},"ackedAt":{"type":"string","format":"date-time"},"ackedBy":{"type":"string"},"resolvedAt":{"type":"string","format":"date-time"},"readAt":{"type":"string","format":"date-time"},"silenced":{"type":"boolean"},"currentValue":{"type":"number","format":"double"},"threshold":{"type":"number","format":"double"},"context":{"type":"object","additionalProperties":{"type":"object"}}}},"TestEvaluateRequest":{"type":"object"},"TestEvaluateResponse":{"type":"object","properties":{"resultKind":{"type":"string"},"detail":{"type":"string"}}},"RenderPreviewRequest":{"type":"object","properties":{"context":{"type":"object","additionalProperties":{"type":"object"}}}},"RenderPreviewResponse":{"type":"object","properties":{"title":{"type":"string"},"message":{"type":"string"}}},"BulkIdsRequest":{"type":"object","properties":{"instanceIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"minItems":1}},"required":["instanceIds"]},"LogEntry":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"level":{"type":"string"},"loggerName":{"type":"string"},"message":{"type":"string"},"threadName":{"type":"string"},"stackTrace":{"type":"string"},"mdc":{"type":"object","additionalProperties":{"type":"string"}},"source":{"type":"string"}}},"RefreshRequest":{"type":"object","properties":{"refreshToken":{"type":"string"}}},"AuthTokenResponse":{"type":"object","description":"JWT token pair","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"displayName":{"type":"string"},"idToken":{"type":"string","description":"OIDC id_token for end-session logout (only present after OIDC login)"}},"required":["accessToken","displayName","refreshToken"]},"CallbackRequest":{"type":"object","properties":{"code":{"type":"string"},"redirectUri":{"type":"string"}}},"LoginRequest":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}}},"AlertNotificationDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"alertInstanceId":{"type":"string","format":"uuid"},"webhookId":{"type":"string","format":"uuid"},"outboundConnectionId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["PENDING","DELIVERED","FAILED"]},"attempts":{"type":"integer","format":"int32"},"nextAttemptAt":{"type":"string","format":"date-time"},"lastResponseStatus":{"type":"integer","format":"int32"},"lastResponseSnippet":{"type":"string"},"deliveredAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"ReplayRequest":{"type":"object","description":"Request to replay an exchange on an agent","properties":{"routeId":{"type":"string","description":"Camel route ID to replay on"},"body":{"type":"string","description":"Message body for the replayed exchange"},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Message headers for the replayed exchange"},"originalExchangeId":{"type":"string","description":"Exchange ID of the original execution being replayed (for audit trail)"}},"required":["routeId"]},"ReplayResponse":{"type":"object","description":"Result of a replay command","properties":{"status":{"type":"string","description":"Replay outcome: SUCCESS or FAILURE"},"message":{"type":"string","description":"Human-readable result message"},"data":{"type":"string","description":"Structured result data from the agent (JSON)"}}},"AgentRefreshRequest":{"type":"object","description":"Agent token refresh request","properties":{"refreshToken":{"type":"string"}},"required":["refreshToken"]},"AgentRefreshResponse":{"type":"object","description":"Refreshed access and refresh tokens","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"}},"required":["accessToken","refreshToken"]},"HeartbeatRequest":{"type":"object","properties":{"routeStates":{"type":"object","additionalProperties":{"type":"string"}},"capabilities":{"type":"object","additionalProperties":{"type":"object"}},"environmentId":{"type":"string"}}},"CommandRequest":{"type":"object","description":"Command to send to agent(s)","properties":{"type":{"type":"string","description":"Command type: config-update, deep-trace, or replay"},"payload":{"type":"object","description":"Command payload JSON"}},"required":["type"]},"CommandSingleResponse":{"type":"object","description":"Result of sending a command to a single agent","properties":{"commandId":{"type":"string"},"status":{"type":"string"}},"required":["commandId","status"]},"CommandAckRequest":{"type":"object","properties":{"status":{"type":"string"},"message":{"type":"string"},"data":{"type":"string"}}},"AgentRegistrationRequest":{"type":"object","description":"Agent registration payload","properties":{"instanceId":{"type":"string"},"applicationId":{"type":"string","default":"default"},"environmentId":{"type":"string","default":"default"},"version":{"type":"string"},"routeIds":{"type":"array","items":{"type":"string"}},"capabilities":{"type":"object","additionalProperties":{"type":"object"}}},"required":["instanceId"]},"AgentRegistrationResponse":{"type":"object","description":"Agent registration result with JWT tokens and SSE endpoint","properties":{"instanceId":{"type":"string"},"sseEndpoint":{"type":"string"},"heartbeatIntervalMs":{"type":"integer","format":"int64"},"serverPublicKey":{"type":"string"},"accessToken":{"type":"string"},"refreshToken":{"type":"string"}},"required":["accessToken","instanceId","refreshToken","serverPublicKey","sseEndpoint"]},"CommandBroadcastResponse":{"type":"object","description":"Result of broadcasting a command to multiple agents","properties":{"commandIds":{"type":"array","items":{"type":"string"}},"targetCount":{"type":"integer","format":"int32"}},"required":["commandIds"]},"CreateUserRequest":{"type":"object","properties":{"username":{"type":"string"},"displayName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"}}},"SetPasswordRequest":{"type":"object","properties":{"password":{"type":"string","minLength":1}}},"QueryBody":{"type":"object","properties":{"metric":{"type":"string"},"statistic":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"stepSeconds":{"type":"integer","format":"int32"},"groupByTags":{"type":"array","items":{"type":"string"}},"filterTags":{"type":"object","additionalProperties":{"type":"string"}},"aggregation":{"type":"string"},"mode":{"type":"string"},"serverInstanceIds":{"type":"array","items":{"type":"string"}}}},"ServerMetricPoint":{"type":"object","properties":{"t":{"type":"string","format":"date-time"},"v":{"type":"number","format":"double"}}},"ServerMetricQueryResponse":{"type":"object","properties":{"metric":{"type":"string"},"statistic":{"type":"string"},"aggregation":{"type":"string"},"mode":{"type":"string"},"stepSeconds":{"type":"integer","format":"int32"},"series":{"type":"array","items":{"$ref":"#/components/schemas/ServerMetricSeries"}}}},"ServerMetricSeries":{"type":"object","properties":{"tags":{"type":"object","additionalProperties":{"type":"string"}},"points":{"type":"array","items":{"$ref":"#/components/schemas/ServerMetricPoint"}}}},"CreateRoleRequest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"scope":{"type":"string"}}},"OutboundConnectionTestResult":{"type":"object","properties":{"status":{"type":"integer","format":"int32"},"latencyMs":{"type":"integer","format":"int64"},"responseSnippet":{"type":"string"},"tlsProtocol":{"type":"string"},"tlsCipherSuite":{"type":"string"},"peerCertificateSubject":{"type":"string"},"peerCertificateExpiresAtEpochMs":{"type":"integer","format":"int64"},"error":{"type":"string"}}},"OidcTestResult":{"type":"object","description":"OIDC provider connectivity test result","properties":{"status":{"type":"string"},"authorizationEndpoint":{"type":"string"}},"required":["authorizationEndpoint","status"]},"UpdateLicenseRequest":{"type":"object","properties":{"token":{"type":"string"}}},"CreateGroupRequest":{"type":"object","properties":{"name":{"type":"string"},"parentGroupId":{"type":"string","format":"uuid"}}},"CreateEnvironmentRequest":{"type":"object","properties":{"slug":{"type":"string"},"displayName":{"type":"string"},"production":{"type":"boolean"}}},"TestRequest":{"type":"object","properties":{"rules":{"type":"array","items":{"$ref":"#/components/schemas/TestRuleRequest"}},"claims":{"type":"object","additionalProperties":{"type":"object"}}}},"TestRuleRequest":{"type":"object","properties":{"id":{"type":"string"},"claim":{"type":"string"},"matchType":{"type":"string"},"matchValue":{"type":"string"},"action":{"type":"string"},"target":{"type":"string"},"priority":{"type":"integer","format":"int32"}}},"MatchedRuleResponse":{"type":"object","properties":{"ruleId":{"type":"string"},"priority":{"type":"integer","format":"int32"},"claim":{"type":"string"},"matchType":{"type":"string"},"matchValue":{"type":"string"},"action":{"type":"string"},"target":{"type":"string"}}},"TestResponse":{"type":"object","properties":{"matchedRules":{"type":"array","items":{"$ref":"#/components/schemas/MatchedRuleResponse"}},"effectiveRoles":{"type":"array","items":{"type":"string"}},"effectiveGroups":{"type":"array","items":{"type":"string"}},"fallback":{"type":"boolean"}}},"ExecutionDetail":{"type":"object","properties":{"executionId":{"type":"string"},"routeId":{"type":"string"},"instanceId":{"type":"string"},"applicationId":{"type":"string"},"environment":{"type":"string"},"status":{"type":"string"},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"},"correlationId":{"type":"string"},"exchangeId":{"type":"string"},"errorMessage":{"type":"string"},"errorStackTrace":{"type":"string"},"diagramContentHash":{"type":"string"},"processors":{"type":"array","items":{"$ref":"#/components/schemas/ProcessorNode"}},"inputBody":{"type":"string"},"outputBody":{"type":"string"},"inputHeaders":{"type":"string"},"outputHeaders":{"type":"string"},"inputProperties":{"type":"string"},"outputProperties":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}},"errorType":{"type":"string"},"errorCategory":{"type":"string"},"rootCauseType":{"type":"string"},"rootCauseMessage":{"type":"string"},"traceId":{"type":"string"},"spanId":{"type":"string"}},"required":["applicationId","attributes","correlationId","diagramContentHash","durationMs","endTime","environment","errorCategory","errorMessage","errorStackTrace","errorType","exchangeId","executionId","inputBody","inputHeaders","inputProperties","instanceId","outputBody","outputHeaders","outputProperties","processors","rootCauseMessage","rootCauseType","routeId","spanId","startTime","status","traceId"]},"ProcessorNode":{"type":"object","properties":{"processorId":{"type":"string"},"processorType":{"type":"string"},"status":{"type":"string"},"startTime":{"type":"string","format":"date-time"},"endTime":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"},"errorMessage":{"type":"string"},"errorStackTrace":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"type":"string"}},"iteration":{"type":"integer","format":"int32"},"iterationSize":{"type":"integer","format":"int32"},"loopIndex":{"type":"integer","format":"int32"},"loopSize":{"type":"integer","format":"int32"},"splitIndex":{"type":"integer","format":"int32"},"splitSize":{"type":"integer","format":"int32"},"multicastIndex":{"type":"integer","format":"int32"},"resolvedEndpointUri":{"type":"string"},"errorType":{"type":"string"},"errorCategory":{"type":"string"},"rootCauseType":{"type":"string"},"rootCauseMessage":{"type":"string"},"errorHandlerType":{"type":"string"},"circuitBreakerState":{"type":"string"},"fallbackTriggered":{"type":"boolean"},"filterMatched":{"type":"boolean"},"duplicateMessage":{"type":"boolean"},"hasTraceData":{"type":"boolean"},"children":{"type":"array","items":{"$ref":"#/components/schemas/ProcessorNode"}}},"required":["attributes","children","circuitBreakerState","duplicateMessage","durationMs","endTime","errorCategory","errorHandlerType","errorMessage","errorStackTrace","errorType","fallbackTriggered","filterMatched","hasTraceData","iteration","iterationSize","loopIndex","loopSize","multicastIndex","processorId","processorType","resolvedEndpointUri","rootCauseMessage","rootCauseType","splitIndex","splitSize","startTime","status"]},"ExecutionStats":{"type":"object","properties":{"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"integer","format":"int64"},"p99LatencyMs":{"type":"integer","format":"int64"},"activeCount":{"type":"integer","format":"int64"},"totalToday":{"type":"integer","format":"int64"},"prevTotalCount":{"type":"integer","format":"int64"},"prevFailedCount":{"type":"integer","format":"int64"},"prevAvgDurationMs":{"type":"integer","format":"int64"},"prevP99LatencyMs":{"type":"integer","format":"int64"},"slaCompliance":{"type":"number","format":"double"}},"required":["activeCount","avgDurationMs","failedCount","p99LatencyMs","prevAvgDurationMs","prevFailedCount","prevP99LatencyMs","prevTotalCount","slaCompliance","totalCount","totalToday"]},"StatsTimeseries":{"type":"object","properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}},"required":["buckets"]},"TimeseriesBucket":{"type":"object","properties":{"time":{"type":"string","format":"date-time"},"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"integer","format":"int64"},"p99DurationMs":{"type":"integer","format":"int64"},"activeCount":{"type":"integer","format":"int64"}},"required":["activeCount","avgDurationMs","failedCount","p99DurationMs","time","totalCount"]},"PunchcardCell":{"type":"object","properties":{"weekday":{"type":"integer","format":"int32"},"hour":{"type":"integer","format":"int32"},"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"}}},"AgentSummary":{"type":"object","description":"Summary of an agent instance for sidebar display","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"tps":{"type":"number","format":"double"}},"required":["id","name","status","tps"]},"AppCatalogEntry":{"type":"object","description":"Application catalog entry with routes and agents","properties":{"appId":{"type":"string"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/RouteSummary"}},"agents":{"type":"array","items":{"$ref":"#/components/schemas/AgentSummary"}},"agentCount":{"type":"integer","format":"int32"},"health":{"type":"string"},"exchangeCount":{"type":"integer","format":"int64"}},"required":["agentCount","agents","appId","exchangeCount","health","routes"]},"RouteSummary":{"type":"object","description":"Summary of a route within an application","properties":{"routeId":{"type":"string"},"exchangeCount":{"type":"integer","format":"int64"},"lastSeen":{"type":"string","format":"date-time"},"fromEndpointUri":{"type":"string","description":"The from() endpoint URI, e.g. 'direct:processOrder'"},"routeState":{"type":"string","description":"Operational state of the route: stopped, suspended, or null (started/default)"}},"required":["exchangeCount","fromEndpointUri","lastSeen","routeId","routeState"]},"RouteMetrics":{"type":"object","description":"Aggregated route performance metrics","properties":{"routeId":{"type":"string"},"appId":{"type":"string"},"exchangeCount":{"type":"integer","format":"int64"},"successRate":{"type":"number","format":"double"},"avgDurationMs":{"type":"number","format":"double"},"p99DurationMs":{"type":"number","format":"double"},"errorRate":{"type":"number","format":"double"},"throughputPerSec":{"type":"number","format":"double"},"sparkline":{"type":"array","items":{"type":"number","format":"double"}},"slaCompliance":{"type":"number","format":"double"}},"required":["appId","avgDurationMs","errorRate","exchangeCount","p99DurationMs","routeId","slaCompliance","sparkline","successRate","throughputPerSec"]},"ProcessorMetrics":{"type":"object","properties":{"processorId":{"type":"string"},"processorType":{"type":"string"},"routeId":{"type":"string"},"appId":{"type":"string"},"totalCount":{"type":"integer","format":"int64"},"failedCount":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"number","format":"double"},"p99DurationMs":{"type":"number","format":"double"},"errorRate":{"type":"number","format":"double"}},"required":["appId","avgDurationMs","errorRate","failedCount","p99DurationMs","processorId","processorType","routeId","totalCount"]},"LogEntryResponse":{"type":"object","description":"Application log entry","properties":{"timestamp":{"type":"string","description":"Log timestamp (ISO-8601)"},"level":{"type":"string","description":"Log level (INFO, WARN, ERROR, DEBUG, TRACE)"},"loggerName":{"type":"string","description":"Logger name"},"message":{"type":"string","description":"Log message"},"threadName":{"type":"string","description":"Thread name"},"stackTrace":{"type":"string","description":"Stack trace (if present)"},"exchangeId":{"type":"string","description":"Camel exchange ID (if present)"},"instanceId":{"type":"string","description":"Agent instance ID"},"application":{"type":"string","description":"Application ID"},"mdc":{"type":"object","additionalProperties":{"type":"string"},"description":"MDC context map"},"source":{"type":"string","description":"Log source: app or agent"}}},"LogSearchPageResponse":{"type":"object","description":"Log search response with cursor pagination and level counts","properties":{"data":{"type":"array","description":"Log entries for the current page","items":{"$ref":"#/components/schemas/LogEntryResponse"}},"nextCursor":{"type":"string","description":"Cursor for next page (null if no more results)"},"hasMore":{"type":"boolean","description":"Whether more results exist beyond this page"},"levelCounts":{"type":"object","additionalProperties":{"type":"integer","format":"int64"},"description":"Count of logs per level (unaffected by level filter)"}}},"TopError":{"type":"object","properties":{"errorType":{"type":"string"},"routeId":{"type":"string"},"processorId":{"type":"string"},"count":{"type":"integer","format":"int64"},"velocity":{"type":"number","format":"double"},"trend":{"type":"string"},"lastSeen":{"type":"string","format":"date-time"}}},"App":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"environmentId":{"type":"string","format":"uuid"},"slug":{"type":"string"},"displayName":{"type":"string"},"containerConfig":{"type":"object","additionalProperties":{"type":"object"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"DiagramLayout":{"type":"object","properties":{"width":{"type":"number","format":"double"},"height":{"type":"number","format":"double"},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/PositionedNode"}},"edges":{"type":"array","items":{"$ref":"#/components/schemas/PositionedEdge"}}}},"PositionedEdge":{"type":"object","properties":{"sourceId":{"type":"string"},"targetId":{"type":"string"},"label":{"type":"string"},"points":{"type":"array","items":{"type":"array","items":{"type":"number","format":"double"}}}}},"PositionedNode":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"type":{"type":"string"},"x":{"type":"number","format":"double"},"y":{"type":"number","format":"double"},"width":{"type":"number","format":"double"},"height":{"type":"number","format":"double"},"endpointUri":{"type":"string"}}},"Difference":{"type":"object","properties":{"field":{"type":"string"},"staged":{"type":"string"},"deployed":{"type":"string"}}},"DirtyStateResponse":{"type":"object","properties":{"dirty":{"type":"boolean"},"lastSuccessfulDeploymentId":{"type":"string"},"differences":{"type":"array","items":{"$ref":"#/components/schemas/Difference"}}}},"AppConfigResponse":{"type":"object","properties":{"config":{"$ref":"#/components/schemas/ApplicationConfig"},"globalSensitiveKeys":{"type":"array","items":{"type":"string"}},"mergedSensitiveKeys":{"type":"array","items":{"type":"string"}}}},"UnreadCountResponse":{"type":"object","properties":{"total":{"type":"integer","format":"int64"},"bySeverity":{"type":"object","additionalProperties":{"type":"integer","format":"int64"}}}},"AgentInstanceResponse":{"type":"object","description":"Agent instance summary with runtime metrics","properties":{"instanceId":{"type":"string"},"displayName":{"type":"string"},"applicationId":{"type":"string"},"environmentId":{"type":"string"},"status":{"type":"string"},"routeIds":{"type":"array","items":{"type":"string"}},"registeredAt":{"type":"string","format":"date-time"},"lastHeartbeat":{"type":"string","format":"date-time"},"version":{"type":"string"},"capabilities":{"type":"object","additionalProperties":{"type":"object"}},"tps":{"type":"number","format":"double"},"errorRate":{"type":"number","format":"double"},"activeRoutes":{"type":"integer","format":"int32"},"totalRoutes":{"type":"integer","format":"int32"},"uptimeSeconds":{"type":"integer","format":"int64"},"cpuUsage":{"type":"number","format":"double","description":"Recent average CPU usage (0.0–1.0), -1 if unavailable"}},"required":["activeRoutes","applicationId","capabilities","cpuUsage","displayName","environmentId","errorRate","instanceId","lastHeartbeat","registeredAt","routeIds","status","totalRoutes","tps","uptimeSeconds","version"]},"AgentMetricsResponse":{"type":"object","properties":{"metrics":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"required":["metrics"]},"MetricBucket":{"type":"object","properties":{"time":{"type":"string","format":"date-time"},"value":{"type":"number","format":"double"}},"required":["time","value"]},"AgentEventPageResponse":{"type":"object","description":"Cursor-paginated agent event list","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AgentEventResponse"}},"nextCursor":{"type":"string"},"hasMore":{"type":"boolean"}}},"AgentEventResponse":{"type":"object","description":"Agent lifecycle event","properties":{"id":{"type":"integer","format":"int64"},"instanceId":{"type":"string"},"applicationId":{"type":"string"},"eventType":{"type":"string"},"detail":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}},"required":["applicationId","detail","eventType","id","instanceId","timestamp"]},"CatalogApp":{"type":"object","description":"Unified catalog entry combining app records with live agent data","properties":{"slug":{"type":"string","description":"Application slug (universal identifier)"},"displayName":{"type":"string","description":"Display name"},"managed":{"type":"boolean","description":"True if a managed App record exists in the database"},"environmentSlug":{"type":"string","description":"Environment slug"},"health":{"type":"string","description":"Composite health: deployment status + agent health"},"healthTooltip":{"type":"string","description":"Human-readable tooltip explaining the health state"},"agentCount":{"type":"integer","format":"int32","description":"Number of connected agents"},"routes":{"type":"array","description":"Live routes from agents","items":{"$ref":"#/components/schemas/RouteSummary"}},"agents":{"type":"array","description":"Connected agent summaries","items":{"$ref":"#/components/schemas/AgentSummary"}},"exchangeCount":{"type":"integer","format":"int64","description":"Total exchange count from ClickHouse"},"deployment":{"$ref":"#/components/schemas/DeploymentSummary","description":"Active deployment info, null if no deployment"}}},"DeploymentSummary":{"type":"object","properties":{"status":{"type":"string"},"replicas":{"type":"string"},"version":{"type":"integer","format":"int32"}}},"OidcPublicConfigResponse":{"type":"object","description":"OIDC configuration for SPA login flow","properties":{"issuer":{"type":"string"},"clientId":{"type":"string"},"authorizationEndpoint":{"type":"string"},"endSessionEndpoint":{"type":"string","description":"Present if the provider supports RP-initiated logout"},"resource":{"type":"string","description":"RFC 8707 resource indicator for the authorization request"},"additionalScopes":{"type":"array","description":"Additional scopes to request beyond openid email profile","items":{"type":"string"}}},"required":["authorizationEndpoint","clientId","issuer"]},"GroupSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"RoleSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"system":{"type":"boolean"},"source":{"type":"string"}}},"UserDetail":{"type":"object","properties":{"userId":{"type":"string"},"provider":{"type":"string"},"email":{"type":"string"},"displayName":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"directRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"directGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}},"effectiveRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"effectiveGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}}}},"AuthCapabilitiesResponse":{"type":"object","description":"Authentication capabilities reported to the SPA so it can render the login page deterministically","properties":{"oidc":{"$ref":"#/components/schemas/Oidc","description":"OIDC interactive login capability"},"localAccounts":{"$ref":"#/components/schemas/LocalAccounts","description":"Local username/password account capability"}}},"LocalAccounts":{"type":"object","description":"Local username/password accounts","properties":{"enabled":{"type":"boolean","description":"Whether the local form is reachable at all"},"adminRecoveryOnly":{"type":"boolean","description":"When true, the SPA gates the local form behind ?local with an admin-recovery banner"}}},"Oidc":{"type":"object","description":"OIDC interactive login","properties":{"enabled":{"type":"boolean","description":"Whether OIDC is configured AND enabled"},"providerName":{"type":"string","description":"Best-effort display label, e.g. \"Logto\", \"Keycloak\", \"Single Sign-On\""},"primary":{"type":"boolean","description":"When true, OIDC is the canonical entry point and the SPA hides the local form unless ?local is set"}},"required":["providerName"]},"SseEmitter":{"type":"object","properties":{"timeout":{"type":"integer","format":"int64"}}},"UsageStats":{"type":"object","properties":{"key":{"type":"string"},"count":{"type":"integer","format":"int64"},"avgDurationMs":{"type":"integer","format":"int64"}}},"ServerInstanceInfo":{"type":"object","properties":{"serverInstanceId":{"type":"string"},"firstSeen":{"type":"string","format":"date-time"},"lastSeen":{"type":"string","format":"date-time"}}},"ServerMetricCatalogEntry":{"type":"object","properties":{"metricName":{"type":"string"},"metricType":{"type":"string"},"statistics":{"type":"array","items":{"type":"string"}},"tagKeys":{"type":"array","items":{"type":"string"}}}},"SensitiveKeysConfig":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"string"}}}},"RoleDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"scope":{"type":"string"},"system":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"assignedGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}},"directUsers":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"}},"effectivePrincipals":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"}}}},"UserSummary":{"type":"object","properties":{"userId":{"type":"string"},"displayName":{"type":"string"},"provider":{"type":"string"}}},"RbacStats":{"type":"object","properties":{"userCount":{"type":"integer","format":"int32"},"activeUserCount":{"type":"integer","format":"int32"},"groupCount":{"type":"integer","format":"int32"},"maxGroupDepth":{"type":"integer","format":"int32"},"roleCount":{"type":"integer","format":"int32"}}},"GroupDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"parentGroupId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"directRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"effectiveRoles":{"type":"array","items":{"$ref":"#/components/schemas/RoleSummary"}},"members":{"type":"array","items":{"$ref":"#/components/schemas/UserSummary"}},"childGroups":{"type":"array","items":{"$ref":"#/components/schemas/GroupSummary"}}}},"TableSizeResponse":{"type":"object","description":"Table size and row count information","properties":{"tableName":{"type":"string","description":"Table name"},"rowCount":{"type":"integer","format":"int64","description":"Approximate row count"},"dataSize":{"type":"string","description":"Human-readable data size"},"indexSize":{"type":"string","description":"Human-readable index size"},"dataSizeBytes":{"type":"integer","format":"int64","description":"Data size in bytes"},"indexSizeBytes":{"type":"integer","format":"int64","description":"Index size in bytes"}}},"DatabaseStatusResponse":{"type":"object","description":"Database connection and version status","properties":{"connected":{"type":"boolean","description":"Whether the database is reachable"},"version":{"type":"string","description":"PostgreSQL version string"},"host":{"type":"string","description":"Database host"},"schema":{"type":"string","description":"Current schema"}}},"ActiveQueryResponse":{"type":"object","description":"Currently running database query","properties":{"pid":{"type":"integer","format":"int32","description":"Backend process ID"},"durationSeconds":{"type":"number","format":"double","description":"Query duration in seconds"},"state":{"type":"string","description":"Backend state (active, idle, etc.)"},"query":{"type":"string","description":"SQL query text"}}},"ConnectionPoolResponse":{"type":"object","description":"HikariCP connection pool statistics","properties":{"activeConnections":{"type":"integer","format":"int32","description":"Number of currently active connections"},"idleConnections":{"type":"integer","format":"int32","description":"Number of idle connections"},"pendingThreads":{"type":"integer","format":"int32","description":"Number of threads waiting for a connection"},"maxWaitMs":{"type":"integer","format":"int64","description":"Maximum wait time in milliseconds"},"maxPoolSize":{"type":"integer","format":"int32","description":"Maximum pool size"}}},"ClickHouseTableInfo":{"type":"object","description":"ClickHouse table information","properties":{"name":{"type":"string"},"engine":{"type":"string"},"rowCount":{"type":"integer","format":"int64"},"dataSize":{"type":"string"},"dataSizeBytes":{"type":"integer","format":"int64"},"partitionCount":{"type":"integer","format":"int32"}}},"ClickHouseStatusResponse":{"type":"object","description":"ClickHouse cluster status","properties":{"reachable":{"type":"boolean"},"version":{"type":"string"},"uptime":{"type":"string"},"host":{"type":"string"}}},"ClickHouseQueryInfo":{"type":"object","description":"Active ClickHouse query information","properties":{"queryId":{"type":"string"},"elapsedSeconds":{"type":"number","format":"double"},"memory":{"type":"string"},"readRows":{"type":"integer","format":"int64"},"query":{"type":"string"}}},"ClickHousePerformanceResponse":{"type":"object","description":"ClickHouse storage and performance metrics","properties":{"diskSize":{"type":"string"},"uncompressedSize":{"type":"string"},"compressionRatio":{"type":"number","format":"double"},"totalRows":{"type":"integer","format":"int64"},"partCount":{"type":"integer","format":"int32"},"memoryUsage":{"type":"string"},"currentQueries":{"type":"integer","format":"int32"}}},"AuditLogPageResponse":{"type":"object","description":"Paginated audit log entries","properties":{"items":{"type":"array","description":"Audit log entries","items":{"$ref":"#/components/schemas/AuditRecord"}},"totalCount":{"type":"integer","format":"int64","description":"Total number of matching entries"},"page":{"type":"integer","format":"int32","description":"Current page number (0-based)"},"pageSize":{"type":"integer","format":"int32","description":"Page size"},"totalPages":{"type":"integer","format":"int32","description":"Total number of pages"}}},"AuditRecord":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"timestamp":{"type":"string","format":"date-time"},"username":{"type":"string"},"action":{"type":"string"},"category":{"type":"string","enum":["INFRA","AUTH","USER_MGMT","CONFIG","RBAC","AGENT","OUTBOUND_CONNECTION_CHANGE","OUTBOUND_HTTP_TRUST_CHANGE","ALERT_RULE_CHANGE","ALERT_SILENCE_CHANGE","DEPLOYMENT","LICENSE"]},"target":{"type":"string"},"detail":{"type":"object","additionalProperties":{"type":"object"}},"result":{"type":"string","enum":["SUCCESS","FAILURE"]},"ipAddress":{"type":"string"},"userAgent":{"type":"string"}}}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}}} \ No newline at end of file diff --git a/ui/src/api/queries/auth.test.tsx b/ui/src/api/queries/auth.test.tsx new file mode 100644 index 00000000..fe87a1c5 --- /dev/null +++ b/ui/src/api/queries/auth.test.tsx @@ -0,0 +1,46 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { renderHook, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import type { ReactNode } from 'react'; + +vi.mock('../client', () => ({ api: { GET: vi.fn() } })); + +import { api as apiClient } from '../client'; +import { useAuthCapabilities } from './auth'; + +function wrapper({ children }: { children: ReactNode }) { + const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + return {children}; +} + +describe('useAuthCapabilities', () => { + beforeEach(() => vi.clearAllMocks()); + + it('returns the capabilities body on success', async () => { + (apiClient.GET as any).mockResolvedValue({ + data: { + oidc: { enabled: true, providerName: 'Logto', primary: true }, + localAccounts: { enabled: true, adminRecoveryOnly: true }, + }, + error: null, + }); + + const { result } = renderHook(() => useAuthCapabilities(), { wrapper }); + + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + expect(result.current.data?.oidc?.enabled).toBe(true); + expect(result.current.data?.oidc?.providerName).toBe('Logto'); + expect(result.current.data?.localAccounts?.adminRecoveryOnly).toBe(true); + }); + + it('exposes error state when the request fails', async () => { + (apiClient.GET as any).mockResolvedValue({ + data: undefined, + error: { message: 'boom' }, + }); + + const { result } = renderHook(() => useAuthCapabilities(), { wrapper }); + + await waitFor(() => expect(result.current.isError).toBe(true)); + }); +}); diff --git a/ui/src/api/queries/auth.ts b/ui/src/api/queries/auth.ts index 343f462b..b728e642 100644 --- a/ui/src/api/queries/auth.ts +++ b/ui/src/api/queries/auth.ts @@ -1,6 +1,8 @@ import { useQuery } from '@tanstack/react-query'; import { config } from '../../config'; import { useAuthStore } from '../../auth/auth-store'; +import { api } from '../client'; +import type { components } from '../schema'; export interface RoleSummary { id: string; @@ -46,3 +48,18 @@ export function useMe(enabled = false) { staleTime: 30_000, }); } + +export type AuthCapabilities = components['schemas']['AuthCapabilitiesResponse']; + +export function useAuthCapabilities() { + return useQuery({ + queryKey: ['auth', 'capabilities'], + queryFn: async () => { + const { data, error } = await api.GET('/auth/capabilities'); + if (error || !data) throw new Error('Failed to load auth capabilities'); + return data as AuthCapabilities; + }, + staleTime: Infinity, + retry: false, + }); +} diff --git a/ui/src/api/schema.d.ts b/ui/src/api/schema.d.ts index 4de70b48..6ea3178e 100644 --- a/ui/src/api/schema.d.ts +++ b/ui/src/api/schema.d.ts @@ -1131,10 +1131,10 @@ export interface paths { path?: never; cookie?: never; }; - /** Get current license info */ + /** Get current license state, invalid reason, and parsed envelope */ get: operations["getCurrent"]; put?: never; - /** Update license token at runtime */ + /** Install or replace the license token at runtime */ post: operations["update_5"]; delete?: never; options?: never; @@ -1872,6 +1872,23 @@ export interface paths { patch?: never; trace?: never; }; + "/auth/capabilities": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Auth capabilities for the SPA login page */ + get: operations["getCapabilities"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/agents/{id}/events": { parameters: { query?: never; @@ -2005,6 +2022,22 @@ export interface paths { patch?: never; trace?: never; }; + "/admin/license/usage": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["get_4"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/admin/database/tables": { parameters: { query?: never; @@ -2194,6 +2227,12 @@ export interface components { color?: string; /** Format: date-time */ createdAt?: string; + /** Format: int32 */ + executionRetentionDays?: number; + /** Format: int32 */ + logRetentionDays?: number; + /** Format: int32 */ + metricRetentionDays?: number; }; /** @description Per-application dashboard settings */ AppSettingsRequest: { @@ -3594,6 +3633,29 @@ export interface components { effectiveRoles?: components["schemas"]["RoleSummary"][]; effectiveGroups?: components["schemas"]["GroupSummary"][]; }; + /** @description Authentication capabilities reported to the SPA so it can render the login page deterministically */ + AuthCapabilitiesResponse: { + /** @description OIDC interactive login capability */ + oidc?: components["schemas"]["Oidc"]; + /** @description Local username/password account capability */ + localAccounts?: components["schemas"]["LocalAccounts"]; + }; + /** @description Local username/password accounts */ + LocalAccounts: { + /** @description Whether the local form is reachable at all */ + enabled?: boolean; + /** @description When true, the SPA gates the local form behind ?local with an admin-recovery banner */ + adminRecoveryOnly?: boolean; + }; + /** @description OIDC interactive login */ + Oidc: { + /** @description Whether OIDC is configured AND enabled */ + enabled?: boolean; + /** @description Best-effort display label, e.g. "Logto", "Keycloak", "Single Sign-On" */ + providerName: string; + /** @description When true, OIDC is the canonical entry point and the SPA hides the local form unless ?local is set */ + primary?: boolean; + }; SseEmitter: { /** Format: int64 */ timeout?: number; @@ -3651,18 +3713,6 @@ export interface components { /** Format: int32 */ roleCount?: number; }; - LicenseInfo: { - tier?: string; - features?: ("topology" | "lineage" | "correlation" | "debugger" | "replay")[]; - limits?: { - [key: string]: number; - }; - /** Format: date-time */ - issuedAt?: string; - /** Format: date-time */ - expiresAt?: string; - expired?: boolean; - }; GroupDetail: { /** Format: uuid */ id?: string; @@ -3832,7 +3882,7 @@ export interface components { username?: string; action?: string; /** @enum {string} */ - category?: "INFRA" | "AUTH" | "USER_MGMT" | "CONFIG" | "RBAC" | "AGENT" | "OUTBOUND_CONNECTION_CHANGE" | "OUTBOUND_HTTP_TRUST_CHANGE" | "ALERT_RULE_CHANGE" | "ALERT_SILENCE_CHANGE" | "DEPLOYMENT"; + category?: "INFRA" | "AUTH" | "USER_MGMT" | "CONFIG" | "RBAC" | "AGENT" | "OUTBOUND_CONNECTION_CHANGE" | "OUTBOUND_HTTP_TRUST_CHANGE" | "ALERT_RULE_CHANGE" | "ALERT_SILENCE_CHANGE" | "DEPLOYMENT" | "LICENSE"; target?: string; detail?: { [key: string]: Record; @@ -4825,6 +4875,15 @@ export interface operations { "*/*": Record; }; }; + /** @description jarRetentionCount exceeds license cap */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "*/*": Record; + }; + }; }; }; updateDefaultContainerConfig: { @@ -6553,7 +6612,9 @@ export interface operations { [name: string]: unknown; }; content: { - "*/*": components["schemas"]["LicenseInfo"]; + "*/*": { + [key: string]: Record; + }; }; }; }; @@ -7886,6 +7947,26 @@ export interface operations { }; }; }; + getCapabilities: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Capabilities resolved */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "*/*": components["schemas"]["AuthCapabilitiesResponse"]; + }; + }; + }; + }; events: { parameters: { query?: never; @@ -8062,6 +8143,28 @@ export interface operations { }; }; }; + get_4: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "*/*": { + [key: string]: Record; + }; + }; + }; + }; + }; getTables: { parameters: { query?: never; diff --git a/ui/src/auth/LoginPage.module.css b/ui/src/auth/LoginPage.module.css index f42f1da6..44c0d428 100644 --- a/ui/src/auth/LoginPage.module.css +++ b/ui/src/auth/LoginPage.module.css @@ -91,3 +91,32 @@ width: 100%; justify-content: center; } + +.adminRecoveryBanner { + margin-bottom: 1rem; +} + +.adminRecoveryBanner .backToSsoLink { + display: inline-block; + margin-top: 0.5rem; + color: var(--accent); + text-decoration: none; + font-size: 0.875rem; +} + +.adminRecoveryBanner .backToSsoLink:hover { + text-decoration: underline; +} + +.adminRecoveryLink { + display: inline-block; + margin-top: 0.75rem; + color: var(--text-muted); + font-size: 0.8125rem; + text-decoration: none; +} + +.adminRecoveryLink:hover { + color: var(--accent); + text-decoration: underline; +} diff --git a/ui/src/auth/LoginPage.test.tsx b/ui/src/auth/LoginPage.test.tsx new file mode 100644 index 00000000..acf7436f --- /dev/null +++ b/ui/src/auth/LoginPage.test.tsx @@ -0,0 +1,156 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { MemoryRouter } from 'react-router'; +import type { ReactNode } from 'react'; + +vi.mock('../api/client', () => ({ api: { GET: vi.fn() } })); +vi.mock('./auth-store', () => ({ + useAuthStore: Object.assign( + () => ({ isAuthenticated: false, login: vi.fn(), loading: false, error: null }), + { setState: vi.fn() } + ), +})); + +import { api as apiClient } from '../api/client'; +import { useAuthStore } from './auth-store'; +import { LoginPage } from './LoginPage'; + +function wrapper(initialEntries: string[]) { + return ({ children }: { children: ReactNode }) => { + const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + return ( + + {children} + + ); + }; +} + +function mockCaps(body: any) { + (apiClient.GET as any).mockImplementation((path: string) => { + if (path === '/auth/capabilities') return Promise.resolve({ data: body, error: null }); + if (path === '/auth/oidc/config') return Promise.resolve({ + data: { + clientId: 'spa-client', + authorizationEndpoint: 'https://auth.logto.example/oidc/auth', + resource: 'https://api.cameleer.local', + additionalScopes: [], + }, + error: null, + }); + return Promise.resolve({ data: undefined, error: { message: 'unexpected' } }); + }); +} + +describe('LoginPage', () => { + beforeEach(() => vi.clearAllMocks()); + + it('SSO primary, no ?local: renders SSO button only and admin-recovery link, no local form', async () => { + mockCaps({ + oidc: { enabled: true, providerName: 'Logto', primary: true }, + localAccounts: { enabled: true, adminRecoveryOnly: true }, + }); + + render(, { wrapper: wrapper(['/login']) }); + + expect(await screen.findByRole('button', { name: /sign in with logto/i })).toBeInTheDocument(); + expect(screen.queryByLabelText(/username/i)).toBeNull(); + expect(screen.queryByLabelText(/password/i)).toBeNull(); + expect(screen.getByRole('link', { name: /admin recovery/i })).toBeInTheDocument(); + }); + + it('SSO primary, ?local present: renders local form with amber recovery banner and back-to-SSO link', async () => { + mockCaps({ + oidc: { enabled: true, providerName: 'Logto', primary: true }, + localAccounts: { enabled: true, adminRecoveryOnly: true }, + }); + + render(, { wrapper: wrapper(['/login?local']) }); + + expect(await screen.findByLabelText(/username/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/password/i)).toBeInTheDocument(); + expect(screen.getByText(/admin recovery/i)).toBeInTheDocument(); + expect(screen.getByRole('link', { name: /back to sso/i })).toBeInTheDocument(); + }); + + it('OIDC disabled: renders local form only, no SSO button', async () => { + mockCaps({ + oidc: { enabled: false, providerName: '', primary: false }, + localAccounts: { enabled: true, adminRecoveryOnly: false }, + }); + + render(, { wrapper: wrapper(['/login']) }); + + expect(await screen.findByLabelText(/username/i)).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: /sign in with/i })).toBeNull(); + expect(screen.queryByText(/admin recovery/i)).toBeNull(); + }); + + it('capabilities request fails: renders degraded local form with warning banner', async () => { + (apiClient.GET as any).mockImplementation((path: string) => { + if (path === '/auth/capabilities') return Promise.resolve({ data: undefined, error: { message: 'fail' } }); + return Promise.resolve({ data: undefined, error: { message: 'unexpected' } }); + }); + + render(, { wrapper: wrapper(['/login']) }); + + expect(await screen.findByLabelText(/username/i)).toBeInTheDocument(); + expect(screen.getByText(/sign-in options couldn't load/i)).toBeInTheDocument(); + }); + + it('SSO button click: navigates to authorize URL WITHOUT prompt=none', async () => { + mockCaps({ + oidc: { enabled: true, providerName: 'Logto', primary: true }, + localAccounts: { enabled: true, adminRecoveryOnly: true }, + }); + + const originalLocation = window.location; + const hrefSetter = vi.fn(); + Object.defineProperty(window, 'location', { + configurable: true, + value: { ...originalLocation, get href() { return ''; }, set href(v: string) { hrefSetter(v); } }, + }); + + try { + render(, { wrapper: wrapper(['/login']) }); + const btn = await screen.findByRole('button', { name: /sign in with logto/i }); + fireEvent.click(btn); + + await waitFor(() => expect(hrefSetter).toHaveBeenCalled()); + const url: string = hrefSetter.mock.calls[0][0]; + expect(url).toMatch(/^https:\/\/auth\.logto\.example\/oidc\/auth\?/); + expect(url).not.toMatch(/prompt=none/); + expect(url).toMatch(/response_type=code/); + expect(url).toMatch(/client_id=spa-client/); + expect(url).toMatch(/scope=/); + } finally { + Object.defineProperty(window, 'location', { configurable: true, value: originalLocation }); + } + }); + + it('SSO button click: when /auth/oidc/config fails, button unlocks and error is set', async () => { + const setStateMock = vi.fn(); + const useAuthStoreMock = vi.mocked(useAuthStore) as unknown as { setState: typeof setStateMock }; + useAuthStoreMock.setState = setStateMock; + + (apiClient.GET as any).mockImplementation((path: string) => { + if (path === '/auth/capabilities') return Promise.resolve({ + data: { oidc: { enabled: true, providerName: 'Logto', primary: true }, localAccounts: { enabled: true, adminRecoveryOnly: true } }, + error: null, + }); + if (path === '/auth/oidc/config') return Promise.reject(new Error('network down')); + return Promise.resolve({ data: undefined, error: { message: 'unexpected' } }); + }); + + render(, { wrapper: wrapper(['/login']) }); + const btn = await screen.findByRole('button', { name: /sign in with logto/i }); + fireEvent.click(btn); + + await waitFor(() => expect(setStateMock).toHaveBeenCalled()); + const errorPayload = setStateMock.mock.calls[0][0]; + expect(errorPayload.error).toMatch(/OIDC configuration unavailable/i); + // Button should not stay locked in "Redirecting…" + await waitFor(() => expect(btn).not.toHaveTextContent(/redirecting/i)); + }); +}); diff --git a/ui/src/auth/LoginPage.tsx b/ui/src/auth/LoginPage.tsx index 78e2ccb5..515b3de8 100644 --- a/ui/src/auth/LoginPage.tsx +++ b/ui/src/auth/LoginPage.tsx @@ -1,21 +1,13 @@ -import { type FormEvent, useEffect, useMemo, useRef, useState } from 'react'; -import { Navigate, useSearchParams } from 'react-router'; +import { type FormEvent, useMemo, useState } from 'react'; +import { Link, Navigate, useSearchParams } from 'react-router'; import { useAuthStore } from './auth-store'; import { api } from '../api/client'; import { config } from '../config'; +import { useAuthCapabilities } from '../api/queries/auth'; import { Card, Input, Button, Alert, FormField } from '@cameleer/design-system'; import brandLogo from '@cameleer/design-system/assets/cameleer-logo.svg'; import styles from './LoginPage.module.css'; -interface OidcInfo { - clientId: string; - authorizationEndpoint: string; - resource?: string; - additionalScopes?: string[]; -} - -// Logto org scopes required for role mapping in multi-tenant setups. -// Always requested, harmless for non-Logto providers (unknown scopes are ignored per OIDC spec). const PLATFORM_SCOPES = ['urn:logto:scope:organizations', 'urn:logto:scope:organization_roles']; const SUBTITLES = [ @@ -53,66 +45,55 @@ export function LoginPage() { const subtitle = useMemo(() => SUBTITLES[Math.floor(Math.random() * SUBTITLES.length)], []); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); - const [oidc, setOidc] = useState(null); const [oidcLoading, setOidcLoading] = useState(false); - const autoRedirected = useRef(false); - useEffect(() => { - api.GET('/auth/oidc/config') - .then(({ data }) => { - if (data?.authorizationEndpoint && data?.clientId) { - setOidc({ - clientId: data.clientId, - authorizationEndpoint: data.authorizationEndpoint, - resource: data.resource ?? undefined, - additionalScopes: data.additionalScopes ?? undefined, - }); - if (data.endSessionEndpoint) { - localStorage.setItem('cameleer-oidc-end-session', data.endSessionEndpoint); - } - } - }) - .catch(() => {}); - }, []); - - // Auto-redirect to OIDC provider for SSO (skip if ?local is in URL) - useEffect(() => { - if (oidc && !forceLocal && !autoRedirected.current) { - autoRedirected.current = true; - const redirectUri = `${window.location.origin}${config.basePath}oidc/callback`; - const scopes = ['openid', 'email', 'profile', ...PLATFORM_SCOPES, ...(oidc.additionalScopes || [])]; - const params = new URLSearchParams({ - response_type: 'code', - client_id: oidc.clientId, - redirect_uri: redirectUri, - scope: scopes.join(' '), - prompt: 'none', - }); - if (oidc.resource) params.set('resource', oidc.resource); - window.location.href = `${oidc.authorizationEndpoint}?${params}`; - } - }, [oidc, forceLocal]); + const { data: caps, isError: capsFailed, isLoading: capsLoading } = useAuthCapabilities(); if (isAuthenticated) return ; + if (capsLoading) return null; + + const oidcPrimary = caps?.oidc?.primary === true; + const adminRecoveryOnly = caps?.localAccounts?.adminRecoveryOnly === true; + const providerName = caps?.oidc?.providerName || 'Single Sign-On'; + + // Render decisions + const showSsoPrimary = oidcPrimary && adminRecoveryOnly && !forceLocal; + const showLocalForm = !oidcPrimary || forceLocal || !adminRecoveryOnly || capsFailed; + const showAdminRecoveryBanner = oidcPrimary && adminRecoveryOnly && forceLocal; const handleSubmit = (e: FormEvent) => { e.preventDefault(); login(username, password); }; - const handleOidcLogin = () => { - if (!oidc) return; + const handleOidcLogin = async () => { setOidcLoading(true); - const redirectUri = `${window.location.origin}${config.basePath}oidc/callback`; - const scopes = ['openid', 'email', 'profile', ...PLATFORM_SCOPES, ...(oidc.additionalScopes || [])]; - const params = new URLSearchParams({ - response_type: 'code', - client_id: oidc.clientId, - redirect_uri: redirectUri, - scope: scopes.join(' '), - }); - if (oidc.resource) params.set('resource', oidc.resource); - window.location.href = `${oidc.authorizationEndpoint}?${params}`; + try { + const { data } = await api.GET('/auth/oidc/config'); + if (!data?.authorizationEndpoint || !data?.clientId) { + useAuthStore.setState({ error: 'OIDC configuration unavailable. Try the local form via /login?local.' }); + return; + } + if (data.endSessionEndpoint) { + localStorage.setItem('cameleer-oidc-end-session', data.endSessionEndpoint); + } + const redirectUri = `${window.location.origin}${config.basePath}oidc/callback`; + const scopes = ['openid', 'email', 'profile', ...PLATFORM_SCOPES, ...(data.additionalScopes || [])]; + const params = new URLSearchParams({ + response_type: 'code', + client_id: data.clientId, + redirect_uri: redirectUri, + scope: scopes.join(' '), + }); + if (data.resource) params.set('resource', data.resource); + // Note: NO prompt=none. Per RFC 9700 §4.4, that's silent re-auth only; + // for first-time login it returns login_required and traps users on a local form. + window.location.href = `${data.authorizationEndpoint}?${params}`; + } catch { + useAuthStore.setState({ error: 'OIDC configuration unavailable. Try the local form via /login?local.' }); + } finally { + setOidcLoading(false); + } }; return ( @@ -125,68 +106,81 @@ export function LoginPage() {

{subtitle}

+ {capsFailed && ( +
+ Sign-in options couldn't load. Refresh or use the form below. +
+ )} + + {showAdminRecoveryBanner && ( +
+ + Admin recovery login. Use SSO for normal sign-in. + + ← Back to SSO +
+ )} + {error && (
{error}
)} - {oidc && ( - <> -
- -
-
-
- or -
-
- + {showSsoPrimary && ( +
+ + + Admin recovery → + +
)} -
- - setUsername(e.target.value)} - placeholder="Enter your username" - autoFocus - autoComplete="username" - disabled={loading} - /> - + {showLocalForm && ( + + + setUsername(e.target.value)} + placeholder="Enter your username" + autoFocus + autoComplete="username" + disabled={loading} + /> + - - setPassword(e.target.value)} - placeholder="••••••••" - autoComplete="current-password" - disabled={loading} - /> - + + setPassword(e.target.value)} + placeholder="••••••••" + autoComplete="current-password" + disabled={loading} + /> + - -
+ + + )}
diff --git a/ui/src/auth/OidcCallback.tsx b/ui/src/auth/OidcCallback.tsx index 091a6438..e74bec4c 100644 --- a/ui/src/auth/OidcCallback.tsx +++ b/ui/src/auth/OidcCallback.tsx @@ -20,11 +20,6 @@ export function OidcCallback() { const errorParam = params.get('error'); if (errorParam) { - // prompt=none failed — no session, fall back to login form - if (errorParam === 'login_required' || errorParam === 'interaction_required') { - window.location.replace(`${config.basePath}login?local`); - return; - } // consent_required — retry without prompt=none so user can grant scopes if (errorParam === 'consent_required' && !sessionStorage.getItem('oidc-consent-retry')) { sessionStorage.setItem('oidc-consent-retry', '1'); @@ -43,7 +38,7 @@ export function OidcCallback() { window.location.href = `${data.authorizationEndpoint}?${p}`; } }).catch(() => { - window.location.replace(`${config.basePath}login?local`); + useAuthStore.setState({ error: 'OIDC consent retry failed.', loading: false }); }); return; } @@ -77,7 +72,7 @@ export function OidcCallback() { {error && ( <> {error} - diff --git a/ui/src/auth/auth-store.ts b/ui/src/auth/auth-store.ts index 9c83808e..4b3e9e3c 100644 --- a/ui/src/auth/auth-store.ts +++ b/ui/src/auth/auth-store.ts @@ -154,11 +154,11 @@ export const useAuthStore = create((set, get) => ({ isAuthenticated: false, error: null, }); - const loginUrl = `${config.basePath}login?local`; + const loginUrl = `${config.basePath}login`; if (endSessionEndpoint && idToken) { const params = new URLSearchParams({ id_token_hint: idToken, - post_logout_redirect_uri: `${window.location.origin}${config.basePath}login?local`, + post_logout_redirect_uri: `${window.location.origin}${config.basePath}login`, }); fetch(`${endSessionEndpoint}?${params}`, { mode: 'no-cors' }).finally(() => { window.location.href = loginUrl; diff --git a/ui/src/test/e2e/fixtures.ts b/ui/src/test/e2e/fixtures.ts index 2a02ead3..f27b9dad 100644 --- a/ui/src/test/e2e/fixtures.ts +++ b/ui/src/test/e2e/fixtures.ts @@ -19,8 +19,9 @@ type Fixtures = { export const test = base.extend({ loggedIn: [ async ({ page }, use) => { - // `?local` keeps the login page's auto-OIDC-redirect from firing so the - // form-based login works even when an OIDC config happens to be present. + // Navigate to ?local to bypass the SSO-primary page and reach the local + // form directly, so the fixture works regardless of whether OIDC is + // configured on the test server. await page.goto('/login?local'); await page.getByLabel(/username/i).fill(ADMIN_USER); await page.getByLabel(/password/i).fill(ADMIN_PASS);