diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DetailController.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DetailController.java
new file mode 100644
index 00000000..a47a19d6
--- /dev/null
+++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DetailController.java
@@ -0,0 +1,54 @@
+package com.cameleer3.server.app.controller;
+
+import com.cameleer3.server.app.storage.ClickHouseExecutionRepository;
+import com.cameleer3.server.core.detail.DetailService;
+import com.cameleer3.server.core.detail.ExecutionDetail;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+/**
+ * Endpoints for retrieving execution details and processor snapshots.
+ *
+ * The detail endpoint returns a nested processor tree reconstructed from
+ * flat parallel arrays stored in ClickHouse. The snapshot endpoint returns
+ * per-processor exchange data (bodies and headers).
+ */
+@RestController
+@RequestMapping("/api/v1/executions")
+@Tag(name = "Detail", description = "Execution detail and processor snapshot endpoints")
+public class DetailController {
+
+ private final DetailService detailService;
+ private final ClickHouseExecutionRepository executionRepository;
+
+ public DetailController(DetailService detailService,
+ ClickHouseExecutionRepository executionRepository) {
+ this.detailService = detailService;
+ this.executionRepository = executionRepository;
+ }
+
+ @GetMapping("/{executionId}")
+ @Operation(summary = "Get execution detail with nested processor tree")
+ public ResponseEntity getDetail(@PathVariable String executionId) {
+ return detailService.getDetail(executionId)
+ .map(ResponseEntity::ok)
+ .orElse(ResponseEntity.notFound().build());
+ }
+
+ @GetMapping("/{executionId}/processors/{index}/snapshot")
+ @Operation(summary = "Get exchange snapshot for a specific processor")
+ public ResponseEntity