---
phase: 02-transaction-search-diagrams
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
- cameleer-server-app/pom.xml
- cameleer-server-core/src/main/java/com/cameleer/server/core/diagram/DiagramRenderer.java
- cameleer-server-core/src/main/java/com/cameleer/server/core/diagram/DiagramLayout.java
- cameleer-server-core/src/main/java/com/cameleer/server/core/diagram/PositionedNode.java
- cameleer-server-core/src/main/java/com/cameleer/server/core/diagram/PositionedEdge.java
- cameleer-server-app/src/main/java/com/cameleer/server/app/diagram/ElkDiagramRenderer.java
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DiagramRenderController.java
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/DiagramBeanConfig.java
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramRenderControllerIT.java
- cameleer-server-app/src/test/java/com/cameleer/server/app/diagram/ElkDiagramRendererTest.java
autonomous: true
requirements:
- DIAG-03
must_haves:
truths:
- "GET /api/v1/diagrams/{hash} with Accept: image/svg+xml returns an SVG document with color-coded nodes"
- "GET /api/v1/diagrams/{hash} with Accept: application/json returns a JSON layout with node positions"
- "Nodes are laid out top-to-bottom using ELK layered algorithm"
- "Node colors match the route-diagram-example.html style: blue endpoints, green processors, red error handlers, purple EIPs"
- "Nested processors (inside split, choice, try-catch) are rendered in compound/swimlane groups"
artifacts:
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/diagram/DiagramRenderer.java"
provides: "Renderer interface for SVG and JSON layout output"
exports: ["DiagramRenderer"]
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/diagram/ElkDiagramRenderer.java"
provides: "ELK + JFreeSVG implementation of DiagramRenderer"
min_lines: 100
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DiagramRenderController.java"
provides: "GET /api/v1/diagrams/{hash} with content negotiation"
exports: ["DiagramRenderController"]
key_links:
- from: "DiagramRenderController"
to: "DiagramRepository"
via: "findByContentHash to load RouteGraph"
pattern: "findByContentHash"
- from: "DiagramRenderController"
to: "DiagramRenderer"
via: "renderSvg or layoutJson based on Accept header"
pattern: "renderSvg|layoutJson"
- from: "ElkDiagramRenderer"
to: "ELK RecursiveGraphLayoutEngine"
via: "layout computation"
pattern: "RecursiveGraphLayoutEngine"
---
Implement route diagram rendering with Eclipse ELK for layout and JFreeSVG for SVG output, exposed via a REST endpoint with content negotiation.
Purpose: Users need to visualize route diagrams from stored RouteGraph definitions. The server renders color-coded, top-to-bottom SVG diagrams or returns JSON layout data for client-side rendering. This is independent of the search work and can run in parallel.
Output: DiagramRenderer interface in core, ElkDiagramRenderer implementation in app, DiagramRenderController with Accept header content negotiation, integration and unit tests.
@C:/Users/Hendrik/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/Hendrik/.claude/get-shit-done/templates/summary.md
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/02-transaction-search-diagrams/02-CONTEXT.md
@.planning/phases/02-transaction-search-diagrams/02-RESEARCH.md
@cameleer-server-core/src/main/java/com/cameleer/server/core/storage/DiagramRepository.java
@cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseDiagramRepository.java
@cameleer-server-app/pom.xml
From cameleer-server-core/.../storage/DiagramRepository.java:
```java
public interface DiagramRepository {
void store(RouteGraph graph);
Optional findByContentHash(String contentHash);
Optional findContentHashForRoute(String routeId, String agentId);
}
```
From cameleer-common (decompiled — diagram models):
```java
// RouteGraph: routeId (String), nodes (List), edges (List),
// processorNodeMapping (Map)
// RouteNode: id (String), label (String), type (NodeType), properties (Map)
// RouteEdge: source (String), target (String), label (String)
// NodeType enum: ENDPOINT, TO, TO_DYNAMIC, DIRECT, SEDA, PROCESSOR, BEAN, LOG,
// SET_HEADER, SET_BODY, TRANSFORM, MARSHAL, UNMARSHAL, CHOICE, WHEN, OTHERWISE,
// SPLIT, AGGREGATE, MULTICAST, FILTER, RECIPIENT_LIST, ROUTING_SLIP, DYNAMIC_ROUTER,
// LOAD_BALANCE, THROTTLE, DELAY, ERROR_HANDLER, ON_EXCEPTION, TRY_CATCH, DO_TRY,
// DO_CATCH, DO_FINALLY, WIRE_TAP, ENRICH, POLL_ENRICH, SORT, RESEQUENCE,
// IDEMPOTENT_CONSUMER, CIRCUIT_BREAKER, SAGA, LOOP
```
NodeType color mapping (from CONTEXT.md, matching route-diagram-example.html):
- Blue (#3B82F6): ENDPOINT, TO, TO_DYNAMIC, DIRECT, SEDA (endpoints)
- Green (#22C55E): PROCESSOR, BEAN, LOG, SET_HEADER, SET_BODY, TRANSFORM, MARSHAL, UNMARSHAL (processors)
- Red (#EF4444): ERROR_HANDLER, ON_EXCEPTION, TRY_CATCH, DO_TRY, DO_CATCH, DO_FINALLY (error handling)
- Purple (#A855F7): CHOICE, WHEN, OTHERWISE, SPLIT, AGGREGATE, MULTICAST, FILTER, etc. (EIP patterns)
- Cyan (#06B6D4): WIRE_TAP, ENRICH, POLL_ENRICH (cross-route)
Task 1: Add ELK/JFreeSVG dependencies and create core diagram rendering interfaces
cameleer-server-app/pom.xml,
cameleer-server-core/src/main/java/com/cameleer/server/core/diagram/DiagramRenderer.java,
cameleer-server-core/src/main/java/com/cameleer/server/core/diagram/DiagramLayout.java,
cameleer-server-core/src/main/java/com/cameleer/server/core/diagram/PositionedNode.java,
cameleer-server-core/src/main/java/com/cameleer/server/core/diagram/PositionedEdge.java
1. Add Maven dependencies to `cameleer-server-app/pom.xml`:
```xml
org.eclipse.elkorg.eclipse.elk.core0.11.0org.eclipse.elkorg.eclipse.elk.alg.layered0.11.0org.jfreeorg.jfree.svg5.0.7
```
2. Create core diagram rendering interfaces in `com.cameleer.server.core.diagram`:
- `PositionedNode` record: id (String), label (String), type (String — NodeType name), x (double), y (double), width (double), height (double), children (List — for compound/swimlane groups). JSON-serializable for the JSON layout response.
- `PositionedEdge` record: sourceId (String), targetId (String), label (String), points (List — waypoints for edge routing). The points list contains [x,y] pairs from source to target.
- `DiagramLayout` record: width (double), height (double), nodes (List), edges (List). This is the JSON layout response format.
- `DiagramRenderer` interface with two methods:
- `String renderSvg(RouteGraph graph)` — returns SVG XML string
- `DiagramLayout layoutJson(RouteGraph graph)` — returns positioned layout data
Both methods take a RouteGraph and produce output. The interface lives in core so it can be swapped (e.g., for a different renderer).
cd C:/Users/Hendrik/Documents/projects/cameleer-server && mvn compile -pl cameleer-server-core && mvn dependency:resolve -pl cameleer-server-app -qELK and JFreeSVG dependencies resolve, DiagramRenderer interface and layout DTOs compile in core moduleTask 2: Implement ElkDiagramRenderer, DiagramRenderController, and integration tests
cameleer-server-app/src/main/java/com/cameleer/server/app/diagram/ElkDiagramRenderer.java,
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DiagramRenderController.java,
cameleer-server-app/src/main/java/com/cameleer/server/app/config/DiagramBeanConfig.java,
cameleer-server-app/src/test/java/com/cameleer/server/app/diagram/ElkDiagramRendererTest.java,
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramRenderControllerIT.java
- Unit test: ElkDiagramRenderer.renderSvg with a simple 3-node graph (from->process->to) produces valid SVG containing svg element, rect elements for nodes, line/path elements for edges
- Unit test: ElkDiagramRenderer.renderSvg produces SVG where endpoint nodes have blue fill (#3B82F6 or rgb equivalent)
- Unit test: ElkDiagramRenderer.layoutJson returns DiagramLayout with correct node count and positive coordinates
- Unit test: Nested processors (e.g., CHOICE with WHEN children) are laid out as compound nodes with children inside parent bounds
- Integration test: GET /api/v1/diagrams/{hash} with Accept: image/svg+xml returns 200 with content-type image/svg+xml and body starting with '
- `mvn test -pl cameleer-server-app -Dtest=ElkDiagramRendererTest` passes (unit tests for layout and SVG)
- `mvn test -pl cameleer-server-app -Dtest=DiagramRenderControllerIT` passes (integration tests for REST endpoint)
- `mvn clean verify` passes (all existing tests still green)
- SVG output contains color-coded nodes matching the NodeType color scheme
- GET /api/v1/diagrams/{hash}/render returns SVG with color-coded nodes (blue endpoints, green processors, red error handlers, purple EIPs, cyan cross-route)
- GET /api/v1/diagrams/{hash}/render with Accept: application/json returns JSON layout with node positions
- Nodes laid out top-to-bottom via ELK layered algorithm
- Compound nodes group nested processors (CHOICE/WHEN, TRY/CATCH) in swimlane containers
- Non-existent hash returns 404
- Default (no Accept header) returns SVG