diff --git a/.claude/rules/app-classes.md b/.claude/rules/app-classes.md index 033bd33f..a6a6840b 100644 --- a/.claude/rules/app-classes.md +++ b/.claude/rules/app-classes.md @@ -57,7 +57,7 @@ Env-scoped read-path controllers (`AlertController`, `AlertRuleController`, `Ale - `DeploymentController` — `/api/v1/environments/{envSlug}/apps/{appSlug}/deployments`. GET list / POST create (body `{ appVersionId }`) / POST `{id}/stop` / POST `{id}/promote` (body `{ targetEnvironment: slug }` — target app slug must exist in target env) / GET `{id}/logs`. All lifecycle ops (`POST /` deploy, `POST /{id}/stop`, `POST /{id}/promote`) audited under `AuditCategory.DEPLOYMENT`. Action codes: `deploy_app`, `stop_deployment`, `promote_deployment`. Acting user resolved via the `user:` prefix-strip convention; both SUCCESS and FAILURE branches write audit rows. `created_by` (TEXT, nullable) populated from `SecurityContextHolder` and surfaced on the `Deployment` DTO. - `ApplicationConfigController` — `/api/v1/environments/{envSlug}`. GET `/config` (list), GET/PUT `/apps/{appSlug}/config`, GET `/apps/{appSlug}/processor-routes`, POST `/apps/{appSlug}/config/test-expression`. PUT accepts `?apply=staged|live` (default `live`). `live` saves to DB and pushes `CONFIG_UPDATE` SSE to live agents in this env (existing behavior); `staged` saves to DB only, skipping the SSE push — used by the unified app deployment page. Audit action is `stage_app_config` for staged writes, `update_app_config` for live. Invalid `apply` values return 400. - `AppSettingsController` — `/api/v1/environments/{envSlug}`. GET `/app-settings` (list), GET/PUT/DELETE `/apps/{appSlug}/settings`. ADMIN/OPERATOR only. -- `SearchController` — `/api/v1/environments/{envSlug}`. GET `/executions`, POST `/executions/search`, GET `/stats`, `/stats/timeseries`, `/stats/timeseries/by-app`, `/stats/timeseries/by-route`, `/stats/punchcard`, `/attributes/keys`, `/errors/top`. +- `SearchController` — `/api/v1/environments/{envSlug}`. GET `/executions`, POST `/executions/search`, GET `/stats`, `/stats/timeseries`, `/stats/timeseries/by-app`, `/stats/timeseries/by-route`, `/stats/punchcard`, `/attributes/keys`, `/errors/top`. GET `/executions` accepts repeat `attr` query params: `attr=order` (key-exists), `attr=order:47` (exact), `attr=order:4*` (wildcard — `*` maps to SQL LIKE `%`). First `:` splits key/value; later colons stay in the value. Invalid keys → 400. POST `/executions/search` accepts the same filters via `SearchRequest.attributeFilters` in the body. - `LogQueryController` — GET `/api/v1/environments/{envSlug}/logs` (filters: source (multi, comma-split, OR-joined), level (multi, comma-split, OR-joined), application, agentId, exchangeId, logger, q, time range, instanceIds (multi, comma-split, AND-joined as WHERE instance_id IN (...) — used by the Checkpoint detail drawer to scope logs to a deployment's replicas); sort asc/desc). Cursor-paginated, returns `{ data, nextCursor, hasMore, levelCounts }`; cursor is base64url of `"{timestampIso}|{insert_id_uuid}"` — same-millisecond tiebreak via the `insert_id` UUID column on `logs`. - `RouteCatalogController` — GET `/api/v1/environments/{envSlug}/routes` (merged route catalog from registry + ClickHouse; env filter unconditional). - `RouteMetricsController` — GET `/api/v1/environments/{envSlug}/routes/metrics`, GET `/api/v1/environments/{envSlug}/routes/metrics/processors`. diff --git a/.claude/rules/core-classes.md b/.claude/rules/core-classes.md index a16b1cd6..c7b7ee64 100644 --- a/.claude/rules/core-classes.md +++ b/.claude/rules/core-classes.md @@ -47,7 +47,8 @@ paths: ## search/ — Execution search and stats - `SearchService` — search, count, stats, statsForApp, statsForRoute, timeseries, timeseriesForApp, timeseriesForRoute, timeseriesGroupedByApp, timeseriesGroupedByRoute, slaCompliance, slaCountsByApp, slaCountsByRoute, topErrors, activeErrorTypes, punchcard, distinctAttributeKeys. `statsForRoute`/`timeseriesForRoute` take `(routeId, applicationId)` — app filter is applied to `stats_1m_route`. -- `SearchRequest` / `SearchResult` — search DTOs +- `SearchRequest` / `SearchResult` — search DTOs. `SearchRequest.attributeFilters: List` carries structured facet filters for execution attributes — key-only (exists), exact (key=value), or wildcard (`*` in value). The 21-arg legacy ctor is preserved for call-site churn; the compact ctor normalises null → `List.of()`. +- `AttributeFilter(key, value)` — record with key regex `^[a-zA-Z0-9._-]+$` (inlined into SQL, same constraint as alerting), `value == null` means key-exists, `value` containing `*` becomes a SQL LIKE pattern via `toLikePattern()`. - `ExecutionStats`, `ExecutionSummary` — stats aggregation records - `StatsTimeseries`, `TopError` — timeseries and error DTOs - `LogSearchRequest` / `LogSearchResponse` — log search DTOs. `LogSearchRequest.sources` / `levels` are `List` (null-normalized, multi-value OR); `cursor` + `limit` + `sort` drive keyset pagination. Response carries `nextCursor` + `hasMore` + per-level `levelCounts`. diff --git a/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/SearchController.java b/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/SearchController.java index 02cb16e5..146946df 100644 --- a/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/SearchController.java +++ b/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/SearchController.java @@ -4,6 +4,7 @@ import com.cameleer.server.app.web.EnvPath; import com.cameleer.server.core.admin.AppSettings; import com.cameleer.server.core.admin.AppSettingsRepository; import com.cameleer.server.core.runtime.Environment; +import com.cameleer.server.core.search.AttributeFilter; import com.cameleer.server.core.search.ExecutionStats; import com.cameleer.server.core.search.ExecutionSummary; import com.cameleer.server.core.search.SearchRequest; @@ -14,6 +15,7 @@ import com.cameleer.server.core.search.TopError; import com.cameleer.server.core.storage.StatsStore; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -21,8 +23,10 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; import java.time.Instant; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -57,11 +61,19 @@ public class SearchController { @RequestParam(name = "agentId", required = false) String instanceId, @RequestParam(required = false) String processorType, @RequestParam(required = false) String application, + @RequestParam(name = "attr", required = false) List attr, @RequestParam(defaultValue = "0") int offset, @RequestParam(defaultValue = "50") int limit, @RequestParam(required = false) String sortField, @RequestParam(required = false) String sortDir) { + List attributeFilters; + try { + attributeFilters = parseAttrParams(attr); + } catch (IllegalArgumentException e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e); + } + SearchRequest request = new SearchRequest( status, timeFrom, timeTo, null, null, @@ -72,12 +84,36 @@ public class SearchController { offset, limit, sortField, sortDir, null, - env.slug() + env.slug(), + attributeFilters ); return ResponseEntity.ok(searchService.search(request)); } + /** + * Parses {@code attr} query params of the form {@code key} (key-only) or {@code key:value} + * (exact or wildcard via {@code *}). Splits on the first {@code :}; later colons are part of + * the value. Blank / null list → empty result. Key validation is delegated to + * {@link AttributeFilter}'s compact constructor, which throws {@link IllegalArgumentException} + * on invalid keys (mapped to 400 by the caller). + */ + static List parseAttrParams(List raw) { + if (raw == null || raw.isEmpty()) return List.of(); + List out = new ArrayList<>(raw.size()); + for (String entry : raw) { + if (entry == null || entry.isBlank()) continue; + int colon = entry.indexOf(':'); + if (colon < 0) { + out.add(new AttributeFilter(entry.trim(), null)); + } else { + out.add(new AttributeFilter(entry.substring(0, colon).trim(), + entry.substring(colon + 1))); + } + } + return out; + } + @PostMapping("/executions/search") @Operation(summary = "Advanced search with all filters", description = "Env from the path overrides any environment field in the body.") diff --git a/cameleer-server-app/src/main/java/com/cameleer/server/app/search/ClickHouseSearchIndex.java b/cameleer-server-app/src/main/java/com/cameleer/server/app/search/ClickHouseSearchIndex.java index 246557c1..7546cfd3 100644 --- a/cameleer-server-app/src/main/java/com/cameleer/server/app/search/ClickHouseSearchIndex.java +++ b/cameleer-server-app/src/main/java/com/cameleer/server/app/search/ClickHouseSearchIndex.java @@ -1,6 +1,7 @@ package com.cameleer.server.app.search; import com.cameleer.server.core.alerting.AlertMatchSpec; +import com.cameleer.server.core.search.AttributeFilter; import com.cameleer.server.core.search.ExecutionSummary; import com.cameleer.server.core.search.SearchRequest; import com.cameleer.server.core.search.SearchResult; @@ -256,6 +257,23 @@ public class ClickHouseSearchIndex implements SearchIndex { params.add(likeTerm); } + // Structured attribute filters. Keys were validated at AttributeFilter construction + // time against ^[a-zA-Z0-9._-]+$ so they are safe to single-quote-inline; the JSON path + // argument of JSONExtractString does not accept a ? placeholder in ClickHouse JDBC + // (same constraint as countExecutionsForAlerting below). Values are parameter-bound. + for (AttributeFilter filter : request.attributeFilters()) { + String escapedKey = filter.key().replace("'", "\\'"); + if (filter.isKeyOnly()) { + conditions.add("JSONHas(attributes, '" + escapedKey + "')"); + } else if (filter.isWildcard()) { + conditions.add("JSONExtractString(attributes, '" + escapedKey + "') LIKE ?"); + params.add(filter.toLikePattern()); + } else { + conditions.add("JSONExtractString(attributes, '" + escapedKey + "') = ?"); + params.add(filter.value()); + } + } + return String.join(" AND ", conditions); } diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java index 7a7296e7..49eed7fb 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java @@ -166,6 +166,42 @@ class SearchControllerIT extends AbstractPostgresIT { """, i, i, i, i, i)); } + // Executions 11-12: carry structured attributes used by the attribute-filter tests. + ingest(""" + { + "exchangeId": "ex-search-attr-1", + "applicationId": "test-group", + "instanceId": "test-agent-search-it", + "routeId": "search-route-attr-1", + "correlationId": "corr-attr-alpha", + "status": "COMPLETED", + "startTime": "2026-03-12T10:00:00Z", + "endTime": "2026-03-12T10:00:00.050Z", + "durationMs": 50, + "attributes": {"order": "12345", "tenant": "acme"}, + "chunkSeq": 0, + "final": true, + "processors": [] + } + """); + ingest(""" + { + "exchangeId": "ex-search-attr-2", + "applicationId": "test-group", + "instanceId": "test-agent-search-it", + "routeId": "search-route-attr-2", + "correlationId": "corr-attr-beta", + "status": "COMPLETED", + "startTime": "2026-03-12T10:01:00Z", + "endTime": "2026-03-12T10:01:00.050Z", + "durationMs": 50, + "attributes": {"order": "99999"}, + "chunkSeq": 0, + "final": true, + "processors": [] + } + """); + // Wait for async ingestion + search indexing via REST (no raw SQL). // Probe the last seeded execution to avoid false positives from // other test classes that may have written into the shared CH tables. @@ -174,6 +210,11 @@ class SearchControllerIT extends AbstractPostgresIT { JsonNode body = objectMapper.readTree(r.getBody()); assertThat(body.get("total").asLong()).isGreaterThanOrEqualTo(1); }); + await().atMost(30, SECONDS).untilAsserted(() -> { + ResponseEntity r = searchGet("?correlationId=corr-attr-beta"); + JsonNode body = objectMapper.readTree(r.getBody()); + assertThat(body.get("total").asLong()).isGreaterThanOrEqualTo(1); + }); } @Test @@ -371,6 +412,69 @@ class SearchControllerIT extends AbstractPostgresIT { assertThat(body.get("limit").asInt()).isEqualTo(50); } + @Test + void attrParam_exactMatch_filtersToMatchingExecution() throws Exception { + ResponseEntity response = searchGet("?attr=order:12345&correlationId=corr-attr-alpha"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JsonNode body = objectMapper.readTree(response.getBody()); + assertThat(body.get("total").asLong()).isEqualTo(1); + assertThat(body.get("data").get(0).get("correlationId").asText()).isEqualTo("corr-attr-alpha"); + } + + @Test + void attrParam_keyOnly_matchesAnyExecutionCarryingTheKey() throws Exception { + ResponseEntity response = searchGet("?attr=tenant&correlationId=corr-attr-alpha"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JsonNode body = objectMapper.readTree(response.getBody()); + assertThat(body.get("total").asLong()).isEqualTo(1); + assertThat(body.get("data").get(0).get("correlationId").asText()).isEqualTo("corr-attr-alpha"); + } + + @Test + void attrParam_multipleValues_produceIntersection() throws Exception { + // order:99999 AND tenant=* should yield zero — exec-attr-2 has order=99999 but no tenant. + ResponseEntity response = searchGet("?attr=order:99999&attr=tenant"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JsonNode body = objectMapper.readTree(response.getBody()); + assertThat(body.get("total").asLong()).isZero(); + } + + @Test + void attrParam_invalidKey_returns400() throws Exception { + ResponseEntity response = searchGet("?attr=bad%20key:x"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + } + + @Test + void attributeFilters_inPostBody_filtersCorrectly() throws Exception { + ResponseEntity response = searchPost(""" + { + "attributeFilters": [ + {"key": "order", "value": "12345"} + ], + "correlationId": "corr-attr-alpha" + } + """); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JsonNode body = objectMapper.readTree(response.getBody()); + assertThat(body.get("total").asLong()).isEqualTo(1); + assertThat(body.get("data").get(0).get("correlationId").asText()).isEqualTo("corr-attr-alpha"); + } + + @Test + void attrParam_wildcardValue_matchesOnPrefix() throws Exception { + ResponseEntity response = searchGet("?attr=order:1*&correlationId=corr-attr-alpha"); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + JsonNode body = objectMapper.readTree(response.getBody()); + assertThat(body.get("total").asLong()).isEqualTo(1); + assertThat(body.get("data").get(0).get("correlationId").asText()).isEqualTo("corr-attr-alpha"); + } + // --- Helper methods --- private void ingest(String json) { diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/search/ClickHouseSearchIndexIT.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/search/ClickHouseSearchIndexIT.java index b1269825..7a5e73bd 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/search/ClickHouseSearchIndexIT.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/search/ClickHouseSearchIndexIT.java @@ -2,6 +2,7 @@ package com.cameleer.server.app.search; import com.cameleer.server.app.storage.ClickHouseExecutionStore; import com.cameleer.server.core.ingestion.MergedExecution; +import com.cameleer.server.core.search.AttributeFilter; import com.cameleer.server.core.search.ExecutionSummary; import com.cameleer.server.core.search.SearchRequest; import com.cameleer.server.core.search.SearchResult; @@ -62,7 +63,7 @@ class ClickHouseSearchIndexIT { 500L, "", "", "", "", "", "", "hash-abc", "FULL", - "{\"order\":\"12345\"}", "", "", "", "", "", "{\"env\":\"prod\"}", + "", "", "", "", "", "", "{\"order\":\"12345\",\"tenant\":\"acme\"}", "", "", false, false, null, null @@ -79,7 +80,7 @@ class ClickHouseSearchIndexIT { "java.lang.NPE\n at Foo.bar(Foo.java:42)", "NullPointerException", "RUNTIME", "", "", "", "FULL", - "", "", "", "", "", "", "", + "", "", "", "", "", "", "{\"order\":\"99999\"}", "", "", false, false, null, null @@ -309,4 +310,59 @@ class ClickHouseSearchIndexIT { assertThat(result.total()).isEqualTo(1); assertThat(result.data().get(0).executionId()).isEqualTo("exec-1"); } + + @Test + void search_byAttributeFilter_exactMatch_matchesExec1() { + SearchRequest request = new SearchRequest( + null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, 0, 50, null, null, null, null, + List.of(new AttributeFilter("order", "12345"))); + + SearchResult result = searchIndex.search(request); + + assertThat(result.total()).isEqualTo(1); + assertThat(result.data().get(0).executionId()).isEqualTo("exec-1"); + } + + @Test + void search_byAttributeFilter_keyOnly_matchesExec1AndExec2() { + SearchRequest request = new SearchRequest( + null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, 0, 50, null, null, null, null, + List.of(new AttributeFilter("order", null))); + + SearchResult result = searchIndex.search(request); + + assertThat(result.total()).isEqualTo(2); + assertThat(result.data()).extracting(ExecutionSummary::executionId) + .containsExactlyInAnyOrder("exec-1", "exec-2"); + } + + @Test + void search_byAttributeFilter_wildcardValue_matchesExec1Only() { + SearchRequest request = new SearchRequest( + null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, 0, 50, null, null, null, null, + List.of(new AttributeFilter("order", "123*"))); + + SearchResult result = searchIndex.search(request); + + assertThat(result.total()).isEqualTo(1); + assertThat(result.data().get(0).executionId()).isEqualTo("exec-1"); + } + + @Test + void search_byAttributeFilter_multipleFiltersAreAnded() { + SearchRequest request = new SearchRequest( + null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, 0, 50, null, null, null, null, + List.of( + new AttributeFilter("order", "12345"), + new AttributeFilter("tenant", "acme"))); + + SearchResult result = searchIndex.search(request); + + assertThat(result.total()).isEqualTo(1); + assertThat(result.data().get(0).executionId()).isEqualTo("exec-1"); + } } diff --git a/cameleer-server-core/src/main/java/com/cameleer/server/core/search/AttributeFilter.java b/cameleer-server-core/src/main/java/com/cameleer/server/core/search/AttributeFilter.java new file mode 100644 index 00000000..7dbb9d02 --- /dev/null +++ b/cameleer-server-core/src/main/java/com/cameleer/server/core/search/AttributeFilter.java @@ -0,0 +1,60 @@ +package com.cameleer.server.core.search; + +import java.util.regex.Pattern; + +/** + * Structured attribute filter for execution search. + *

+ * Value semantics: + *

    + *
  • {@code value == null} or blank -> key-exists check
  • + *
  • {@code value} contains {@code *} -> wildcard match (translated to SQL LIKE pattern)
  • + *
  • otherwise -> exact match
  • + *
+ *

+ * Keys must match {@code ^[a-zA-Z0-9._-]+$} — they are later inlined into + * ClickHouse SQL via {@code JSONExtractString}, which does not accept a + * parameter placeholder for the JSON path. Values are always parameter-bound. + */ +public record AttributeFilter(String key, String value) { + + private static final Pattern KEY_PATTERN = Pattern.compile("^[a-zA-Z0-9._-]+$"); + + public AttributeFilter { + if (key == null || !KEY_PATTERN.matcher(key).matches()) { + throw new IllegalArgumentException( + "Invalid attribute key: must match " + KEY_PATTERN.pattern() + ", got: " + key); + } + if (value != null && value.isBlank()) { + value = null; + } + } + + public boolean isKeyOnly() { + return value == null; + } + + public boolean isWildcard() { + return value != null && value.indexOf('*') >= 0; + } + + /** + * Returns a SQL LIKE pattern for wildcard matches with {@code %} / {@code _} / {@code \} + * in the source value escaped, or {@code null} for exact / key-only filters. + */ + public String toLikePattern() { + if (!isWildcard()) return null; + StringBuilder sb = new StringBuilder(value.length() + 4); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + switch (c) { + case '\\' -> sb.append("\\\\"); + case '%' -> sb.append("\\%"); + case '_' -> sb.append("\\_"); + case '*' -> sb.append('%'); + default -> sb.append(c); + } + } + return sb.toString(); + } +} diff --git a/cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchRequest.java b/cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchRequest.java index de15c4b8..02ae76ea 100644 --- a/cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchRequest.java +++ b/cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchRequest.java @@ -54,7 +54,8 @@ public record SearchRequest( String sortField, String sortDir, String afterExecutionId, - String environment + String environment, + List attributeFilters ) { private static final int DEFAULT_LIMIT = 50; @@ -83,6 +84,24 @@ public record SearchRequest( if (offset < 0) offset = 0; if (sortField == null || !ALLOWED_SORT_FIELDS.contains(sortField)) sortField = "startTime"; if (!"asc".equalsIgnoreCase(sortDir)) sortDir = "desc"; + if (attributeFilters == null) attributeFilters = List.of(); + } + + /** Legacy 21-arg constructor preserved for existing call sites — defaults attributeFilters to empty. */ + public SearchRequest( + String status, Instant timeFrom, Instant timeTo, + Long durationMin, Long durationMax, String correlationId, + String text, String textInBody, String textInHeaders, String textInErrors, + String routeId, String instanceId, String processorType, + String applicationId, List instanceIds, + int offset, int limit, String sortField, String sortDir, + String afterExecutionId, String environment + ) { + this(status, timeFrom, timeTo, durationMin, durationMax, correlationId, + text, textInBody, textInHeaders, textInErrors, + routeId, instanceId, processorType, applicationId, instanceIds, + offset, limit, sortField, sortDir, afterExecutionId, environment, + List.of()); } /** Returns the snake_case column name for ORDER BY. */ @@ -96,7 +115,8 @@ public record SearchRequest( status, timeFrom, timeTo, durationMin, durationMax, correlationId, text, textInBody, textInHeaders, textInErrors, routeId, instanceId, processorType, applicationId, resolvedInstanceIds, - offset, limit, sortField, sortDir, afterExecutionId, environment + offset, limit, sortField, sortDir, afterExecutionId, environment, + attributeFilters ); } @@ -106,7 +126,8 @@ public record SearchRequest( status, timeFrom, timeTo, durationMin, durationMax, correlationId, text, textInBody, textInHeaders, textInErrors, routeId, instanceId, processorType, applicationId, instanceIds, - offset, limit, sortField, sortDir, afterExecutionId, env + offset, limit, sortField, sortDir, afterExecutionId, env, + attributeFilters ); } @@ -122,7 +143,8 @@ public record SearchRequest( status, ts, timeTo, durationMin, durationMax, correlationId, text, textInBody, textInHeaders, textInErrors, routeId, instanceId, processorType, applicationId, instanceIds, - offset, limit, sortField, sortDir, afterExecutionId, environment + offset, limit, sortField, sortDir, afterExecutionId, environment, + attributeFilters ); } } diff --git a/cameleer-server-core/src/test/java/com/cameleer/server/core/search/AttributeFilterTest.java b/cameleer-server-core/src/test/java/com/cameleer/server/core/search/AttributeFilterTest.java new file mode 100644 index 00000000..db9cd092 --- /dev/null +++ b/cameleer-server-core/src/test/java/com/cameleer/server/core/search/AttributeFilterTest.java @@ -0,0 +1,88 @@ +package com.cameleer.server.core.search; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class AttributeFilterTest { + + @Test + void keyOnly_blankValue_normalizesToNull() { + AttributeFilter f = new AttributeFilter("order", ""); + assertThat(f.value()).isNull(); + assertThat(f.isKeyOnly()).isTrue(); + assertThat(f.isWildcard()).isFalse(); + } + + @Test + void keyOnly_nullValue_isKeyOnly() { + AttributeFilter f = new AttributeFilter("order", null); + assertThat(f.isKeyOnly()).isTrue(); + } + + @Test + void exactValue_isNotWildcard() { + AttributeFilter f = new AttributeFilter("order", "47"); + assertThat(f.isKeyOnly()).isFalse(); + assertThat(f.isWildcard()).isFalse(); + } + + @Test + void starInValue_isWildcard() { + AttributeFilter f = new AttributeFilter("order", "47*"); + assertThat(f.isWildcard()).isTrue(); + } + + @Test + void invalidKey_throws() { + assertThatThrownBy(() -> new AttributeFilter("bad key", "x")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("attribute key"); + } + + @Test + void blankKey_throws() { + assertThatThrownBy(() -> new AttributeFilter(" ", null)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void wildcardPattern_escapesLikeMetaCharacters() { + AttributeFilter f = new AttributeFilter("order", "a_b%c\\d*"); + assertThat(f.toLikePattern()).isEqualTo("a\\_b\\%c\\\\d%"); + } + + @Test + void exactValue_toLikePattern_returnsNull() { + AttributeFilter f = new AttributeFilter("order", "47"); + assertThat(f.toLikePattern()).isNull(); + } + + @Test + void searchRequest_canonicalCtor_acceptsAttributeFilters() { + SearchRequest r = new SearchRequest( + null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, 0, 50, null, null, null, null, + java.util.List.of(new AttributeFilter("order", "47"))); + assertThat(r.attributeFilters()).hasSize(1); + assertThat(r.attributeFilters().get(0).key()).isEqualTo("order"); + } + + @Test + void searchRequest_legacyCtor_defaultsAttributeFiltersToEmpty() { + SearchRequest r = new SearchRequest( + null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, 0, 50, null, null, null, null); + assertThat(r.attributeFilters()).isEmpty(); + } + + @Test + void searchRequest_compactCtor_normalizesNullAttributeFilters() { + SearchRequest r = new SearchRequest( + null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, 0, 50, null, null, null, null, + null); + assertThat(r.attributeFilters()).isNotNull().isEmpty(); + } +} diff --git a/ui/src/api/openapi.json b/ui/src/api/openapi.json index 12de99b7..a873069e 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":"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/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":"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":"Resolves agents in this env for this app, then looks up the latest diagram for the route they reported. Env scope prevents a dev route from returning a prod diagram.","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/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"}}}},"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"}}},"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"}}},"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}}},"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"}}},"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"}}}}}}},"/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 diff --git a/ui/src/api/schema.d.ts b/ui/src/api/schema.d.ts index 50c1a83e..4de70b48 100644 --- a/ui/src/api/schema.d.ts +++ b/ui/src/api/schema.d.ts @@ -1037,6 +1037,26 @@ export interface paths { patch?: never; trace?: never; }; + "/admin/server-metrics/query": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * 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. + */ + post: operations["query"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/admin/roles": { parameters: { query?: never; @@ -1556,7 +1576,7 @@ export interface paths { }; /** * Find the latest diagram for this app's route in this environment - * @description Resolves agents in this env for this app, then looks up the latest diagram for the route they reported. Env scope prevents a dev route from returning a prod diagram. + * @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. */ get: operations["findByAppAndRoute"]; put?: never; @@ -1912,6 +1932,46 @@ export interface paths { patch?: never; trace?: never; }; + "/admin/server-metrics/instances": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List server_instance_id values observed in the window + * @description Returns first/last seen timestamps — use to partition counter-delta computations. + */ + get: operations["instances"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/admin/server-metrics/catalog": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * 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. + */ + get: operations["catalog"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/admin/rbac/stats": { parameters: { query?: never; @@ -2209,6 +2269,17 @@ export interface components { [key: string]: number; }; sensitiveKeys?: string[]; + /** Format: int32 */ + exportBatchSize?: number; + /** Format: int32 */ + exportQueueSize?: number; + /** Format: int64 */ + exportFlushIntervalMs?: number; + exportOverflowMode?: string; + /** Format: int64 */ + exportBlockTimeoutMs?: number; + /** Format: int32 */ + flushRecordThreshold?: number; }; TapDefinition: { tapId?: string; @@ -2630,6 +2701,12 @@ export interface components { /** Format: date-time */ createdAt?: string; }; + AttributeFilter: { + key?: string; + value?: string; + keyOnly?: boolean; + wildcard?: boolean; + }; SearchRequest: { status?: string; /** Format: date-time */ @@ -2658,6 +2735,7 @@ export interface components { sortDir?: string; afterExecutionId?: string; environment?: string; + attributeFilters?: components["schemas"]["AttributeFilter"][]; }; ExecutionSummary: { executionId: string; @@ -2967,6 +3045,42 @@ export interface components { SetPasswordRequest: { password?: string; }; + QueryBody: { + metric?: string; + statistic?: string; + from?: string; + to?: string; + /** Format: int32 */ + stepSeconds?: number; + groupByTags?: string[]; + filterTags?: { + [key: string]: string; + }; + aggregation?: string; + mode?: string; + serverInstanceIds?: string[]; + }; + ServerMetricPoint: { + /** Format: date-time */ + t?: string; + /** Format: double */ + v?: number; + }; + ServerMetricQueryResponse: { + metric?: string; + statistic?: string; + aggregation?: string; + mode?: string; + /** Format: int32 */ + stepSeconds?: number; + series?: components["schemas"]["ServerMetricSeries"][]; + }; + ServerMetricSeries: { + tags?: { + [key: string]: string; + }; + points?: components["schemas"]["ServerMetricPoint"][]; + }; CreateRoleRequest: { name?: string; description?: string; @@ -3491,6 +3605,19 @@ export interface components { /** Format: int64 */ avgDurationMs?: number; }; + ServerInstanceInfo: { + serverInstanceId?: string; + /** Format: date-time */ + firstSeen?: string; + /** Format: date-time */ + lastSeen?: string; + }; + ServerMetricCatalogEntry: { + metricName?: string; + metricType?: string; + statistics?: string[]; + tagKeys?: string[]; + }; SensitiveKeysConfig: { keys?: string[]; }; @@ -6246,6 +6373,30 @@ export interface operations { }; }; }; + query: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["QueryBody"]; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "*/*": components["schemas"]["ServerMetricQueryResponse"]; + }; + }; + }; + }; listRoles: { parameters: { query?: never; @@ -7068,6 +7219,7 @@ export interface operations { agentId?: string; processorType?: string; application?: string; + attr?: string[]; offset?: number; limit?: number; sortField?: string; @@ -7822,6 +7974,52 @@ export interface operations { }; }; }; + instances: { + parameters: { + query?: { + from?: string; + to?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "*/*": components["schemas"]["ServerInstanceInfo"][]; + }; + }; + }; + }; + catalog: { + parameters: { + query?: { + from?: string; + to?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "*/*": components["schemas"]["ServerMetricCatalogEntry"][]; + }; + }; + }; + }; getStats: { parameters: { query?: never; diff --git a/ui/src/components/LayoutShell.tsx b/ui/src/components/LayoutShell.tsx index 6742857a..b0115ff1 100644 --- a/ui/src/components/LayoutShell.tsx +++ b/ui/src/components/LayoutShell.tsx @@ -44,6 +44,7 @@ import { EnvironmentSwitcherModal } from './EnvironmentSwitcherModal'; import { envColorVar } from './env-colors'; import { useScope } from '../hooks/useScope'; import { formatDuration } from '../utils/format-utils'; +import { parseFacetQuery, formatAttrParam } from '../utils/attribute-filter'; import { buildAppTreeNodes, buildAdminTreeNodes, @@ -111,7 +112,11 @@ function buildSearchData( id: `attr-key-${key}`, category: 'attribute', title: key, - meta: 'attribute key', + meta: 'attribute key — filter list', + // Path carries the facet in query-string form; handlePaletteSelect routes + // attribute results to the current scope, so the leading segment below is + // only used as a fallback when no scope is active. + path: `/exchanges?attr=${encodeURIComponent(key)}`, }); } } @@ -690,7 +695,19 @@ function LayoutContent() { } } - return [...catalogRef.current, ...exchangeItems, ...attributeItems, ...alertingSearchData]; + const facet = parseFacetQuery(debouncedQuery ?? ''); + const facetItems: SearchResult[] = + facet + ? [{ + id: `facet-${formatAttrParam(facet)}`, + category: 'attribute' as const, + title: `Filter: ${facet.key} = "${facet.value}"${facet.value?.includes('*') ? ' (wildcard)' : ''}`, + meta: 'apply attribute filter', + path: `/exchanges?attr=${encodeURIComponent(formatAttrParam(facet))}`, + }] + : []; + + return [...facetItems, ...catalogRef.current, ...exchangeItems, ...attributeItems, ...alertingSearchData]; }, [isAdminPage, catalogRef.current, exchangeResults, debouncedQuery, alertingSearchData]); const searchData = isAdminPage ? adminSearchData : operationalSearchData; @@ -744,6 +761,32 @@ function LayoutContent() { setPaletteOpen(false); return; } + + if (result.category === 'attribute') { + // Three sources feed 'attribute' results: + // - buildSearchData → id `attr-key-` (key-only) + // - operationalSearchData per-exchange → id `-attr-`, title `key = "value"` + // - synthetic facet (Task 9) → id `facet-` where is already + // the URL `attr=` form (`key` or `key:value`) + let attrParam: string | null = null; + if (typeof result.id === 'string' && result.id.startsWith('attr-key-')) { + attrParam = result.id.substring('attr-key-'.length); + } else if (typeof result.id === 'string' && result.id.startsWith('facet-')) { + attrParam = result.id.substring('facet-'.length); + } else if (typeof result.title === 'string') { + const m = /^([a-zA-Z0-9._-]+)\s*=\s*"([^"]*)"/.exec(result.title); + if (m) attrParam = `${m[1]}:${m[2]}`; + } + if (attrParam) { + const base = ['/exchanges']; + if (scope.appId) base.push(scope.appId); + if (scope.routeId) base.push(scope.routeId); + navigate(`${base.join('/')}?attr=${encodeURIComponent(attrParam)}`); + } + setPaletteOpen(false); + return; + } + if (result.path) { if (ADMIN_CATEGORIES.has(result.category)) { const itemId = result.id.split(':').slice(1).join(':'); @@ -752,7 +795,7 @@ function LayoutContent() { }); } else { const state: Record = { sidebarReveal: result.path }; - if (result.category === 'exchange' || result.category === 'attribute') { + if (result.category === 'exchange') { const parts = result.path.split('/').filter(Boolean); if (parts.length === 4 && parts[0] === 'exchanges') { state.selectedExchange = { @@ -766,7 +809,7 @@ function LayoutContent() { } } setPaletteOpen(false); - }, [navigate, setPaletteOpen]); + }, [navigate, setPaletteOpen, scope.appId, scope.routeId]); const handlePaletteSubmit = useCallback((query: string) => { if (isAdminPage) { @@ -780,12 +823,18 @@ function LayoutContent() { } else { navigate('/admin/rbac'); } - } else { - const baseParts = ['/exchanges']; - if (scope.appId) baseParts.push(scope.appId); - if (scope.routeId) baseParts.push(scope.routeId); - navigate(`${baseParts.join('/')}?text=${encodeURIComponent(query)}`); + return; } + + const facet = parseFacetQuery(query); + const baseParts = ['/exchanges']; + if (scope.appId) baseParts.push(scope.appId); + if (scope.routeId) baseParts.push(scope.routeId); + if (facet) { + navigate(`${baseParts.join('/')}?attr=${encodeURIComponent(formatAttrParam(facet))}`); + return; + } + navigate(`${baseParts.join('/')}?text=${encodeURIComponent(query)}`); }, [isAdminPage, adminSearchData, handlePaletteSelect, navigate, scope.appId, scope.routeId]); const handleSidebarNavigate = useCallback((path: string) => { diff --git a/ui/src/pages/Dashboard/Dashboard.module.css b/ui/src/pages/Dashboard/Dashboard.module.css index 63d4d9dd..610beb90 100644 --- a/ui/src/pages/Dashboard/Dashboard.module.css +++ b/ui/src/pages/Dashboard/Dashboard.module.css @@ -139,3 +139,23 @@ color: var(--text-muted); } +.attrChip { + display: inline-flex; + align-items: center; + gap: 4px; + margin-left: 8px; + padding: 2px 8px; + background: var(--bg-hover); + border: 1px solid var(--border); + border-radius: 10px; + font-size: 11px; + font-family: var(--font-mono); + color: var(--text-primary); +} + +.attrChip code { + background: transparent; + font-family: inherit; + color: var(--text-primary); +} + diff --git a/ui/src/pages/Dashboard/Dashboard.tsx b/ui/src/pages/Dashboard/Dashboard.tsx index 65ec6ba7..bf9efa9a 100644 --- a/ui/src/pages/Dashboard/Dashboard.tsx +++ b/ui/src/pages/Dashboard/Dashboard.tsx @@ -15,6 +15,8 @@ import { import { useEnvironmentStore } from '../../api/environment-store' import type { ExecutionSummary } from '../../api/types' import { attributeBadgeColor } from '../../utils/attribute-color' +import { parseAttrParam, formatAttrParam } from '../../utils/attribute-filter'; +import type { AttributeFilter } from '../../utils/attribute-filter'; import { formatDuration, statusLabel } from '../../utils/format-utils' import styles from './Dashboard.module.css' import tableStyles from '../../styles/table-section.module.css' @@ -84,7 +86,7 @@ function buildColumns(hasAttributes: boolean): Column[] {

{shown.map(([k, v]) => ( - + ))} {overflow > 0 && +{overflow}} @@ -147,6 +149,12 @@ export default function Dashboard({ onExchangeSelect, activeExchangeId }: Dashbo const navigate = useNavigate() const [searchParams, setSearchParams] = useSearchParams() const textFilter = searchParams.get('text') || undefined + const attributeFilters = useMemo( + () => searchParams.getAll('attr') + .map(parseAttrParam) + .filter((f): f is AttributeFilter => f != null), + [searchParams], + ); const [selectedId, setSelectedId] = useState(activeExchangeId) const [sortField, setSortField] = useState('startTime') const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc') @@ -180,12 +188,13 @@ export default function Dashboard({ onExchangeSelect, activeExchangeId }: Dashbo environment: selectedEnv, status: statusParam, text: textFilter, + attributeFilters: attributeFilters.length > 0 ? attributeFilters : undefined, sortField, sortDir, offset: 0, - limit: textFilter ? 200 : 50, + limit: textFilter || attributeFilters.length > 0 ? 200 : 50, }, - !textFilter, + !textFilter && attributeFilters.length === 0, ) // ─── Rows ──────────────────────────────────────────────────────────────── @@ -221,17 +230,46 @@ export default function Dashboard({ onExchangeSelect, activeExchangeId }: Dashbo
- {textFilter ? ( + {textFilter || attributeFilters.length > 0 ? ( <> - Search: “{textFilter}” - + {textFilter && ( + <> + Search: “{textFilter}” + + + )} + {attributeFilters.map((f, i) => ( + + {f.value === undefined + ? <>has {f.key} + : <>{f.key} = {f.value}} + + + ))} ) : 'Recent Exchanges'} @@ -239,7 +277,7 @@ export default function Dashboard({ onExchangeSelect, activeExchangeId }: Dashbo {rows.length.toLocaleString()} of {(searchResult?.total ?? 0).toLocaleString()} exchanges - {!textFilter && } + {!textFilter && attributeFilters.length === 0 && }
diff --git a/ui/src/utils/attribute-filter.test.ts b/ui/src/utils/attribute-filter.test.ts new file mode 100644 index 00000000..fbb8b23f --- /dev/null +++ b/ui/src/utils/attribute-filter.test.ts @@ -0,0 +1,69 @@ +import { describe, it, expect } from 'vitest'; +import { parseAttrParam, formatAttrParam, parseFacetQuery } from './attribute-filter'; + +describe('parseAttrParam', () => { + it('returns key-only for input without colon', () => { + expect(parseAttrParam('order')).toEqual({ key: 'order' }); + }); + + it('splits on first colon, trims key, preserves value as-is', () => { + expect(parseAttrParam('order:47')).toEqual({ key: 'order', value: '47' }); + }); + + it('treats a value containing colons as a single value', () => { + expect(parseAttrParam('trace-id:abc:123')).toEqual({ key: 'trace-id', value: 'abc:123' }); + }); + + it('returns null for blank input', () => { + expect(parseAttrParam('')).toBeNull(); + expect(parseAttrParam(' ')).toBeNull(); + }); + + it('returns null for missing key', () => { + expect(parseAttrParam(':x')).toBeNull(); + }); + + it('returns null when the key contains invalid characters', () => { + expect(parseAttrParam('bad key:1')).toBeNull(); + }); +}); + +describe('formatAttrParam', () => { + it('returns bare key for key-only filter', () => { + expect(formatAttrParam({ key: 'order' })).toBe('order'); + }); + + it('joins with colon when value is present', () => { + expect(formatAttrParam({ key: 'order', value: '47' })).toBe('order:47'); + }); + + it('joins with colon when value is empty string', () => { + expect(formatAttrParam({ key: 'order', value: '' })).toBe('order:'); + }); +}); + +describe('parseFacetQuery', () => { + it('matches `key: value`', () => { + expect(parseFacetQuery('order: 47')).toEqual({ key: 'order', value: '47' }); + }); + + it('matches `key:value` without spaces', () => { + expect(parseFacetQuery('order:47')).toEqual({ key: 'order', value: '47' }); + }); + + it('matches wildcard values', () => { + expect(parseFacetQuery('order: 4*')).toEqual({ key: 'order', value: '4*' }); + }); + + it('returns null when the key contains invalid characters', () => { + expect(parseFacetQuery('bad key: 1')).toBeNull(); + }); + + it('returns null without a colon', () => { + expect(parseFacetQuery('order')).toBeNull(); + }); + + it('returns null with an empty value side', () => { + expect(parseFacetQuery('order: ')).toBeNull(); + }); +}); diff --git a/ui/src/utils/attribute-filter.ts b/ui/src/utils/attribute-filter.ts new file mode 100644 index 00000000..b291df11 --- /dev/null +++ b/ui/src/utils/attribute-filter.ts @@ -0,0 +1,37 @@ +export interface AttributeFilter { + key: string; + value?: string; +} + +const KEY_REGEX = /^[a-zA-Z0-9._-]+$/; + +/** Parses a single `?attr=` URL value. Returns null for invalid / blank input. */ +export function parseAttrParam(raw: string): AttributeFilter | null { + if (!raw) return null; + const trimmed = raw.trim(); + if (trimmed.length === 0) return null; + + const colon = trimmed.indexOf(':'); + if (colon < 0) { + return KEY_REGEX.test(trimmed) ? { key: trimmed } : null; + } + + const key = trimmed.substring(0, colon).trim(); + const value = raw.substring(raw.indexOf(':') + 1); + if (!KEY_REGEX.test(key)) return null; + return { key, value }; +} + +/** Serialises an AttributeFilter back to a URL `?attr=` value. */ +export function formatAttrParam(f: AttributeFilter): string { + return f.value === undefined ? f.key : `${f.key}:${f.value}`; +} + +const FACET_REGEX = /^\s*([a-zA-Z0-9._-]+)\s*:\s*(\S(?:.*\S)?)\s*$/; + +/** Parses a cmd-k query like `order: 47` into a facet descriptor. */ +export function parseFacetQuery(query: string): AttributeFilter | null { + const m = FACET_REGEX.exec(query); + if (!m) return null; + return { key: m[1], value: m[2] }; +}