From 0995ab35c4b30595d6ea9b5c5b3fd1e128aae309 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Thu, 23 Apr 2026 19:01:19 +0200 Subject: [PATCH] fix(catalog): preserve fromEndpointUri for removed routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both catalog controllers resolved the from-endpoint URI via findContentHashForRouteByAgents, which filtered by the currently-live agent instance_ids. Routes removed between app versions therefore lost their fromUri even though the diagram row still exists. Route through findLatestContentHashForAppRoute so resolution depends only on (app, env, route) — stays populated for historical routes. CatalogController now resolves the per-row env slug up-front so the fromUri lookup works even for cross-env queries against managed apps. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../app/controller/CatalogController.java | 28 +++++++++++-------- .../controller/RouteCatalogController.java | 7 ++--- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/CatalogController.java b/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/CatalogController.java index 7fd2f1be..60b2b8fe 100644 --- a/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/CatalogController.java +++ b/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/CatalogController.java @@ -196,7 +196,16 @@ public class CatalogController { } Set routeIds = routesByApp.getOrDefault(slug, Set.of()); - List agentIds = agents.stream().map(AgentInfo::instanceId).toList(); + + // Resolve the env slug for this row early so fromUri can survive + // cross-env queries (env==null) against managed apps. + String rowEnvSlug = envSlug; + if (app != null && rowEnvSlug.isEmpty()) { + try { + rowEnvSlug = envService.getById(app.environmentId()).slug(); + } catch (Exception ignored) {} + } + final String resolvedEnvSlug = rowEnvSlug; // Routes List routeSummaries = routeIds.stream() @@ -204,7 +213,7 @@ public class CatalogController { String key = slug + "/" + routeId; long count = routeExchangeCounts.getOrDefault(key, 0L); Instant lastSeen = routeLastSeen.get(key); - String fromUri = resolveFromEndpointUri(routeId, agentIds); + String fromUri = resolveFromEndpointUri(slug, routeId, resolvedEnvSlug); String state = routeStateRegistry.getState(slug, routeId).name().toLowerCase(); String routeState = "started".equals(state) ? null : state; return new RouteSummary(routeId, count, lastSeen, fromUri, routeState); @@ -258,15 +267,9 @@ public class CatalogController { String healthTooltip = buildHealthTooltip(app != null, deployStatus, agentHealth, agents.size()); String displayName = app != null ? app.displayName() : slug; - String appEnvSlug = envSlug; - if (app != null && appEnvSlug.isEmpty()) { - try { - appEnvSlug = envService.getById(app.environmentId()).slug(); - } catch (Exception ignored) {} - } catalog.add(new CatalogApp( - slug, displayName, app != null, appEnvSlug, + slug, displayName, app != null, resolvedEnvSlug, health, healthTooltip, agents.size(), routeSummaries, agentSummaries, totalExchanges, deploymentSummary )); @@ -275,8 +278,11 @@ public class CatalogController { return ResponseEntity.ok(catalog); } - private String resolveFromEndpointUri(String routeId, List agentIds) { - return diagramStore.findContentHashForRouteByAgents(routeId, agentIds) + private String resolveFromEndpointUri(String applicationId, String routeId, String environment) { + if (environment == null || environment.isBlank()) { + return null; + } + return diagramStore.findLatestContentHashForAppRoute(applicationId, routeId, environment) .flatMap(diagramStore::findByContentHash) .map(RouteGraph::getRoot) .map(root -> root.getEndpointUri()) diff --git a/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/RouteCatalogController.java b/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/RouteCatalogController.java index 96bd415a..d4407810 100644 --- a/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/RouteCatalogController.java +++ b/cameleer-server-app/src/main/java/com/cameleer/server/app/controller/RouteCatalogController.java @@ -132,13 +132,12 @@ public class RouteCatalogController { List agents = agentsByApp.getOrDefault(appId, List.of()); Set routeIds = routesByApp.getOrDefault(appId, Set.of()); - List agentIds = agents.stream().map(AgentInfo::instanceId).toList(); List routeSummaries = routeIds.stream() .map(routeId -> { String key = appId + "/" + routeId; long count = routeExchangeCounts.getOrDefault(key, 0L); Instant lastSeen = routeLastSeen.get(key); - String fromUri = resolveFromEndpointUri(routeId, agentIds); + String fromUri = resolveFromEndpointUri(appId, routeId, envSlug); String state = routeStateRegistry.getState(appId, routeId).name().toLowerCase(); String routeState = "started".equals(state) ? null : state; return new RouteSummary(routeId, count, lastSeen, fromUri, routeState); @@ -160,8 +159,8 @@ public class RouteCatalogController { return ResponseEntity.ok(catalog); } - private String resolveFromEndpointUri(String routeId, List agentIds) { - return diagramStore.findContentHashForRouteByAgents(routeId, agentIds) + private String resolveFromEndpointUri(String applicationId, String routeId, String environment) { + return diagramStore.findLatestContentHashForAppRoute(applicationId, routeId, environment) .flatMap(diagramStore::findByContentHash) .map(RouteGraph::getRoot) .map(root -> root.getEndpointUri())