---
phase: 02-transaction-search-diagrams
plan: 02
subsystem: api
tags: [elk, jfreesvg, svg, diagram, layout, content-negotiation]

requires:
  - phase: 01-ingestion-pipeline
    provides: DiagramRepository with findByContentHash for loading RouteGraph definitions
provides:
  - DiagramRenderer interface in core module for SVG and JSON layout output
  - ElkDiagramRenderer implementation using ELK layered algorithm and JFreeSVG
  - DiagramRenderController with Accept header content negotiation
  - Color-coded node rendering matching route-diagram-example.html style
  - Compound node support for nested processors (CHOICE, SPLIT, TRY_CATCH)
affects: [02-03, ui-rendering, execution-overlay]

tech-stack:
  added: [org.eclipse.elk.core:0.11.0, org.eclipse.elk.alg.layered:0.11.0, org.jfree.svg:5.0.7, org.eclipse.xtext.xbase.lib:2.37.0]
  patterns: [ELK graph construction, JFreeSVG rendering, manual Accept header content negotiation]

key-files:
  created:
    - 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/diagram/ElkDiagramRendererTest.java
    - cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramRenderControllerIT.java
  modified:
    - cameleer-server-app/pom.xml

key-decisions:
  - "Used ELK layered algorithm with top-to-bottom direction for route diagram layout"
  - "JFreeSVG for server-side SVG generation (lightweight, no Batik dependency)"
  - "Manual Accept header parsing for content negotiation -- JSON only when first preference, SVG as default"
  - "Added xtext xbase lib runtime dependency required by ELK 0.11.0 LayeredMetaDataProvider"
  - "Compound nodes detected via RouteNode.children rather than edge topology analysis"

patterns-established:
  - "DiagramRenderer interface in core, implementation in app -- swappable rendering backend"
  - "Accept header content negotiation: check first media type preference, default to SVG"
  - "NodeType color mapping via EnumSet groupings for efficient lookup"

requirements-completed: [DIAG-03]

duration: 14min
completed: 2026-03-11
---

# Phase 2 Plan 2: Diagram Rendering Summary

**ELK-based route diagram rendering with color-coded SVG output, JSON layout API, and compound node swimlanes via content-negotiated REST endpoint**

## Performance

- **Duration:** 14 min
- **Started:** 2026-03-11T15:03:12Z
- **Completed:** 2026-03-11T15:17:22Z
- **Tasks:** 2
- **Files modified:** 10

## Accomplishments
- Route diagrams render as color-coded top-to-bottom SVG with ELK layered algorithm
- JSON layout API returns positioned nodes and edges for client-side rendering
- Compound nodes (CHOICE, SPLIT, TRY_CATCH) render in swimlane containers with children
- Content negotiation: Accept: application/json returns JSON, everything else defaults to SVG
- 11 unit tests and 4 integration tests verify layout, colors, content types, and 404 handling

## Task Commits

Each task was committed atomically:

1. **Task 1: Add ELK/JFreeSVG dependencies and create core diagram rendering interfaces** - `6df7450` (feat)
2. **Task 2: Implement ElkDiagramRenderer, DiagramRenderController, and integration tests** - `c1bc32d` (feat, TDD)

## Files Created/Modified
- `cameleer-server-core/.../diagram/DiagramRenderer.java` - Renderer interface with renderSvg and layoutJson
- `cameleer-server-core/.../diagram/DiagramLayout.java` - Layout record (width, height, nodes, edges)
- `cameleer-server-core/.../diagram/PositionedNode.java` - Node record with position, dimensions, children
- `cameleer-server-core/.../diagram/PositionedEdge.java` - Edge record with waypoints
- `cameleer-server-app/.../diagram/ElkDiagramRenderer.java` - ELK + JFreeSVG implementation (~400 lines)
- `cameleer-server-app/.../controller/DiagramRenderController.java` - GET /api/v1/diagrams/{hash}/render
- `cameleer-server-app/.../config/DiagramBeanConfig.java` - Spring bean wiring for DiagramRenderer
- `cameleer-server-app/pom.xml` - Added ELK, JFreeSVG, xtext dependencies
- `cameleer-server-app/.../diagram/ElkDiagramRendererTest.java` - 11 unit tests
- `cameleer-server-app/.../controller/DiagramRenderControllerIT.java` - 4 integration tests

## Decisions Made
- Used ELK layered algorithm (org.eclipse.elk.alg.layered) -- well-maintained, supports compound nodes natively
- JFreeSVG over Batik -- lightweight, no transitive dependency bloat, sufficient for server-side SVG generation
- Manual Accept header parsing instead of Spring content negotiation -- simpler, avoids Spring's default JSON preference when Accept includes wildcards
- Added xtext xbase lib as runtime dependency -- ELK 0.11.0's LayeredMetaDataProvider references CollectionLiterals at class init time
- Compound node children detected from RouteNode.getChildren() rather than edge topology -- cleaner and matches the agent's graph model

## Deviations from Plan

### Auto-fixed Issues

**1. [Rule 3 - Blocking] Added xtext xbase lib dependency for ELK compatibility**
- **Found during:** Task 2 (ElkDiagramRenderer implementation)
- **Issue:** ELK 0.11.0 LayeredMetaDataProvider references org.eclipse.xtext.xbase.lib.CollectionLiterals at class initialization, causing NoClassDefFoundError
- **Fix:** Added org.eclipse.xtext:org.eclipse.xtext.xbase.lib:2.37.0 dependency to app pom.xml
- **Files modified:** cameleer-server-app/pom.xml
- **Verification:** All unit tests pass after adding dependency
- **Committed in:** c1bc32d (Task 2 commit)

**2. [Rule 1 - Bug] Fixed content negotiation default format**
- **Found during:** Task 2 (integration test for default Accept header)
- **Issue:** TestRestTemplate sends Accept: text/plain, application/json, */* by default; simple contains("application/json") check returned JSON instead of SVG
- **Fix:** Changed to check only the first media type in Accept header -- JSON only when explicitly first preference
- **Files modified:** DiagramRenderController.java
- **Verification:** Integration test getWithNoAcceptHeader_defaultsToSvg passes
- **Committed in:** c1bc32d (Task 2 commit)

**3. [Rule 1 - Bug] Adapted to actual NodeType enum naming (EIP_ prefix)**
- **Found during:** Task 2 (ElkDiagramRenderer implementation)
- **Issue:** Plan referenced CHOICE, SPLIT etc. but actual enum values are EIP_CHOICE, EIP_SPLIT etc.
- **Fix:** Used correct enum names from decompiled cameleer-common jar in all color mapping sets
- **Files modified:** ElkDiagramRenderer.java
- **Verification:** Unit tests verify correct colors for endpoint and processor nodes
- **Committed in:** c1bc32d (Task 2 commit)

---

**Total deviations:** 3 auto-fixed (2 bugs, 1 blocking dependency)
**Impact on plan:** All auto-fixes necessary for correctness. No scope creep.

## Issues Encountered
- ELK 0.11.0 has an undeclared runtime dependency on xtext xbase lib -- resolved by adding explicit dependency
- RouteEdge.EdgeType uses FLOW/BRANCH/ERROR/CROSS_ROUTE (not NORMAL as plan implied) -- adapted tests accordingly

## User Setup Required
None - no external service configuration required.

## Next Phase Readiness
- Diagram rendering complete, ready for execution overlay in UI (v2)
- DiagramRenderer interface can be swapped for alternative implementations
- JSON layout format suitable for client-side interactive rendering

---
*Phase: 02-transaction-search-diagrams*
*Completed: 2026-03-11*
