chore: rename cameleer3 to cameleer
Rename Java packages from com.cameleer3 to com.cameleer, module directories from cameleer3-* to cameleer-*, and all references throughout workflows, Dockerfiles, docs, migrations, and pom.xml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,18 +6,18 @@ wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- pom.xml
|
||||
- cameleer3-server-core/pom.xml
|
||||
- cameleer3-server-app/pom.xml
|
||||
- cameleer-server-core/pom.xml
|
||||
- cameleer-server-app/pom.xml
|
||||
- docker-compose.yml
|
||||
- clickhouse/init/01-schema.sql
|
||||
- cameleer3-server-app/src/main/resources/application.yml
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/ClickHouseConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/IngestionConfig.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/WriteBuffer.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/ExecutionRepository.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/DiagramRepository.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/MetricsRepository.java
|
||||
- cameleer3-server-core/src/test/java/com/cameleer3/server/core/ingestion/WriteBufferTest.java
|
||||
- cameleer-server-app/src/main/resources/application.yml
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/ClickHouseConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/IngestionConfig.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/WriteBuffer.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/storage/ExecutionRepository.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/storage/DiagramRepository.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/storage/MetricsRepository.java
|
||||
- cameleer-server-core/src/test/java/com/cameleer/server/core/ingestion/WriteBufferTest.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- INGST-04
|
||||
@@ -32,7 +32,7 @@ must_haves:
|
||||
- "TTL clause on tables removes data older than configured days"
|
||||
- "Docker Compose starts ClickHouse and initializes the schema"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/WriteBuffer.java"
|
||||
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/WriteBuffer.java"
|
||||
provides: "Generic bounded write buffer with offer/drain/isFull"
|
||||
min_lines: 30
|
||||
- path: "clickhouse/init/01-schema.sql"
|
||||
@@ -41,15 +41,15 @@ must_haves:
|
||||
- path: "docker-compose.yml"
|
||||
provides: "Local ClickHouse service"
|
||||
contains: "clickhouse-server"
|
||||
- path: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/ExecutionRepository.java"
|
||||
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/storage/ExecutionRepository.java"
|
||||
provides: "Repository interface for execution batch inserts"
|
||||
exports: ["insertBatch"]
|
||||
key_links:
|
||||
- from: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/ClickHouseConfig.java"
|
||||
- from: "cameleer-server-app/src/main/java/com/cameleer/server/app/config/ClickHouseConfig.java"
|
||||
to: "application.yml"
|
||||
via: "spring.datasource properties"
|
||||
pattern: "spring\\.datasource"
|
||||
- from: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/IngestionConfig.java"
|
||||
- from: "cameleer-server-app/src/main/java/com/cameleer/server/app/config/IngestionConfig.java"
|
||||
to: "application.yml"
|
||||
via: "ingestion.* properties"
|
||||
pattern: "ingestion\\."
|
||||
@@ -74,8 +74,8 @@ Output: Working ClickHouse via Docker Compose, DDL with TTL, WriteBuffer with un
|
||||
@.planning/phases/01-ingestion-pipeline-api-foundation/01-RESEARCH.md
|
||||
|
||||
@pom.xml
|
||||
@cameleer3-server-core/pom.xml
|
||||
@cameleer3-server-app/pom.xml
|
||||
@cameleer-server-core/pom.xml
|
||||
@cameleer-server-app/pom.xml
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
@@ -84,11 +84,11 @@ Output: Working ClickHouse via Docker Compose, DDL with TTL, WriteBuffer with un
|
||||
<name>Task 1: Dependencies, Docker Compose, ClickHouse schema, and application config</name>
|
||||
<files>
|
||||
pom.xml,
|
||||
cameleer3-server-core/pom.xml,
|
||||
cameleer3-server-app/pom.xml,
|
||||
cameleer-server-core/pom.xml,
|
||||
cameleer-server-app/pom.xml,
|
||||
docker-compose.yml,
|
||||
clickhouse/init/01-schema.sql,
|
||||
cameleer3-server-app/src/main/resources/application.yml
|
||||
cameleer-server-app/src/main/resources/application.yml
|
||||
</files>
|
||||
<behavior>
|
||||
- docker compose up -d starts ClickHouse on ports 8123/9000
|
||||
@@ -101,7 +101,7 @@ Output: Working ClickHouse via Docker Compose, DDL with TTL, WriteBuffer with un
|
||||
- Maven compile succeeds with new dependencies
|
||||
</behavior>
|
||||
<action>
|
||||
1. Add dependencies to cameleer3-server-app/pom.xml per research:
|
||||
1. Add dependencies to cameleer-server-app/pom.xml per research:
|
||||
- clickhouse-jdbc 0.9.7 (classifier: all)
|
||||
- spring-boot-starter-actuator
|
||||
- springdoc-openapi-starter-webmvc-ui 2.8.6
|
||||
@@ -109,13 +109,13 @@ Output: Working ClickHouse via Docker Compose, DDL with TTL, WriteBuffer with un
|
||||
- junit-jupiter from testcontainers 2.0.2 (test scope)
|
||||
- awaitility (test scope)
|
||||
|
||||
2. Add slf4j-api dependency to cameleer3-server-core/pom.xml.
|
||||
2. Add slf4j-api dependency to cameleer-server-core/pom.xml.
|
||||
|
||||
3. Create docker-compose.yml at project root with ClickHouse service:
|
||||
- Image: clickhouse/clickhouse-server:25.3
|
||||
- Ports: 8123:8123, 9000:9000
|
||||
- Volume mount ./clickhouse/init to /docker-entrypoint-initdb.d
|
||||
- Environment: CLICKHOUSE_USER=cameleer, CLICKHOUSE_PASSWORD=cameleer_dev, CLICKHOUSE_DB=cameleer3
|
||||
- Environment: CLICKHOUSE_USER=cameleer, CLICKHOUSE_PASSWORD=cameleer_dev, CLICKHOUSE_DB=cameleer
|
||||
- ulimits nofile 262144
|
||||
|
||||
4. Create clickhouse/init/01-schema.sql with the three tables from research:
|
||||
@@ -124,9 +124,9 @@ Output: Working ClickHouse via Docker Compose, DDL with TTL, WriteBuffer with un
|
||||
- agent_metrics: MergeTree, daily partitioning on collected_at, ORDER BY (agent_id, metric_name, collected_at), TTL collected_at + INTERVAL 30 DAY, SETTINGS ttl_only_drop_parts=1.
|
||||
- All DateTime fields use DateTime64(3, 'UTC').
|
||||
|
||||
5. Create cameleer3-server-app/src/main/resources/application.yml with config from research:
|
||||
5. Create cameleer-server-app/src/main/resources/application.yml with config from research:
|
||||
- server.port: 8081
|
||||
- spring.datasource: url=jdbc:ch://localhost:8123/cameleer3, username/password, driver-class-name
|
||||
- spring.datasource: url=jdbc:ch://localhost:8123/cameleer, username/password, driver-class-name
|
||||
- spring.jackson: write-dates-as-timestamps=false, fail-on-unknown-properties=false
|
||||
- ingestion: buffer-capacity=50000, batch-size=5000, flush-interval-ms=1000
|
||||
- clickhouse.ttl-days: 30
|
||||
@@ -144,13 +144,13 @@ Output: Working ClickHouse via Docker Compose, DDL with TTL, WriteBuffer with un
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: WriteBuffer, repository interfaces, IngestionConfig, and ClickHouseConfig</name>
|
||||
<files>
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/WriteBuffer.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/ExecutionRepository.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/DiagramRepository.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/MetricsRepository.java,
|
||||
cameleer3-server-core/src/test/java/com/cameleer3/server/core/ingestion/WriteBufferTest.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/ClickHouseConfig.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/IngestionConfig.java
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/WriteBuffer.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/storage/ExecutionRepository.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/storage/DiagramRepository.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/storage/MetricsRepository.java,
|
||||
cameleer-server-core/src/test/java/com/cameleer/server/core/ingestion/WriteBufferTest.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/config/ClickHouseConfig.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/config/IngestionConfig.java
|
||||
</files>
|
||||
<behavior>
|
||||
- WriteBuffer(capacity=10): offer() returns true for first 10 items, false on 11th
|
||||
@@ -181,7 +181,7 @@ Output: Working ClickHouse via Docker Compose, DDL with TTL, WriteBuffer with un
|
||||
3. Create repository interfaces in core module:
|
||||
- ExecutionRepository: void insertBatch(List<RouteExecution> executions)
|
||||
- DiagramRepository: void store(RouteGraph graph), Optional<RouteGraph> findByContentHash(String hash), Optional<String> findContentHashForRoute(String routeId, String agentId)
|
||||
- MetricsRepository: void insertBatch(List<MetricsSnapshot> metrics) -- use a generic type or the cameleer3-common metrics model if available; if not, create a simple MetricsData record in core module
|
||||
- MetricsRepository: void insertBatch(List<MetricsSnapshot> metrics) -- use a generic type or the cameleer-common metrics model if available; if not, create a simple MetricsData record in core module
|
||||
|
||||
4. Create IngestionConfig as @ConfigurationProperties("ingestion"):
|
||||
- bufferCapacity (int, default 50000)
|
||||
@@ -193,7 +193,7 @@ Output: Working ClickHouse via Docker Compose, DDL with TTL, WriteBuffer with un
|
||||
- No custom bean needed if relying on auto-config; only create if explicit JdbcTemplate customization required
|
||||
</action>
|
||||
<verify>
|
||||
<automated>mvn test -pl cameleer3-server-core -Dtest=WriteBufferTest -q 2>&1 | tail -10</automated>
|
||||
<automated>mvn test -pl cameleer-server-core -Dtest=WriteBufferTest -q 2>&1 | tail -10</automated>
|
||||
</verify>
|
||||
<done>WriteBuffer passes all unit tests. Repository interfaces exist with correct method signatures. IngestionConfig reads from application.yml.</done>
|
||||
</task>
|
||||
@@ -201,7 +201,7 @@ Output: Working ClickHouse via Docker Compose, DDL with TTL, WriteBuffer with un
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `mvn test -pl cameleer3-server-core -q` -- all WriteBuffer unit tests pass
|
||||
- `mvn test -pl cameleer-server-core -q` -- all WriteBuffer unit tests pass
|
||||
- `mvn clean compile -q` -- full project compiles with new dependencies
|
||||
- `docker compose config` -- validates Docker Compose file
|
||||
- clickhouse/init/01-schema.sql contains CREATE TABLE for all three tables with correct ENGINE, ORDER BY, PARTITION BY, and TTL
|
||||
|
||||
@@ -26,22 +26,22 @@ key-files:
|
||||
created:
|
||||
- docker-compose.yml
|
||||
- clickhouse/init/01-schema.sql
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/WriteBuffer.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/ExecutionRepository.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/DiagramRepository.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/MetricsRepository.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/model/MetricsSnapshot.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/IngestionConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/ClickHouseConfig.java
|
||||
- cameleer3-server-core/src/test/java/com/cameleer3/server/core/ingestion/WriteBufferTest.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/WriteBuffer.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/storage/ExecutionRepository.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/storage/DiagramRepository.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/storage/MetricsRepository.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/storage/model/MetricsSnapshot.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/IngestionConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/ClickHouseConfig.java
|
||||
- cameleer-server-core/src/test/java/com/cameleer/server/core/ingestion/WriteBufferTest.java
|
||||
modified:
|
||||
- cameleer3-server-core/pom.xml
|
||||
- cameleer3-server-app/pom.xml
|
||||
- cameleer3-server-app/src/main/resources/application.yml
|
||||
- cameleer-server-core/pom.xml
|
||||
- cameleer-server-app/pom.xml
|
||||
- cameleer-server-app/src/main/resources/application.yml
|
||||
|
||||
key-decisions:
|
||||
- "Used spring-boot-starter-jdbc for JdbcTemplate + HikariCP auto-config rather than manual DataSource"
|
||||
- "Created MetricsSnapshot record in core module since cameleer3-common has no metrics model"
|
||||
- "Created MetricsSnapshot record in core module since cameleer-common has no metrics model"
|
||||
- "ClickHouseConfig exposes JdbcTemplate bean; relies on Spring Boot DataSource auto-config"
|
||||
|
||||
patterns-established:
|
||||
@@ -84,21 +84,21 @@ Each task was committed atomically:
|
||||
## Files Created/Modified
|
||||
- `docker-compose.yml` - ClickHouse service with ports 8123/9000, init volume mount
|
||||
- `clickhouse/init/01-schema.sql` - DDL for route_executions, route_diagrams, agent_metrics
|
||||
- `cameleer3-server-core/src/main/java/.../ingestion/WriteBuffer.java` - Bounded queue with offer/offerBatch/drain
|
||||
- `cameleer3-server-core/src/main/java/.../storage/ExecutionRepository.java` - Batch insert interface for RouteExecution
|
||||
- `cameleer3-server-core/src/main/java/.../storage/DiagramRepository.java` - Store/find interface for RouteGraph
|
||||
- `cameleer3-server-core/src/main/java/.../storage/MetricsRepository.java` - Batch insert interface for MetricsSnapshot
|
||||
- `cameleer3-server-core/src/main/java/.../storage/model/MetricsSnapshot.java` - Metrics data record
|
||||
- `cameleer3-server-app/src/main/java/.../config/IngestionConfig.java` - Buffer capacity, batch size, flush interval
|
||||
- `cameleer3-server-app/src/main/java/.../config/ClickHouseConfig.java` - JdbcTemplate bean
|
||||
- `cameleer3-server-core/src/test/java/.../ingestion/WriteBufferTest.java` - 10 unit tests for WriteBuffer
|
||||
- `cameleer3-server-core/pom.xml` - Added slf4j-api
|
||||
- `cameleer3-server-app/pom.xml` - Added clickhouse-jdbc, springdoc, actuator, testcontainers, awaitility
|
||||
- `cameleer3-server-app/src/main/resources/application.yml` - Full config with datasource, ingestion, springdoc, actuator
|
||||
- `cameleer-server-core/src/main/java/.../ingestion/WriteBuffer.java` - Bounded queue with offer/offerBatch/drain
|
||||
- `cameleer-server-core/src/main/java/.../storage/ExecutionRepository.java` - Batch insert interface for RouteExecution
|
||||
- `cameleer-server-core/src/main/java/.../storage/DiagramRepository.java` - Store/find interface for RouteGraph
|
||||
- `cameleer-server-core/src/main/java/.../storage/MetricsRepository.java` - Batch insert interface for MetricsSnapshot
|
||||
- `cameleer-server-core/src/main/java/.../storage/model/MetricsSnapshot.java` - Metrics data record
|
||||
- `cameleer-server-app/src/main/java/.../config/IngestionConfig.java` - Buffer capacity, batch size, flush interval
|
||||
- `cameleer-server-app/src/main/java/.../config/ClickHouseConfig.java` - JdbcTemplate bean
|
||||
- `cameleer-server-core/src/test/java/.../ingestion/WriteBufferTest.java` - 10 unit tests for WriteBuffer
|
||||
- `cameleer-server-core/pom.xml` - Added slf4j-api
|
||||
- `cameleer-server-app/pom.xml` - Added clickhouse-jdbc, springdoc, actuator, testcontainers, awaitility
|
||||
- `cameleer-server-app/src/main/resources/application.yml` - Full config with datasource, ingestion, springdoc, actuator
|
||||
|
||||
## Decisions Made
|
||||
- Used spring-boot-starter-jdbc to get JdbcTemplate and HikariCP auto-configuration rather than manually wiring a DataSource
|
||||
- Created MetricsSnapshot record in core module since cameleer3-common does not include a metrics model
|
||||
- Created MetricsSnapshot record in core module since cameleer-common does not include a metrics model
|
||||
- ClickHouseConfig is minimal -- relies on Spring Boot auto-configuring DataSource from spring.datasource properties
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
@@ -5,18 +5,18 @@ type: execute
|
||||
wave: 3
|
||||
depends_on: ["01-01", "01-03"]
|
||||
files_modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/ExecutionController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DiagramController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/MetricsController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseDiagramRepository.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseMetricsRepository.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/ingestion/ClickHouseFlushScheduler.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/IngestionService.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ExecutionControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/MetricsControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/BackpressureIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/ExecutionController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DiagramController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/MetricsController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseDiagramRepository.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseMetricsRepository.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/ingestion/ClickHouseFlushScheduler.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/IngestionService.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ExecutionControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/MetricsControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/BackpressureIT.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- INGST-01
|
||||
@@ -32,16 +32,16 @@ must_haves:
|
||||
- "Data posted to endpoints appears in ClickHouse after flush interval"
|
||||
- "When buffer is full, endpoints return 503 with Retry-After header"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/ExecutionController.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/controller/ExecutionController.java"
|
||||
provides: "POST /api/v1/data/executions endpoint"
|
||||
min_lines: 20
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java"
|
||||
provides: "Batch insert to route_executions table via JdbcTemplate"
|
||||
min_lines: 30
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/ingestion/ClickHouseFlushScheduler.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/ingestion/ClickHouseFlushScheduler.java"
|
||||
provides: "Scheduled drain of WriteBuffer into ClickHouse"
|
||||
min_lines: 20
|
||||
- path: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/IngestionService.java"
|
||||
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/IngestionService.java"
|
||||
provides: "Routes data to appropriate WriteBuffer instances"
|
||||
min_lines: 20
|
||||
key_links:
|
||||
@@ -92,7 +92,7 @@ Output: Working ingestion flow verified by integration tests against Testcontain
|
||||
|
||||
<!-- Interfaces from Plan 01 that this plan depends on -->
|
||||
<interfaces>
|
||||
From cameleer3-server-core WriteBuffer.java:
|
||||
From cameleer-server-core WriteBuffer.java:
|
||||
```java
|
||||
public class WriteBuffer<T> {
|
||||
public WriteBuffer(int capacity);
|
||||
@@ -106,7 +106,7 @@ public class WriteBuffer<T> {
|
||||
}
|
||||
```
|
||||
|
||||
From cameleer3-server-core repository interfaces:
|
||||
From cameleer-server-core repository interfaces:
|
||||
```java
|
||||
public interface ExecutionRepository {
|
||||
void insertBatch(List<RouteExecution> executions);
|
||||
@@ -138,11 +138,11 @@ public class IngestionConfig {
|
||||
<task type="auto" tdd="false">
|
||||
<name>Task 1: IngestionService, ClickHouse repositories, and flush scheduler</name>
|
||||
<files>
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/IngestionService.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseDiagramRepository.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseMetricsRepository.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/ingestion/ClickHouseFlushScheduler.java
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/IngestionService.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseDiagramRepository.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseMetricsRepository.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/ingestion/ClickHouseFlushScheduler.java
|
||||
</files>
|
||||
<action>
|
||||
1. Create IngestionService in core module (no Spring annotations -- it's a plain class):
|
||||
@@ -188,13 +188,13 @@ public class IngestionConfig {
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Ingestion REST controllers and integration tests</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/ExecutionController.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DiagramController.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/MetricsController.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ExecutionControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/MetricsControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/BackpressureIT.java
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/ExecutionController.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DiagramController.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/MetricsController.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ExecutionControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/MetricsControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/BackpressureIT.java
|
||||
</files>
|
||||
<behavior>
|
||||
- POST /api/v1/data/executions with single RouteExecution JSON returns 202
|
||||
@@ -245,7 +245,7 @@ public class IngestionConfig {
|
||||
Note: All integration tests must include X-Cameleer-Protocol-Version:1 header (API-04 will be enforced by Plan 03's interceptor, but include the header now for forward compatibility).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>mvn test -pl cameleer3-server-app -Dtest="ExecutionControllerIT,DiagramControllerIT,MetricsControllerIT,BackpressureIT" -q 2>&1 | tail -15</automated>
|
||||
<automated>mvn test -pl cameleer-server-app -Dtest="ExecutionControllerIT,DiagramControllerIT,MetricsControllerIT,BackpressureIT" -q 2>&1 | tail -15</automated>
|
||||
</verify>
|
||||
<done>All three ingestion endpoints return 202 on valid data. Data arrives in ClickHouse after flush. Buffer-full returns 503 with Retry-After. Unknown JSON fields accepted. Integration tests green.</done>
|
||||
</task>
|
||||
@@ -253,7 +253,7 @@ public class IngestionConfig {
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `mvn test -pl cameleer3-server-app -Dtest="ExecutionControllerIT,DiagramControllerIT,MetricsControllerIT,BackpressureIT" -q` -- all integration tests pass
|
||||
- `mvn test -pl cameleer-server-app -Dtest="ExecutionControllerIT,DiagramControllerIT,MetricsControllerIT,BackpressureIT" -q` -- all integration tests pass
|
||||
- POST to /api/v1/data/executions returns 202
|
||||
- POST to /api/v1/data/diagrams returns 202
|
||||
- POST to /api/v1/data/metrics returns 202
|
||||
|
||||
@@ -30,21 +30,21 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/IngestionService.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseDiagramRepository.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseMetricsRepository.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/ingestion/ClickHouseFlushScheduler.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/IngestionBeanConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/ExecutionController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DiagramController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/MetricsController.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ExecutionControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/MetricsControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/BackpressureIT.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/IngestionService.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseDiagramRepository.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseMetricsRepository.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/ingestion/ClickHouseFlushScheduler.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/IngestionBeanConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/ExecutionController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DiagramController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/MetricsController.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ExecutionControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/MetricsControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/BackpressureIT.java
|
||||
modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/IngestionConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/IngestionConfig.java
|
||||
|
||||
key-decisions:
|
||||
- "Controllers accept raw String body and detect single vs array JSON to support both payload formats"
|
||||
@@ -91,20 +91,20 @@ Each task was committed atomically:
|
||||
3. **Task 2 GREEN: Ingestion REST controllers with backpressure** - `8fe65f0` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
- `cameleer3-server-core/.../ingestion/IngestionService.java` - Routes data to WriteBuffer instances
|
||||
- `cameleer3-server-app/.../storage/ClickHouseExecutionRepository.java` - Batch insert with parallel processor arrays
|
||||
- `cameleer3-server-app/.../storage/ClickHouseDiagramRepository.java` - JSON storage with SHA-256 content-hash dedup
|
||||
- `cameleer3-server-app/.../storage/ClickHouseMetricsRepository.java` - Batch insert for agent_metrics
|
||||
- `cameleer3-server-app/.../ingestion/ClickHouseFlushScheduler.java` - Scheduled drain + SmartLifecycle shutdown
|
||||
- `cameleer3-server-app/.../config/IngestionBeanConfig.java` - WriteBuffer and IngestionService bean wiring
|
||||
- `cameleer3-server-app/.../controller/ExecutionController.java` - POST /api/v1/data/executions
|
||||
- `cameleer3-server-app/.../controller/DiagramController.java` - POST /api/v1/data/diagrams
|
||||
- `cameleer3-server-app/.../controller/MetricsController.java` - POST /api/v1/data/metrics
|
||||
- `cameleer3-server-app/.../config/IngestionConfig.java` - Removed @Configuration (fix duplicate bean)
|
||||
- `cameleer3-server-app/.../controller/ExecutionControllerIT.java` - 4 tests: single, array, flush, unknown fields
|
||||
- `cameleer3-server-app/.../controller/DiagramControllerIT.java` - 3 tests: single, array, flush
|
||||
- `cameleer3-server-app/.../controller/MetricsControllerIT.java` - 2 tests: POST, flush
|
||||
- `cameleer3-server-app/.../controller/BackpressureIT.java` - 2 tests: 503 response, data not lost
|
||||
- `cameleer-server-core/.../ingestion/IngestionService.java` - Routes data to WriteBuffer instances
|
||||
- `cameleer-server-app/.../storage/ClickHouseExecutionRepository.java` - Batch insert with parallel processor arrays
|
||||
- `cameleer-server-app/.../storage/ClickHouseDiagramRepository.java` - JSON storage with SHA-256 content-hash dedup
|
||||
- `cameleer-server-app/.../storage/ClickHouseMetricsRepository.java` - Batch insert for agent_metrics
|
||||
- `cameleer-server-app/.../ingestion/ClickHouseFlushScheduler.java` - Scheduled drain + SmartLifecycle shutdown
|
||||
- `cameleer-server-app/.../config/IngestionBeanConfig.java` - WriteBuffer and IngestionService bean wiring
|
||||
- `cameleer-server-app/.../controller/ExecutionController.java` - POST /api/v1/data/executions
|
||||
- `cameleer-server-app/.../controller/DiagramController.java` - POST /api/v1/data/diagrams
|
||||
- `cameleer-server-app/.../controller/MetricsController.java` - POST /api/v1/data/metrics
|
||||
- `cameleer-server-app/.../config/IngestionConfig.java` - Removed @Configuration (fix duplicate bean)
|
||||
- `cameleer-server-app/.../controller/ExecutionControllerIT.java` - 4 tests: single, array, flush, unknown fields
|
||||
- `cameleer-server-app/.../controller/DiagramControllerIT.java` - 3 tests: single, array, flush
|
||||
- `cameleer-server-app/.../controller/MetricsControllerIT.java` - 2 tests: POST, flush
|
||||
- `cameleer-server-app/.../controller/BackpressureIT.java` - 2 tests: 503 response, data not lost
|
||||
|
||||
## Decisions Made
|
||||
- Controllers accept raw String body and detect single vs array JSON (starts with `[`), supporting both payload formats per protocol spec
|
||||
@@ -119,7 +119,7 @@ Each task was committed atomically:
|
||||
- **Found during:** Task 2 (integration test context startup)
|
||||
- **Issue:** IngestionConfig had both `@Configuration` and `@ConfigurationProperties`, while `@EnableConfigurationProperties(IngestionConfig.class)` on the app class created a second bean, causing "expected single matching bean but found 2"
|
||||
- **Fix:** Removed `@Configuration` from IngestionConfig, relying solely on `@EnableConfigurationProperties`
|
||||
- **Files modified:** cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/IngestionConfig.java
|
||||
- **Files modified:** cameleer-server-app/src/main/java/com/cameleer/server/app/config/IngestionConfig.java
|
||||
- **Verification:** Application context starts successfully, all tests pass
|
||||
- **Committed in:** 8fe65f0
|
||||
|
||||
|
||||
@@ -5,15 +5,15 @@ type: execute
|
||||
wave: 2
|
||||
depends_on: ["01-01"]
|
||||
files_modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/interceptor/ProtocolVersionInterceptor.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/Cameleer3ServerApplication.java
|
||||
- cameleer3-server-app/src/test/resources/application-test.yml
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/interceptor/ProtocolVersionIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/HealthControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/OpenApiIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ForwardCompatIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/interceptor/ProtocolVersionInterceptor.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/CameleerServerApplication.java
|
||||
- cameleer-server-app/src/test/resources/application-test.yml
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/interceptor/ProtocolVersionIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/HealthControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/OpenApiIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ForwardCompatIT.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- API-01
|
||||
@@ -34,13 +34,13 @@ must_haves:
|
||||
- "Unknown JSON fields in request body do not cause deserialization errors"
|
||||
- "ClickHouse tables have TTL clause for 30-day retention"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/interceptor/ProtocolVersionInterceptor.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/interceptor/ProtocolVersionInterceptor.java"
|
||||
provides: "Validates X-Cameleer-Protocol-Version:1 header on data endpoints"
|
||||
min_lines: 20
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java"
|
||||
provides: "Registers interceptor with path patterns"
|
||||
min_lines: 10
|
||||
- path: "cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java"
|
||||
- path: "cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java"
|
||||
provides: "Shared Testcontainers base class for integration tests"
|
||||
min_lines: 20
|
||||
key_links:
|
||||
@@ -83,11 +83,11 @@ Output: AbstractClickHouseIT base class, working health, Swagger UI, protocol he
|
||||
<task type="auto">
|
||||
<name>Task 1: Test infrastructure, protocol version interceptor, WebConfig, and Spring Boot application class</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/test/resources/application-test.yml,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/interceptor/ProtocolVersionInterceptor.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/Cameleer3ServerApplication.java
|
||||
cameleer-server-app/src/test/resources/application-test.yml,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/interceptor/ProtocolVersionInterceptor.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/CameleerServerApplication.java
|
||||
</files>
|
||||
<action>
|
||||
1. Create application-test.yml for test profile:
|
||||
@@ -113,15 +113,15 @@ Output: AbstractClickHouseIT base class, working health, Swagger UI, protocol he
|
||||
- Override addInterceptors: register interceptor with pathPatterns "/api/v1/data/**" and "/api/v1/agents/**"
|
||||
- Explicitly EXCLUDE: "/api/v1/health", "/api/v1/api-docs/**", "/api/v1/swagger-ui/**", "/api/v1/swagger-ui.html"
|
||||
|
||||
5. Create or update Cameleer3ServerApplication:
|
||||
- @SpringBootApplication in package com.cameleer3.server.app
|
||||
5. Create or update CameleerServerApplication:
|
||||
- @SpringBootApplication in package com.cameleer.server.app
|
||||
- @EnableScheduling (needed for ClickHouseFlushScheduler from Plan 02)
|
||||
- @EnableConfigurationProperties(IngestionConfig.class)
|
||||
- Main method with SpringApplication.run()
|
||||
- Ensure package scanning covers com.cameleer3.server.app and com.cameleer3.server.core
|
||||
- Ensure package scanning covers com.cameleer.server.app and com.cameleer.server.core
|
||||
</action>
|
||||
<verify>
|
||||
<automated>mvn clean compile -pl cameleer3-server-app -q 2>&1 | tail -5</automated>
|
||||
<automated>mvn clean compile -pl cameleer-server-app -q 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<done>AbstractClickHouseIT base class ready for integration tests. ProtocolVersionInterceptor validates header on data/agent paths. Health, swagger, and api-docs paths excluded. Application class enables scheduling and config properties.</done>
|
||||
</task>
|
||||
@@ -129,10 +129,10 @@ Output: AbstractClickHouseIT base class, working health, Swagger UI, protocol he
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Health, OpenAPI, protocol version, forward compat, and TTL integration tests</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/HealthControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/OpenApiIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/interceptor/ProtocolVersionIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ForwardCompatIT.java
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/HealthControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/OpenApiIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/interceptor/ProtocolVersionIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ForwardCompatIT.java
|
||||
</files>
|
||||
<behavior>
|
||||
- GET /api/v1/health returns 200 with JSON containing status field
|
||||
@@ -178,7 +178,7 @@ Output: AbstractClickHouseIT base class, working health, Swagger UI, protocol he
|
||||
Note: All tests that POST to data endpoints must include X-Cameleer-Protocol-Version:1 header.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>mvn test -pl cameleer3-server-app -Dtest="HealthControllerIT,OpenApiIT,ProtocolVersionIT,ForwardCompatIT" -q 2>&1 | tail -15</automated>
|
||||
<automated>mvn test -pl cameleer-server-app -Dtest="HealthControllerIT,OpenApiIT,ProtocolVersionIT,ForwardCompatIT" -q 2>&1 | tail -15</automated>
|
||||
</verify>
|
||||
<done>Health returns 200. OpenAPI docs are available and list endpoints. Protocol version header enforced on data paths, not on health/docs. Unknown JSON fields accepted. TTL confirmed in ClickHouse DDL via HealthControllerIT test methods.</done>
|
||||
</task>
|
||||
@@ -186,7 +186,7 @@ Output: AbstractClickHouseIT base class, working health, Swagger UI, protocol he
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `mvn test -pl cameleer3-server-app -Dtest="HealthControllerIT,OpenApiIT,ProtocolVersionIT,ForwardCompatIT" -q` -- all tests pass
|
||||
- `mvn test -pl cameleer-server-app -Dtest="HealthControllerIT,OpenApiIT,ProtocolVersionIT,ForwardCompatIT" -q` -- all tests pass
|
||||
- GET /api/v1/health returns 200
|
||||
- GET /api/v1/api-docs returns OpenAPI spec
|
||||
- Missing protocol header returns 400 on data endpoints
|
||||
|
||||
@@ -12,7 +12,7 @@ provides:
|
||||
- AbstractClickHouseIT base class for all integration tests
|
||||
- ProtocolVersionInterceptor enforcing X-Cameleer-Protocol-Version:1 on data/agent paths
|
||||
- WebConfig with interceptor registration and path exclusions
|
||||
- Cameleer3ServerApplication with @EnableScheduling and component scanning
|
||||
- CameleerServerApplication with @EnableScheduling and component scanning
|
||||
- 12 passing integration tests (health, OpenAPI, protocol version, forward compat, TTL)
|
||||
|
||||
affects: [01-02, 02-search, 03-agent-registry]
|
||||
@@ -23,17 +23,17 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/Cameleer3ServerApplication.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/interceptor/ProtocolVersionInterceptor.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java
|
||||
- cameleer3-server-app/src/test/resources/application-test.yml
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/HealthControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/OpenApiIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/interceptor/ProtocolVersionIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ForwardCompatIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/CameleerServerApplication.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/interceptor/ProtocolVersionInterceptor.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java
|
||||
- cameleer-server-app/src/test/resources/application-test.yml
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/HealthControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/OpenApiIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/interceptor/ProtocolVersionIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ForwardCompatIT.java
|
||||
modified:
|
||||
- cameleer3-server-app/pom.xml
|
||||
- cameleer-server-app/pom.xml
|
||||
- pom.xml
|
||||
- clickhouse/init/01-schema.sql
|
||||
|
||||
@@ -70,7 +70,7 @@ completed: 2026-03-11
|
||||
- ProtocolVersionInterceptor validates X-Cameleer-Protocol-Version:1 on /api/v1/data/** and /api/v1/agents/** paths, returning 400 JSON error for missing or wrong version
|
||||
- AbstractClickHouseIT base class with Testcontainers ClickHouse 25.3, shared static container, schema init from 01-schema.sql
|
||||
- 12 integration tests: health endpoint (2), OpenAPI docs (2), protocol version enforcement (5), forward compatibility (1), TTL verification (2)
|
||||
- Cameleer3ServerApplication with @EnableScheduling, @EnableConfigurationProperties, and dual package scanning
|
||||
- CameleerServerApplication with @EnableScheduling, @EnableConfigurationProperties, and dual package scanning
|
||||
|
||||
## Task Commits
|
||||
|
||||
@@ -80,17 +80,17 @@ Each task was committed atomically:
|
||||
2. **Task 2: Integration tests for health, OpenAPI, protocol version, forward compat, and TTL** - `2d3fde3` (test)
|
||||
|
||||
## Files Created/Modified
|
||||
- `cameleer3-server-app/src/main/java/.../Cameleer3ServerApplication.java` - Spring Boot entry point with scheduling and config properties
|
||||
- `cameleer3-server-app/src/main/java/.../interceptor/ProtocolVersionInterceptor.java` - Validates protocol version header on data/agent paths
|
||||
- `cameleer3-server-app/src/main/java/.../config/WebConfig.java` - Registers interceptor with path patterns and exclusions
|
||||
- `cameleer3-server-app/src/test/java/.../AbstractClickHouseIT.java` - Shared Testcontainers base class for ITs
|
||||
- `cameleer3-server-app/src/test/resources/application-test.yml` - Test profile with small buffer config
|
||||
- `cameleer3-server-app/src/test/java/.../controller/HealthControllerIT.java` - Health endpoint and TTL tests
|
||||
- `cameleer3-server-app/src/test/java/.../controller/OpenApiIT.java` - OpenAPI and Swagger UI tests
|
||||
- `cameleer3-server-app/src/test/java/.../interceptor/ProtocolVersionIT.java` - Protocol header enforcement tests
|
||||
- `cameleer3-server-app/src/test/java/.../controller/ForwardCompatIT.java` - Unknown JSON fields test
|
||||
- `cameleer-server-app/src/main/java/.../CameleerServerApplication.java` - Spring Boot entry point with scheduling and config properties
|
||||
- `cameleer-server-app/src/main/java/.../interceptor/ProtocolVersionInterceptor.java` - Validates protocol version header on data/agent paths
|
||||
- `cameleer-server-app/src/main/java/.../config/WebConfig.java` - Registers interceptor with path patterns and exclusions
|
||||
- `cameleer-server-app/src/test/java/.../AbstractClickHouseIT.java` - Shared Testcontainers base class for ITs
|
||||
- `cameleer-server-app/src/test/resources/application-test.yml` - Test profile with small buffer config
|
||||
- `cameleer-server-app/src/test/java/.../controller/HealthControllerIT.java` - Health endpoint and TTL tests
|
||||
- `cameleer-server-app/src/test/java/.../controller/OpenApiIT.java` - OpenAPI and Swagger UI tests
|
||||
- `cameleer-server-app/src/test/java/.../interceptor/ProtocolVersionIT.java` - Protocol header enforcement tests
|
||||
- `cameleer-server-app/src/test/java/.../controller/ForwardCompatIT.java` - Unknown JSON fields test
|
||||
- `pom.xml` - Override testcontainers.version to 2.0.3
|
||||
- `cameleer3-server-app/pom.xml` - Remove junit-jupiter, upgrade testcontainers-clickhouse to 2.0.3
|
||||
- `cameleer-server-app/pom.xml` - Remove junit-jupiter, upgrade testcontainers-clickhouse to 2.0.3
|
||||
- `clickhouse/init/01-schema.sql` - Fix TTL expressions and error column types
|
||||
|
||||
## Decisions Made
|
||||
@@ -107,7 +107,7 @@ Each task was committed atomically:
|
||||
- **Found during:** Task 2 (compilation)
|
||||
- **Issue:** org.testcontainers:junit-jupiter:2.0.2 does not exist in Maven Central
|
||||
- **Fix:** Removed junit-jupiter dependency, upgraded to TC 2.0.3, managed container lifecycle manually via static initializer
|
||||
- **Files modified:** cameleer3-server-app/pom.xml, pom.xml, AbstractClickHouseIT.java
|
||||
- **Files modified:** cameleer-server-app/pom.xml, pom.xml, AbstractClickHouseIT.java
|
||||
- **Verification:** All tests compile and pass
|
||||
- **Committed in:** 2d3fde3
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## Summary
|
||||
|
||||
Phase 1 establishes the data pipeline and API skeleton for Cameleer3 Server. Agents POST execution data, diagrams, and metrics to REST endpoints; the server buffers these in memory and batch-flushes to ClickHouse. The ClickHouse schema design is the most critical and least reversible decision in this phase -- ORDER BY and partitioning cannot be changed without table recreation.
|
||||
Phase 1 establishes the data pipeline and API skeleton for Cameleer Server. Agents POST execution data, diagrams, and metrics to REST endpoints; the server buffers these in memory and batch-flushes to ClickHouse. The ClickHouse schema design is the most critical and least reversible decision in this phase -- ORDER BY and partitioning cannot be changed without table recreation.
|
||||
|
||||
The ClickHouse Java ecosystem has undergone significant changes. The recommended approach is **clickhouse-jdbc v0.9.7** (JDBC V2 driver) with Spring Boot's JdbcTemplate for batch inserts. An alternative is the standalone **client-v2** artifact which offers a POJO-based insert API, but JDBC integration with Spring Boot is more conventional and better documented. ClickHouse now has a native full-text index (TYPE text, GA as of March 2026) that supersedes the older tokenbf_v1 bloom filter approach -- this is relevant for Phase 2 but should be accounted for in schema design now.
|
||||
|
||||
@@ -17,7 +17,7 @@ The ClickHouse Java ecosystem has undergone significant changes. The recommended
|
||||
|
||||
| ID | Description | Research Support |
|
||||
|----|-------------|-----------------|
|
||||
| INGST-01 (#1) | Accept RouteExecution via POST /api/v1/data/executions, return 202 | REST controller + async write buffer pattern; Jackson deserialization of cameleer3-common models |
|
||||
| INGST-01 (#1) | Accept RouteExecution via POST /api/v1/data/executions, return 202 | REST controller + async write buffer pattern; Jackson deserialization of cameleer-common models |
|
||||
| INGST-02 (#2) | Accept RouteGraph via POST /api/v1/data/diagrams, return 202 | Same pattern; separate ClickHouse table for diagrams with content-hash dedup |
|
||||
| INGST-03 (#3) | Accept metrics via POST /api/v1/data/metrics, return 202 | Same pattern; separate ClickHouse table for metrics |
|
||||
| INGST-04 (#4) | In-memory batch buffer with configurable flush interval/size | ArrayBlockingQueue + @Scheduled flush; configurable via application.yml |
|
||||
@@ -60,7 +60,7 @@ The ClickHouse Java ecosystem has undergone significant changes. The recommended
|
||||
| ArrayBlockingQueue | LMAX Disruptor | Disruptor is faster under extreme contention but adds complexity; ABQ is sufficient for this throughput |
|
||||
| Spring JdbcTemplate | Raw JDBC PreparedStatement | JdbcTemplate provides cleaner error handling and resource management; no meaningful overhead |
|
||||
|
||||
**Installation (add to cameleer3-server-app/pom.xml):**
|
||||
**Installation (add to cameleer-server-app/pom.xml):**
|
||||
```xml
|
||||
<!-- ClickHouse JDBC V2 -->
|
||||
<dependency>
|
||||
@@ -103,7 +103,7 @@ The ClickHouse Java ecosystem has undergone significant changes. The recommended
|
||||
</dependency>
|
||||
```
|
||||
|
||||
**Add to cameleer3-server-core/pom.xml:**
|
||||
**Add to cameleer-server-core/pom.xml:**
|
||||
```xml
|
||||
<!-- SLF4J for logging (no Spring dependency) -->
|
||||
<dependency>
|
||||
@@ -117,7 +117,7 @@ The ClickHouse Java ecosystem has undergone significant changes. The recommended
|
||||
### Recommended Project Structure
|
||||
|
||||
```
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/
|
||||
ingestion/
|
||||
WriteBuffer.java # Bounded queue + flush logic
|
||||
IngestionService.java # Accepts data, routes to buffer
|
||||
@@ -126,9 +126,9 @@ cameleer3-server-core/src/main/java/com/cameleer3/server/core/
|
||||
DiagramRepository.java # Interface: store/retrieve diagrams
|
||||
MetricsRepository.java # Interface: store metrics
|
||||
model/
|
||||
(extend/complement cameleer3-common models as needed)
|
||||
(extend/complement cameleer-common models as needed)
|
||||
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/
|
||||
config/
|
||||
ClickHouseConfig.java # DataSource + JdbcTemplate bean
|
||||
IngestionConfig.java # Buffer size, flush interval from YAML
|
||||
@@ -424,7 +424,7 @@ services:
|
||||
environment:
|
||||
CLICKHOUSE_USER: cameleer
|
||||
CLICKHOUSE_PASSWORD: cameleer_dev
|
||||
CLICKHOUSE_DB: cameleer3
|
||||
CLICKHOUSE_DB: cameleer
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 262144
|
||||
@@ -442,7 +442,7 @@ server:
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:ch://localhost:8123/cameleer3
|
||||
url: jdbc:ch://localhost:8123/cameleer
|
||||
username: cameleer
|
||||
password: cameleer_dev
|
||||
driver-class-name: com.clickhouse.jdbc.ClickHouseDriver
|
||||
@@ -493,10 +493,10 @@ management:
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Exact cameleer3-common model structure**
|
||||
1. **Exact cameleer-common model structure**
|
||||
- What we know: Models include RouteExecution, ProcessorExecution, ExchangeSnapshot, RouteGraph, RouteNode, RouteEdge
|
||||
- What's unclear: Exact field names, types, nesting structure -- needed to design ClickHouse schema precisely
|
||||
- Recommendation: Read cameleer3-common source code before implementing schema. Schema must match the wire format.
|
||||
- Recommendation: Read cameleer-common source code before implementing schema. Schema must match the wire format.
|
||||
|
||||
2. **ClickHouse JDBC V2 + HikariCP compatibility**
|
||||
- What we know: clickhouse-jdbc 0.9.7 implements JDBC spec; HikariCP is Spring Boot default
|
||||
@@ -515,36 +515,36 @@ management:
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Framework | JUnit 5 (Spring Boot managed) + Testcontainers 2.0.2 |
|
||||
| Config file | cameleer3-server-app/src/test/resources/application-test.yml (Wave 0) |
|
||||
| Quick run command | `mvn test -pl cameleer3-server-core -Dtest=WriteBufferTest -q` |
|
||||
| Config file | cameleer-server-app/src/test/resources/application-test.yml (Wave 0) |
|
||||
| Quick run command | `mvn test -pl cameleer-server-core -Dtest=WriteBufferTest -q` |
|
||||
| Full suite command | `mvn verify` |
|
||||
|
||||
### Phase Requirements -> Test Map
|
||||
|
||||
| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|
||||
|--------|----------|-----------|-------------------|-------------|
|
||||
| INGST-01 | POST /api/v1/data/executions returns 202, data in ClickHouse | integration | `mvn test -pl cameleer3-server-app -Dtest=ExecutionControllerIT -q` | Wave 0 |
|
||||
| INGST-02 | POST /api/v1/data/diagrams returns 202 | integration | `mvn test -pl cameleer3-server-app -Dtest=DiagramControllerIT -q` | Wave 0 |
|
||||
| INGST-03 | POST /api/v1/data/metrics returns 202 | integration | `mvn test -pl cameleer3-server-app -Dtest=MetricsControllerIT -q` | Wave 0 |
|
||||
| INGST-04 | Buffer flushes at interval/size | unit | `mvn test -pl cameleer3-server-core -Dtest=WriteBufferTest -q` | Wave 0 |
|
||||
| INGST-05 | 503 when buffer full | unit+integration | `mvn test -pl cameleer3-server-app -Dtest=BackpressureIT -q` | Wave 0 |
|
||||
| INGST-06 | TTL removes old data | integration | `mvn test -pl cameleer3-server-app -Dtest=ClickHouseTtlIT -q` | Wave 0 |
|
||||
| INGST-01 | POST /api/v1/data/executions returns 202, data in ClickHouse | integration | `mvn test -pl cameleer-server-app -Dtest=ExecutionControllerIT -q` | Wave 0 |
|
||||
| INGST-02 | POST /api/v1/data/diagrams returns 202 | integration | `mvn test -pl cameleer-server-app -Dtest=DiagramControllerIT -q` | Wave 0 |
|
||||
| INGST-03 | POST /api/v1/data/metrics returns 202 | integration | `mvn test -pl cameleer-server-app -Dtest=MetricsControllerIT -q` | Wave 0 |
|
||||
| INGST-04 | Buffer flushes at interval/size | unit | `mvn test -pl cameleer-server-core -Dtest=WriteBufferTest -q` | Wave 0 |
|
||||
| INGST-05 | 503 when buffer full | unit+integration | `mvn test -pl cameleer-server-app -Dtest=BackpressureIT -q` | Wave 0 |
|
||||
| INGST-06 | TTL removes old data | integration | `mvn test -pl cameleer-server-app -Dtest=ClickHouseTtlIT -q` | Wave 0 |
|
||||
| API-01 | Endpoints under /api/v1/ | integration | Covered by controller ITs | Wave 0 |
|
||||
| API-02 | OpenAPI docs available | integration | `mvn test -pl cameleer3-server-app -Dtest=OpenApiIT -q` | Wave 0 |
|
||||
| API-03 | GET /api/v1/health responds | integration | `mvn test -pl cameleer3-server-app -Dtest=HealthControllerIT -q` | Wave 0 |
|
||||
| API-04 | Protocol version header validated | integration | `mvn test -pl cameleer3-server-app -Dtest=ProtocolVersionIT -q` | Wave 0 |
|
||||
| API-05 | Unknown JSON fields accepted | unit | `mvn test -pl cameleer3-server-app -Dtest=ForwardCompatIT -q` | Wave 0 |
|
||||
| API-02 | OpenAPI docs available | integration | `mvn test -pl cameleer-server-app -Dtest=OpenApiIT -q` | Wave 0 |
|
||||
| API-03 | GET /api/v1/health responds | integration | `mvn test -pl cameleer-server-app -Dtest=HealthControllerIT -q` | Wave 0 |
|
||||
| API-04 | Protocol version header validated | integration | `mvn test -pl cameleer-server-app -Dtest=ProtocolVersionIT -q` | Wave 0 |
|
||||
| API-05 | Unknown JSON fields accepted | unit | `mvn test -pl cameleer-server-app -Dtest=ForwardCompatIT -q` | Wave 0 |
|
||||
|
||||
### Sampling Rate
|
||||
- **Per task commit:** `mvn test -pl cameleer3-server-core -q` (unit tests, fast)
|
||||
- **Per task commit:** `mvn test -pl cameleer-server-core -q` (unit tests, fast)
|
||||
- **Per wave merge:** `mvn verify` (full suite with Testcontainers integration tests)
|
||||
- **Phase gate:** Full suite green before verification
|
||||
|
||||
### Wave 0 Gaps
|
||||
- [ ] `cameleer3-server-app/src/test/resources/application-test.yml` -- test ClickHouse config
|
||||
- [ ] `cameleer3-server-core/src/test/java/.../WriteBufferTest.java` -- buffer unit tests
|
||||
- [ ] `cameleer3-server-app/src/test/java/.../AbstractClickHouseIT.java` -- shared Testcontainers base class
|
||||
- [ ] `cameleer3-server-app/src/test/java/.../ExecutionControllerIT.java` -- ingestion integration test
|
||||
- [ ] `cameleer-server-app/src/test/resources/application-test.yml` -- test ClickHouse config
|
||||
- [ ] `cameleer-server-core/src/test/java/.../WriteBufferTest.java` -- buffer unit tests
|
||||
- [ ] `cameleer-server-app/src/test/java/.../AbstractClickHouseIT.java` -- shared Testcontainers base class
|
||||
- [ ] `cameleer-server-app/src/test/java/.../ExecutionControllerIT.java` -- ingestion integration test
|
||||
- [ ] Docker available on test machine for Testcontainers
|
||||
|
||||
## Sources
|
||||
|
||||
@@ -18,8 +18,8 @@ created: 2026-03-11
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Framework** | JUnit 5 (Spring Boot managed) + Testcontainers 2.0.2 |
|
||||
| **Config file** | cameleer3-server-app/src/test/resources/application-test.yml (Wave 0) |
|
||||
| **Quick run command** | `mvn test -pl cameleer3-server-core -Dtest=WriteBufferTest -q` |
|
||||
| **Config file** | cameleer-server-app/src/test/resources/application-test.yml (Wave 0) |
|
||||
| **Quick run command** | `mvn test -pl cameleer-server-core -Dtest=WriteBufferTest -q` |
|
||||
| **Full suite command** | `mvn verify` |
|
||||
| **Estimated runtime** | ~30 seconds |
|
||||
|
||||
@@ -27,7 +27,7 @@ created: 2026-03-11
|
||||
|
||||
## Sampling Rate
|
||||
|
||||
- **After every task commit:** Run `mvn test -pl cameleer3-server-core -q`
|
||||
- **After every task commit:** Run `mvn test -pl cameleer-server-core -q`
|
||||
- **After every plan wave:** Run `mvn verify`
|
||||
- **Before `/gsd:verify-work`:** Full suite must be green
|
||||
- **Max feedback latency:** 30 seconds
|
||||
@@ -38,17 +38,17 @@ created: 2026-03-11
|
||||
|
||||
| Task ID | Plan | Wave | Requirement | Test Type | Automated Command | File Exists | Status |
|
||||
|---------|------|------|-------------|-----------|-------------------|-------------|--------|
|
||||
| 1-01-01 | 01 | 1 | INGST-04 | unit | `mvn test -pl cameleer3-server-core -Dtest=WriteBufferTest -q` | no W0 | pending |
|
||||
| 1-01-02 | 01 | 1 | INGST-01 | integration | `mvn test -pl cameleer3-server-app -Dtest=ExecutionControllerIT -q` | no W0 | pending |
|
||||
| 1-01-03 | 01 | 1 | INGST-05 | integration | `mvn test -pl cameleer3-server-app -Dtest=BackpressureIT -q` | no W0 | pending |
|
||||
| 1-01-04 | 01 | 1 | INGST-06 | integration | `mvn test -pl cameleer3-server-app -Dtest=HealthControllerIT#ttlConfigured* -q` | no W0 | pending |
|
||||
| 1-02-01 | 02 | 1 | INGST-01 | integration | `mvn test -pl cameleer3-server-app -Dtest=ExecutionControllerIT -q` | no W0 | pending |
|
||||
| 1-02-02 | 02 | 1 | INGST-02 | integration | `mvn test -pl cameleer3-server-app -Dtest=DiagramControllerIT -q` | no W0 | pending |
|
||||
| 1-02-03 | 02 | 1 | INGST-03 | integration | `mvn test -pl cameleer3-server-app -Dtest=MetricsControllerIT -q` | no W0 | pending |
|
||||
| 1-02-04 | 02 | 1 | API-02 | integration | `mvn test -pl cameleer3-server-app -Dtest=OpenApiIT -q` | no W0 | pending |
|
||||
| 1-02-05 | 02 | 1 | API-03 | integration | `mvn test -pl cameleer3-server-app -Dtest=HealthControllerIT -q` | no W0 | pending |
|
||||
| 1-02-06 | 02 | 1 | API-04 | integration | `mvn test -pl cameleer3-server-app -Dtest=ProtocolVersionIT -q` | no W0 | pending |
|
||||
| 1-02-07 | 02 | 1 | API-05 | unit | `mvn test -pl cameleer3-server-app -Dtest=ForwardCompatIT -q` | no W0 | pending |
|
||||
| 1-01-01 | 01 | 1 | INGST-04 | unit | `mvn test -pl cameleer-server-core -Dtest=WriteBufferTest -q` | no W0 | pending |
|
||||
| 1-01-02 | 01 | 1 | INGST-01 | integration | `mvn test -pl cameleer-server-app -Dtest=ExecutionControllerIT -q` | no W0 | pending |
|
||||
| 1-01-03 | 01 | 1 | INGST-05 | integration | `mvn test -pl cameleer-server-app -Dtest=BackpressureIT -q` | no W0 | pending |
|
||||
| 1-01-04 | 01 | 1 | INGST-06 | integration | `mvn test -pl cameleer-server-app -Dtest=HealthControllerIT#ttlConfigured* -q` | no W0 | pending |
|
||||
| 1-02-01 | 02 | 1 | INGST-01 | integration | `mvn test -pl cameleer-server-app -Dtest=ExecutionControllerIT -q` | no W0 | pending |
|
||||
| 1-02-02 | 02 | 1 | INGST-02 | integration | `mvn test -pl cameleer-server-app -Dtest=DiagramControllerIT -q` | no W0 | pending |
|
||||
| 1-02-03 | 02 | 1 | INGST-03 | integration | `mvn test -pl cameleer-server-app -Dtest=MetricsControllerIT -q` | no W0 | pending |
|
||||
| 1-02-04 | 02 | 1 | API-02 | integration | `mvn test -pl cameleer-server-app -Dtest=OpenApiIT -q` | no W0 | pending |
|
||||
| 1-02-05 | 02 | 1 | API-03 | integration | `mvn test -pl cameleer-server-app -Dtest=HealthControllerIT -q` | no W0 | pending |
|
||||
| 1-02-06 | 02 | 1 | API-04 | integration | `mvn test -pl cameleer-server-app -Dtest=ProtocolVersionIT -q` | no W0 | pending |
|
||||
| 1-02-07 | 02 | 1 | API-05 | unit | `mvn test -pl cameleer-server-app -Dtest=ForwardCompatIT -q` | no W0 | pending |
|
||||
|
||||
*Status: pending / green / red / flaky*
|
||||
|
||||
@@ -56,10 +56,10 @@ created: 2026-03-11
|
||||
|
||||
## Wave 0 Requirements
|
||||
|
||||
- [ ] `cameleer3-server-app/src/test/resources/application-test.yml` — test ClickHouse config
|
||||
- [ ] `cameleer3-server-core/src/test/java/.../WriteBufferTest.java` — buffer unit tests
|
||||
- [ ] `cameleer3-server-app/src/test/java/.../AbstractClickHouseIT.java` — shared Testcontainers base class
|
||||
- [ ] `cameleer3-server-app/src/test/java/.../ExecutionControllerIT.java` — ingestion integration test
|
||||
- [ ] `cameleer-server-app/src/test/resources/application-test.yml` — test ClickHouse config
|
||||
- [ ] `cameleer-server-core/src/test/java/.../WriteBufferTest.java` — buffer unit tests
|
||||
- [ ] `cameleer-server-app/src/test/java/.../AbstractClickHouseIT.java` — shared Testcontainers base class
|
||||
- [ ] `cameleer-server-app/src/test/java/.../ExecutionControllerIT.java` — ingestion integration test
|
||||
- [ ] Docker available on test machine for Testcontainers
|
||||
|
||||
*If none: "Existing infrastructure covers all phase requirements."*
|
||||
|
||||
@@ -35,27 +35,27 @@ re_verification: false
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|---|---|---|---|
|
||||
| `cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/WriteBuffer.java` | Generic bounded write buffer with offer/drain/isFull | VERIFIED | 80 lines; `ArrayBlockingQueue`-backed; implements `offer`, `offerBatch` (all-or-nothing), `drain`, `isFull`, `size`, `capacity`, `remainingCapacity` |
|
||||
| `cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/WriteBuffer.java` | Generic bounded write buffer with offer/drain/isFull | VERIFIED | 80 lines; `ArrayBlockingQueue`-backed; implements `offer`, `offerBatch` (all-or-nothing), `drain`, `isFull`, `size`, `capacity`, `remainingCapacity` |
|
||||
| `clickhouse/init/01-schema.sql` | ClickHouse DDL for all three tables | VERIFIED | Contains `CREATE TABLE route_executions`, `route_diagrams`, `agent_metrics`; correct ENGINE, ORDER BY, PARTITION BY, TTL with `toDateTime()` cast |
|
||||
| `docker-compose.yml` | Local ClickHouse service | VERIFIED | `clickhouse/clickhouse-server:25.3`; ports 8123/9000; init volume mount; credentials configured |
|
||||
| `cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/ExecutionRepository.java` | Repository interface for execution batch inserts | VERIFIED | Declares `void insertBatch(List<RouteExecution> executions)` |
|
||||
| `cameleer-server-core/src/main/java/com/cameleer/server/core/storage/ExecutionRepository.java` | Repository interface for execution batch inserts | VERIFIED | Declares `void insertBatch(List<RouteExecution> executions)` |
|
||||
|
||||
#### Plan 01-02 Artifacts
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|---|---|---|---|
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/ExecutionController.java` | POST /api/v1/data/executions endpoint | VERIFIED | 79 lines; `@PostMapping("/executions")`; handles single/array via raw String parsing; returns 202 or 503 + Retry-After |
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java` | Batch insert to route_executions via JdbcTemplate | VERIFIED | 118 lines; `@Repository`; `BatchPreparedStatementSetter`; flattens processor tree to parallel arrays |
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/ingestion/ClickHouseFlushScheduler.java` | Scheduled drain of WriteBuffer into ClickHouse | VERIFIED | 160 lines; `@Scheduled(fixedDelayString="${ingestion.flush-interval-ms:1000}")`; implements `SmartLifecycle` for shutdown drain |
|
||||
| `cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/IngestionService.java` | Routes data to appropriate WriteBuffer instances | VERIFIED | 115 lines; plain class; `acceptExecution`, `acceptExecutions`, `acceptDiagram`, `acceptDiagrams`, `acceptMetrics`; delegates to typed `WriteBuffer` instances |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/controller/ExecutionController.java` | POST /api/v1/data/executions endpoint | VERIFIED | 79 lines; `@PostMapping("/executions")`; handles single/array via raw String parsing; returns 202 or 503 + Retry-After |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java` | Batch insert to route_executions via JdbcTemplate | VERIFIED | 118 lines; `@Repository`; `BatchPreparedStatementSetter`; flattens processor tree to parallel arrays |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/ingestion/ClickHouseFlushScheduler.java` | Scheduled drain of WriteBuffer into ClickHouse | VERIFIED | 160 lines; `@Scheduled(fixedDelayString="${ingestion.flush-interval-ms:1000}")`; implements `SmartLifecycle` for shutdown drain |
|
||||
| `cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/IngestionService.java` | Routes data to appropriate WriteBuffer instances | VERIFIED | 115 lines; plain class; `acceptExecution`, `acceptExecutions`, `acceptDiagram`, `acceptDiagrams`, `acceptMetrics`; delegates to typed `WriteBuffer` instances |
|
||||
|
||||
#### Plan 01-03 Artifacts
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|---|---|---|---|
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/interceptor/ProtocolVersionInterceptor.java` | Validates X-Cameleer-Protocol-Version:1 header on data endpoints | VERIFIED | 47 lines; implements `HandlerInterceptor.preHandle`; returns 400 JSON on missing/wrong version |
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java` | Registers interceptor with path patterns | VERIFIED | 35 lines; `addInterceptors` registers interceptor on `/api/v1/data/**` and `/api/v1/agents/**`; excludes health, api-docs, swagger-ui |
|
||||
| `cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java` | Shared Testcontainers base class for integration tests | VERIFIED | 73 lines; static `ClickHouseContainer`; `@DynamicPropertySource`; `@BeforeAll` schema init from SQL file; `JdbcTemplate` exposed to subclasses |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/interceptor/ProtocolVersionInterceptor.java` | Validates X-Cameleer-Protocol-Version:1 header on data endpoints | VERIFIED | 47 lines; implements `HandlerInterceptor.preHandle`; returns 400 JSON on missing/wrong version |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java` | Registers interceptor with path patterns | VERIFIED | 35 lines; `addInterceptors` registers interceptor on `/api/v1/data/**` and `/api/v1/agents/**`; excludes health, api-docs, swagger-ui |
|
||||
| `cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java` | Shared Testcontainers base class for integration tests | VERIFIED | 73 lines; static `ClickHouseContainer`; `@DynamicPropertySource`; `@BeforeAll` schema init from SQL file; `JdbcTemplate` exposed to subclasses |
|
||||
|
||||
---
|
||||
|
||||
@@ -113,7 +113,7 @@ No orphaned requirements — all 11 IDs declared in plan frontmatter match the R
|
||||
|
||||
### Anti-Patterns Found
|
||||
|
||||
No anti-patterns detected. Scanned all source files in `cameleer3-server-app/src/main` and `cameleer3-server-core/src/main` for TODO/FIXME/PLACEHOLDER/stub return patterns. None found.
|
||||
No anti-patterns detected. Scanned all source files in `cameleer-server-app/src/main` and `cameleer-server-core/src/main` for TODO/FIXME/PLACEHOLDER/stub return patterns. None found.
|
||||
|
||||
One minor observation (not a blocker):
|
||||
|
||||
|
||||
@@ -6,17 +6,17 @@ wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- clickhouse/init/02-search-columns.sql
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchRequest.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchResult.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchEngine.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchService.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/ExecutionSummary.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/DetailService.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/ExecutionDetail.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/ProcessorNode.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/ExecutionRepository.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchRequest.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchResult.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchEngine.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchService.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/ExecutionSummary.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/detail/DetailService.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/detail/ExecutionDetail.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/detail/ProcessorNode.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/storage/ExecutionRepository.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- SRCH-01
|
||||
@@ -38,21 +38,21 @@ must_haves:
|
||||
- path: "clickhouse/init/02-search-columns.sql"
|
||||
provides: "Schema extension DDL for Phase 2 columns and skip indexes"
|
||||
contains: "exchange_bodies"
|
||||
- path: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchEngine.java"
|
||||
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchEngine.java"
|
||||
provides: "Search backend abstraction interface"
|
||||
exports: ["SearchEngine"]
|
||||
- path: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchRequest.java"
|
||||
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchRequest.java"
|
||||
provides: "Immutable search criteria record"
|
||||
exports: ["SearchRequest"]
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java"
|
||||
provides: "Extended with new columns in INSERT, plus query methods"
|
||||
min_lines: 100
|
||||
key_links:
|
||||
- from: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchService.java"
|
||||
- from: "cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchService.java"
|
||||
to: "SearchEngine"
|
||||
via: "constructor injection"
|
||||
pattern: "SearchEngine"
|
||||
- from: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java"
|
||||
- from: "cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java"
|
||||
to: "clickhouse/init/02-search-columns.sql"
|
||||
via: "INSERT and SELECT SQL matching schema"
|
||||
pattern: "exchange_bodies|processor_depths|diagram_content_hash"
|
||||
@@ -79,22 +79,22 @@ Output: Schema migration SQL, updated ingestion INSERT with new columns, core se
|
||||
@.planning/phases/02-transaction-search-diagrams/02-RESEARCH.md
|
||||
|
||||
@clickhouse/init/01-schema.sql
|
||||
@cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/ExecutionRepository.java
|
||||
@cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/DiagramRepository.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
@cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java
|
||||
@cameleer-server-core/src/main/java/com/cameleer/server/core/storage/ExecutionRepository.java
|
||||
@cameleer-server-core/src/main/java/com/cameleer/server/core/storage/DiagramRepository.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
@cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java
|
||||
|
||||
<interfaces>
|
||||
<!-- Existing interfaces the executor needs -->
|
||||
|
||||
From cameleer3-server-core/.../storage/ExecutionRepository.java:
|
||||
From cameleer-server-core/.../storage/ExecutionRepository.java:
|
||||
```java
|
||||
public interface ExecutionRepository {
|
||||
void insertBatch(List<RouteExecution> executions);
|
||||
}
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../storage/DiagramRepository.java:
|
||||
From cameleer-server-core/.../storage/DiagramRepository.java:
|
||||
```java
|
||||
public interface DiagramRepository {
|
||||
void store(RouteGraph graph);
|
||||
@@ -103,7 +103,7 @@ public interface DiagramRepository {
|
||||
}
|
||||
```
|
||||
|
||||
From cameleer3-common (decompiled — key fields):
|
||||
From cameleer-common (decompiled — key fields):
|
||||
```java
|
||||
// RouteExecution: routeId, status (ExecutionStatus enum: COMPLETED/FAILED/RUNNING),
|
||||
// startTime (Instant), endTime (Instant), durationMs (long), correlationId, exchangeId,
|
||||
@@ -145,15 +145,15 @@ Existing ClickHouse schema (01-schema.sql):
|
||||
<name>Task 1: Schema extension and core domain types</name>
|
||||
<files>
|
||||
clickhouse/init/02-search-columns.sql,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchRequest.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchResult.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchEngine.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchService.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/ExecutionSummary.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/DetailService.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/ExecutionDetail.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/ProcessorNode.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/ExecutionRepository.java
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchRequest.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchResult.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchEngine.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchService.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/search/ExecutionSummary.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/detail/DetailService.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/detail/ExecutionDetail.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/detail/ProcessorNode.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/storage/ExecutionRepository.java
|
||||
</files>
|
||||
<action>
|
||||
1. Create `clickhouse/init/02-search-columns.sql` with ALTER TABLE statements to add Phase 2 columns to route_executions:
|
||||
@@ -172,14 +172,14 @@ Existing ClickHouse schema (01-schema.sql):
|
||||
- Add tokenbf_v1 skip indexes on exchange_bodies and exchange_headers (GRANULARITY 4, same as idx_error)
|
||||
- Add tokenbf_v1 skip index on error_stacktrace (it has no index yet, needed for SRCH-05 full-text search across stack traces)
|
||||
|
||||
2. Create core search domain types in `com.cameleer3.server.core.search`:
|
||||
2. Create core search domain types in `com.cameleer.server.core.search`:
|
||||
- `SearchRequest` record: status (String, nullable), timeFrom (Instant), timeTo (Instant), durationMin (Long), durationMax (Long), correlationId (String), text (String — global full-text), textInBody (String), textInHeaders (String), textInErrors (String), offset (int), limit (int). Compact constructor validates: limit defaults to 50 if <= 0, capped at 500; offset defaults to 0 if < 0.
|
||||
- `SearchResult<T>` record: data (List<T>), total (long), offset (int), limit (int). Include static factory `empty(int offset, int limit)`.
|
||||
- `ExecutionSummary` record: executionId (String), routeId (String), agentId (String), status (String), startTime (Instant), endTime (Instant), durationMs (long), correlationId (String), errorMessage (String), diagramContentHash (String). This is the lightweight list-view DTO — NOT the full processor arrays.
|
||||
- `SearchEngine` interface with methods: `SearchResult<ExecutionSummary> search(SearchRequest request)` and `long count(SearchRequest request)`. This is the swappable backend (ClickHouse now, OpenSearch later per user decision).
|
||||
- `SearchService` class: plain class (no Spring annotations, same pattern as IngestionService). Constructor takes SearchEngine. `search(SearchRequest)` delegates to engine.search(). This thin orchestration layer allows adding cross-cutting concerns later.
|
||||
|
||||
3. Create core detail domain types in `com.cameleer3.server.core.detail`:
|
||||
3. Create core detail domain types in `com.cameleer.server.core.detail`:
|
||||
- `ProcessorNode` record: processorId (String), processorType (String), status (String), startTime (Instant), endTime (Instant), durationMs (long), diagramNodeId (String), errorMessage (String), errorStackTrace (String), children (List<ProcessorNode>). This is the nested tree node.
|
||||
- `ExecutionDetail` record: executionId (String), routeId (String), agentId (String), status (String), startTime (Instant), endTime (Instant), durationMs (long), correlationId (String), exchangeId (String), errorMessage (String), errorStackTrace (String), diagramContentHash (String), processors (List<ProcessorNode>). This is the full detail response.
|
||||
- `DetailService` class: plain class (no Spring annotations). Constructor takes ExecutionRepository. Method `getDetail(String executionId)` returns `Optional<ExecutionDetail>`. Calls repository's new `findDetailById` method, then calls `reconstructTree()` to convert flat arrays into nested ProcessorNode tree. The `reconstructTree` method: takes parallel arrays (ids, types, statuses, starts, ends, durations, diagramNodeIds, errorMessages, errorStackTraces, depths, parentIndexes), creates ProcessorNode[] array, then wires children using parentIndexes (parentIndex == -1 means root).
|
||||
@@ -190,7 +190,7 @@ Existing ClickHouse schema (01-schema.sql):
|
||||
Actually, use a different approach per the layering: add a `findRawById(String executionId)` method that returns `Optional<RawExecutionRow>` — a new record containing all parallel arrays. DetailService takes this and reconstructs. Create `RawExecutionRow` as a record in the detail package with all fields needed for reconstruction.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer3-server && mvn compile -pl cameleer3-server-core</automated>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer-server && mvn compile -pl cameleer-server-core</automated>
|
||||
</verify>
|
||||
<done>Schema migration SQL exists, all core domain types compile, SearchEngine interface and SearchService defined, ExecutionRepository extended with query method, DetailService has tree reconstruction logic</done>
|
||||
</task>
|
||||
@@ -198,9 +198,9 @@ Existing ClickHouse schema (01-schema.sql):
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Update ingestion to populate new columns and verify with integration test</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/IngestionSchemaIT.java
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/storage/IngestionSchemaIT.java
|
||||
</files>
|
||||
<behavior>
|
||||
- Test: After inserting a RouteExecution with processors that have exchange snapshots and nested children, the route_executions row has non-empty exchange_bodies, exchange_headers, processor_depths (correct depth values), processor_parent_indexes (correct parent wiring), processor_input_bodies, processor_output_bodies, processor_input_headers, processor_output_headers, processor_diagram_node_ids, and diagram_content_hash columns
|
||||
@@ -231,7 +231,7 @@ Existing ClickHouse schema (01-schema.sql):
|
||||
- Verifies a second insertion with null snapshots succeeds with empty defaults
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer3-server && mvn test -pl cameleer3-server-app -Dtest=IngestionSchemaIT</automated>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer-server && mvn test -pl cameleer-server-app -Dtest=IngestionSchemaIT</automated>
|
||||
</verify>
|
||||
<done>All new columns populated correctly during ingestion, tree metadata (depth/parent) correct for nested processors, exchange data concatenated for search, existing ingestion tests still pass</done>
|
||||
</task>
|
||||
@@ -239,9 +239,9 @@ Existing ClickHouse schema (01-schema.sql):
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `mvn compile -pl cameleer3-server-core` succeeds (core domain types compile)
|
||||
- `mvn test -pl cameleer3-server-app -Dtest=IngestionSchemaIT` passes (new columns populated correctly)
|
||||
- `mvn test -pl cameleer3-server-app` passes (all existing tests still green with schema extension)
|
||||
- `mvn compile -pl cameleer-server-core` succeeds (core domain types compile)
|
||||
- `mvn test -pl cameleer-server-app -Dtest=IngestionSchemaIT` passes (new columns populated correctly)
|
||||
- `mvn test -pl cameleer-server-app` passes (all existing tests still green with schema extension)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
|
||||
@@ -22,22 +22,22 @@ tech-stack:
|
||||
key-files:
|
||||
created:
|
||||
- clickhouse/init/02-search-columns.sql
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchRequest.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchResult.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/ExecutionSummary.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchEngine.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/search/SearchService.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/DetailService.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/ExecutionDetail.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/ProcessorNode.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/detail/RawExecutionRow.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/DiagramRenderer.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/DiagramLayout.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/IngestionSchemaIT.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchRequest.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchResult.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/ExecutionSummary.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchEngine.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/search/SearchService.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/detail/DetailService.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/detail/ExecutionDetail.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/detail/ProcessorNode.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/detail/RawExecutionRow.java
|
||||
- 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-app/src/test/java/com/cameleer/server/app/storage/IngestionSchemaIT.java
|
||||
modified:
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/ExecutionRepository.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/storage/ExecutionRepository.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java
|
||||
|
||||
key-decisions:
|
||||
- "FlatProcessor record captures depth and parentIndex during DFS traversal"
|
||||
@@ -86,21 +86,21 @@ Each task was committed atomically:
|
||||
|
||||
## Files Created/Modified
|
||||
- `clickhouse/init/02-search-columns.sql` - ALTER TABLE adding 12 columns + 3 skip indexes
|
||||
- `cameleer3-server-core/.../search/SearchRequest.java` - Immutable search criteria record with validation
|
||||
- `cameleer3-server-core/.../search/SearchResult.java` - Paginated result envelope
|
||||
- `cameleer3-server-core/.../search/ExecutionSummary.java` - Lightweight list-view DTO
|
||||
- `cameleer3-server-core/.../search/SearchEngine.java` - Swappable search backend interface
|
||||
- `cameleer3-server-core/.../search/SearchService.java` - Search orchestration layer
|
||||
- `cameleer3-server-core/.../detail/DetailService.java` - Tree reconstruction from flat arrays
|
||||
- `cameleer3-server-core/.../detail/ExecutionDetail.java` - Full execution detail record
|
||||
- `cameleer3-server-core/.../detail/ProcessorNode.java` - Nested tree node (mutable children)
|
||||
- `cameleer3-server-core/.../detail/RawExecutionRow.java` - DB-to-domain intermediate record
|
||||
- `cameleer3-server-core/.../diagram/DiagramRenderer.java` - Diagram rendering interface (stub)
|
||||
- `cameleer3-server-core/.../diagram/DiagramLayout.java` - JSON layout record (stub)
|
||||
- `cameleer3-server-core/.../storage/ExecutionRepository.java` - Extended with findRawById
|
||||
- `cameleer3-server-app/.../storage/ClickHouseExecutionRepository.java` - INSERT extended with 12 new columns
|
||||
- `cameleer3-server-app/src/test/.../AbstractClickHouseIT.java` - Loads 02-search-columns.sql
|
||||
- `cameleer3-server-app/src/test/.../storage/IngestionSchemaIT.java` - 3 integration tests
|
||||
- `cameleer-server-core/.../search/SearchRequest.java` - Immutable search criteria record with validation
|
||||
- `cameleer-server-core/.../search/SearchResult.java` - Paginated result envelope
|
||||
- `cameleer-server-core/.../search/ExecutionSummary.java` - Lightweight list-view DTO
|
||||
- `cameleer-server-core/.../search/SearchEngine.java` - Swappable search backend interface
|
||||
- `cameleer-server-core/.../search/SearchService.java` - Search orchestration layer
|
||||
- `cameleer-server-core/.../detail/DetailService.java` - Tree reconstruction from flat arrays
|
||||
- `cameleer-server-core/.../detail/ExecutionDetail.java` - Full execution detail record
|
||||
- `cameleer-server-core/.../detail/ProcessorNode.java` - Nested tree node (mutable children)
|
||||
- `cameleer-server-core/.../detail/RawExecutionRow.java` - DB-to-domain intermediate record
|
||||
- `cameleer-server-core/.../diagram/DiagramRenderer.java` - Diagram rendering interface (stub)
|
||||
- `cameleer-server-core/.../diagram/DiagramLayout.java` - JSON layout record (stub)
|
||||
- `cameleer-server-core/.../storage/ExecutionRepository.java` - Extended with findRawById
|
||||
- `cameleer-server-app/.../storage/ClickHouseExecutionRepository.java` - INSERT extended with 12 new columns
|
||||
- `cameleer-server-app/src/test/.../AbstractClickHouseIT.java` - Loads 02-search-columns.sql
|
||||
- `cameleer-server-app/src/test/.../storage/IngestionSchemaIT.java` - 3 integration tests
|
||||
|
||||
## Decisions Made
|
||||
- Used FlatProcessor record to carry depth and parentIndex alongside the ProcessorExecution during DFS flattening -- single pass, no separate traversal
|
||||
@@ -116,9 +116,9 @@ Each task was committed atomically:
|
||||
**1. [Rule 3 - Blocking] Created DiagramRenderer and DiagramLayout stub interfaces**
|
||||
- **Found during:** Task 2 (compilation step)
|
||||
- **Issue:** Pre-existing `ElkDiagramRenderer` in app module referenced `DiagramRenderer` and `DiagramLayout` interfaces that did not exist in core module, causing compilation failure
|
||||
- **Fix:** Created minimal stub interfaces in `com.cameleer3.server.core.diagram` package
|
||||
- **Fix:** Created minimal stub interfaces in `com.cameleer.server.core.diagram` package
|
||||
- **Files created:** DiagramRenderer.java, DiagramLayout.java
|
||||
- **Verification:** `mvn compile -pl cameleer3-server-core` and `mvn compile -pl cameleer3-server-app` succeed
|
||||
- **Verification:** `mvn compile -pl cameleer-server-core` and `mvn compile -pl cameleer-server-app` succeed
|
||||
- **Committed in:** f6ff279 (Task 2 GREEN commit)
|
||||
|
||||
**2. [Rule 1 - Bug] Fixed ClickHouse Array type handling in IngestionSchemaIT**
|
||||
|
||||
@@ -5,16 +5,16 @@ type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- cameleer3-server-app/pom.xml
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/DiagramRenderer.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/DiagramLayout.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/PositionedNode.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/PositionedEdge.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DiagramRenderController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/DiagramBeanConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramRenderControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/diagram/ElkDiagramRendererTest.java
|
||||
- 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
|
||||
@@ -27,13 +27,13 @@ must_haves:
|
||||
- "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: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/DiagramRenderer.java"
|
||||
- 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: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/diagram/ElkDiagramRenderer.java"
|
||||
provides: "ELK + JFreeSVG implementation of DiagramRenderer"
|
||||
min_lines: 100
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DiagramRenderController.java"
|
||||
- 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:
|
||||
@@ -70,14 +70,14 @@ Output: DiagramRenderer interface in core, ElkDiagramRenderer implementation in
|
||||
@.planning/phases/02-transaction-search-diagrams/02-CONTEXT.md
|
||||
@.planning/phases/02-transaction-search-diagrams/02-RESEARCH.md
|
||||
|
||||
@cameleer3-server-core/src/main/java/com/cameleer3/server/core/storage/DiagramRepository.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseDiagramRepository.java
|
||||
@cameleer3-server-app/pom.xml
|
||||
@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
|
||||
|
||||
<interfaces>
|
||||
<!-- Existing interfaces needed -->
|
||||
|
||||
From cameleer3-server-core/.../storage/DiagramRepository.java:
|
||||
From cameleer-server-core/.../storage/DiagramRepository.java:
|
||||
```java
|
||||
public interface DiagramRepository {
|
||||
void store(RouteGraph graph);
|
||||
@@ -86,7 +86,7 @@ public interface DiagramRepository {
|
||||
}
|
||||
```
|
||||
|
||||
From cameleer3-common (decompiled — diagram models):
|
||||
From cameleer-common (decompiled — diagram models):
|
||||
```java
|
||||
// RouteGraph: routeId (String), nodes (List<RouteNode>), edges (List<RouteEdge>),
|
||||
// processorNodeMapping (Map<String,String>)
|
||||
@@ -114,14 +114,14 @@ NodeType color mapping (from CONTEXT.md, matching route-diagram-example.html):
|
||||
<task type="auto">
|
||||
<name>Task 1: Add ELK/JFreeSVG dependencies and create core diagram rendering interfaces</name>
|
||||
<files>
|
||||
cameleer3-server-app/pom.xml,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/DiagramRenderer.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/DiagramLayout.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/PositionedNode.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/PositionedEdge.java
|
||||
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
|
||||
</files>
|
||||
<action>
|
||||
1. Add Maven dependencies to `cameleer3-server-app/pom.xml`:
|
||||
1. Add Maven dependencies to `cameleer-server-app/pom.xml`:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.eclipse.elk</groupId>
|
||||
@@ -140,7 +140,7 @@ NodeType color mapping (from CONTEXT.md, matching route-diagram-example.html):
|
||||
</dependency>
|
||||
```
|
||||
|
||||
2. Create core diagram rendering interfaces in `com.cameleer3.server.core.diagram`:
|
||||
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<PositionedNode> — for compound/swimlane groups). JSON-serializable for the JSON layout response.
|
||||
|
||||
@@ -154,7 +154,7 @@ NodeType color mapping (from CONTEXT.md, matching route-diagram-example.html):
|
||||
Both methods take a RouteGraph and produce output. The interface lives in core so it can be swapped (e.g., for a different renderer).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer3-server && mvn compile -pl cameleer3-server-core && mvn dependency:resolve -pl cameleer3-server-app -q</automated>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer-server && mvn compile -pl cameleer-server-core && mvn dependency:resolve -pl cameleer-server-app -q</automated>
|
||||
</verify>
|
||||
<done>ELK and JFreeSVG dependencies resolve, DiagramRenderer interface and layout DTOs compile in core module</done>
|
||||
</task>
|
||||
@@ -162,11 +162,11 @@ NodeType color mapping (from CONTEXT.md, matching route-diagram-example.html):
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Implement ElkDiagramRenderer, DiagramRenderController, and integration tests</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DiagramRenderController.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/DiagramBeanConfig.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/diagram/ElkDiagramRendererTest.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramRenderControllerIT.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
|
||||
</files>
|
||||
<behavior>
|
||||
- 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
|
||||
@@ -179,7 +179,7 @@ NodeType color mapping (from CONTEXT.md, matching route-diagram-example.html):
|
||||
- Integration test: GET /api/v1/diagrams/{hash} with no Accept preference defaults to SVG
|
||||
</behavior>
|
||||
<action>
|
||||
1. Create `ElkDiagramRenderer` implementing `DiagramRenderer` in `com.cameleer3.server.app.diagram`:
|
||||
1. Create `ElkDiagramRenderer` implementing `DiagramRenderer` in `com.cameleer.server.app.diagram`:
|
||||
|
||||
**Layout phase (shared by both SVG and JSON):**
|
||||
- Convert RouteGraph to ELK graph: create ElkNode root, set properties for LayeredOptions.ALGORITHM_ID, Direction.DOWN (top-to-bottom per user decision), spacing 40px node-node, 20px edge-node.
|
||||
@@ -206,10 +206,10 @@ NodeType color mapping (from CONTEXT.md, matching route-diagram-example.html):
|
||||
**JSON layout (layoutJson):**
|
||||
- Run layout phase, return DiagramLayout directly. Jackson will serialize it to JSON.
|
||||
|
||||
2. Create `DiagramBeanConfig` in `com.cameleer3.server.app.config`:
|
||||
2. Create `DiagramBeanConfig` in `com.cameleer.server.app.config`:
|
||||
- @Configuration class that creates DiagramRenderer bean (ElkDiagramRenderer) and SearchService bean wiring (prepare for Plan 03).
|
||||
|
||||
3. Create `DiagramRenderController` in `com.cameleer3.server.app.controller`:
|
||||
3. Create `DiagramRenderController` in `com.cameleer.server.app.controller`:
|
||||
- `GET /api/v1/diagrams/{contentHash}/render` — renders the diagram
|
||||
- Inject DiagramRepository and DiagramRenderer.
|
||||
- Look up RouteGraph via `diagramRepository.findByContentHash(contentHash)`. If empty, return 404.
|
||||
@@ -233,7 +233,7 @@ NodeType color mapping (from CONTEXT.md, matching route-diagram-example.html):
|
||||
- GET /api/v1/diagrams/{hash}/render with no Accept header -> assert SVG response (default).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer3-server && mvn test -pl cameleer3-server-app -Dtest="ElkDiagramRendererTest,DiagramRenderControllerIT"</automated>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer-server && mvn test -pl cameleer-server-app -Dtest="ElkDiagramRendererTest,DiagramRenderControllerIT"</automated>
|
||||
</verify>
|
||||
<done>Diagram rendering produces color-coded top-to-bottom SVG and JSON layout, content negotiation works via Accept header, compound nodes group nested processors, all tests pass</done>
|
||||
</task>
|
||||
@@ -241,8 +241,8 @@ NodeType color mapping (from CONTEXT.md, matching route-diagram-example.html):
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `mvn test -pl cameleer3-server-app -Dtest=ElkDiagramRendererTest` passes (unit tests for layout and SVG)
|
||||
- `mvn test -pl cameleer3-server-app -Dtest=DiagramRenderControllerIT` passes (integration tests for REST endpoint)
|
||||
- `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
|
||||
</verification>
|
||||
|
||||
@@ -21,17 +21,17 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/DiagramRenderer.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/DiagramLayout.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/PositionedNode.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/diagram/PositionedEdge.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/diagram/ElkDiagramRenderer.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DiagramRenderController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/DiagramBeanConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/diagram/ElkDiagramRendererTest.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramRenderControllerIT.java
|
||||
- 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:
|
||||
- cameleer3-server-app/pom.xml
|
||||
- cameleer-server-app/pom.xml
|
||||
|
||||
key-decisions:
|
||||
- "Used ELK layered algorithm with top-to-bottom direction for route diagram layout"
|
||||
@@ -78,16 +78,16 @@ Each task was committed atomically:
|
||||
2. **Task 2: Implement ElkDiagramRenderer, DiagramRenderController, and integration tests** - `c1bc32d` (feat, TDD)
|
||||
|
||||
## Files Created/Modified
|
||||
- `cameleer3-server-core/.../diagram/DiagramRenderer.java` - Renderer interface with renderSvg and layoutJson
|
||||
- `cameleer3-server-core/.../diagram/DiagramLayout.java` - Layout record (width, height, nodes, edges)
|
||||
- `cameleer3-server-core/.../diagram/PositionedNode.java` - Node record with position, dimensions, children
|
||||
- `cameleer3-server-core/.../diagram/PositionedEdge.java` - Edge record with waypoints
|
||||
- `cameleer3-server-app/.../diagram/ElkDiagramRenderer.java` - ELK + JFreeSVG implementation (~400 lines)
|
||||
- `cameleer3-server-app/.../controller/DiagramRenderController.java` - GET /api/v1/diagrams/{hash}/render
|
||||
- `cameleer3-server-app/.../config/DiagramBeanConfig.java` - Spring bean wiring for DiagramRenderer
|
||||
- `cameleer3-server-app/pom.xml` - Added ELK, JFreeSVG, xtext dependencies
|
||||
- `cameleer3-server-app/.../diagram/ElkDiagramRendererTest.java` - 11 unit tests
|
||||
- `cameleer3-server-app/.../controller/DiagramRenderControllerIT.java` - 4 integration tests
|
||||
- `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
|
||||
@@ -104,7 +104,7 @@ Each task was committed atomically:
|
||||
- **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:** cameleer3-server-app/pom.xml
|
||||
- **Files modified:** cameleer-server-app/pom.xml
|
||||
- **Verification:** All unit tests pass after adding dependency
|
||||
- **Committed in:** c1bc32d (Task 2 commit)
|
||||
|
||||
@@ -119,7 +119,7 @@ Each task was committed atomically:
|
||||
**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 cameleer3-common jar in all color mapping sets
|
||||
- **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)
|
||||
|
||||
@@ -6,14 +6,14 @@ wave: 2
|
||||
depends_on:
|
||||
- "02-01"
|
||||
files_modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchEngine.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/SearchController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DetailController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/SearchBeanConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/SearchControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DetailControllerIT.java
|
||||
- cameleer3-server-core/src/test/java/com/cameleer3/server/core/detail/TreeReconstructionTest.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/search/ClickHouseSearchEngine.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/SearchController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DetailController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/SearchBeanConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DetailControllerIT.java
|
||||
- cameleer-server-core/src/test/java/com/cameleer/server/core/detail/TreeReconstructionTest.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- SRCH-01
|
||||
@@ -35,16 +35,16 @@ must_haves:
|
||||
- "Detail response includes diagramContentHash for linking to diagram endpoint"
|
||||
- "Search results are paginated with total count, offset, and limit"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchEngine.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/search/ClickHouseSearchEngine.java"
|
||||
provides: "ClickHouse implementation of SearchEngine with dynamic WHERE building"
|
||||
min_lines: 80
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/SearchController.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/controller/SearchController.java"
|
||||
provides: "GET + POST /api/v1/search/executions endpoints"
|
||||
exports: ["SearchController"]
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DetailController.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DetailController.java"
|
||||
provides: "GET /api/v1/executions/{id} endpoint returning nested tree"
|
||||
exports: ["DetailController"]
|
||||
- path: "cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/SearchControllerIT.java"
|
||||
- path: "cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java"
|
||||
provides: "Integration tests for all search filter combinations"
|
||||
min_lines: 100
|
||||
key_links:
|
||||
@@ -92,13 +92,13 @@ Output: SearchController (GET + POST), DetailController, ClickHouseSearchEngine,
|
||||
|
||||
@clickhouse/init/01-schema.sql
|
||||
@clickhouse/init/02-search-columns.sql
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/ExecutionController.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/controller/ExecutionController.java
|
||||
|
||||
<interfaces>
|
||||
<!-- Core types created by Plan 01 — executor reads these from plan 01 SUMMARY -->
|
||||
|
||||
From cameleer3-server-core/.../search/SearchEngine.java:
|
||||
From cameleer-server-core/.../search/SearchEngine.java:
|
||||
```java
|
||||
public interface SearchEngine {
|
||||
SearchResult<ExecutionSummary> search(SearchRequest request);
|
||||
@@ -106,7 +106,7 @@ public interface SearchEngine {
|
||||
}
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../search/SearchRequest.java:
|
||||
From cameleer-server-core/.../search/SearchRequest.java:
|
||||
```java
|
||||
public record SearchRequest(
|
||||
String status, // nullable, filter by ExecutionStatus name
|
||||
@@ -124,14 +124,14 @@ public record SearchRequest(
|
||||
) { /* compact constructor with validation */ }
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../search/SearchResult.java:
|
||||
From cameleer-server-core/.../search/SearchResult.java:
|
||||
```java
|
||||
public record SearchResult<T>(List<T> data, long total, int offset, int limit) {
|
||||
public static <T> SearchResult<T> empty(int offset, int limit);
|
||||
}
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../search/ExecutionSummary.java:
|
||||
From cameleer-server-core/.../search/ExecutionSummary.java:
|
||||
```java
|
||||
public record ExecutionSummary(
|
||||
String executionId, String routeId, String agentId, String status,
|
||||
@@ -140,7 +140,7 @@ public record ExecutionSummary(
|
||||
) {}
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../detail/DetailService.java:
|
||||
From cameleer-server-core/.../detail/DetailService.java:
|
||||
```java
|
||||
public class DetailService {
|
||||
// Constructor takes ExecutionRepository (or a query interface)
|
||||
@@ -149,7 +149,7 @@ public class DetailService {
|
||||
}
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../detail/ExecutionDetail.java:
|
||||
From cameleer-server-core/.../detail/ExecutionDetail.java:
|
||||
```java
|
||||
public record ExecutionDetail(
|
||||
String executionId, String routeId, String agentId, String status,
|
||||
@@ -160,7 +160,7 @@ public record ExecutionDetail(
|
||||
) {}
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../detail/ProcessorNode.java:
|
||||
From cameleer-server-core/.../detail/ProcessorNode.java:
|
||||
```java
|
||||
public record ProcessorNode(
|
||||
String processorId, String processorType, String status,
|
||||
@@ -201,10 +201,10 @@ Established controller pattern (from Phase 1):
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: ClickHouseSearchEngine, SearchController, and search integration tests</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchEngine.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/SearchController.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/SearchBeanConfig.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/SearchControllerIT.java
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/search/ClickHouseSearchEngine.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/SearchController.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/config/SearchBeanConfig.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java
|
||||
</files>
|
||||
<behavior>
|
||||
- Test searchByStatus: Insert 3 executions (COMPLETED, FAILED, RUNNING). GET /api/v1/search/executions?status=FAILED returns only the FAILED execution. Response has envelope: {"data":[...],"total":1,"offset":0,"limit":50}
|
||||
@@ -221,7 +221,7 @@ Established controller pattern (from Phase 1):
|
||||
- Test emptyResults: Search with no matches returns {"data":[],"total":0,"offset":0,"limit":50}
|
||||
</behavior>
|
||||
<action>
|
||||
1. Create `ClickHouseSearchEngine` in `com.cameleer3.server.app.search`:
|
||||
1. Create `ClickHouseSearchEngine` in `com.cameleer.server.app.search`:
|
||||
- Implements SearchEngine interface from core module.
|
||||
- Constructor takes JdbcTemplate.
|
||||
- `search(SearchRequest)` method:
|
||||
@@ -244,13 +244,13 @@ Established controller pattern (from Phase 1):
|
||||
- `escapeLike(String)` utility: escape `%`, `_`, `\` characters in user input to prevent LIKE injection. Replace `\` with `\\`, `%` with `\%`, `_` with `\_`.
|
||||
- `count(SearchRequest)` method: same WHERE building, just count query.
|
||||
|
||||
2. Create `SearchBeanConfig` in `com.cameleer3.server.app.config`:
|
||||
2. Create `SearchBeanConfig` in `com.cameleer.server.app.config`:
|
||||
- @Configuration class that creates:
|
||||
- `ClickHouseSearchEngine` bean (takes JdbcTemplate)
|
||||
- `SearchService` bean (takes SearchEngine)
|
||||
- `DetailService` bean (takes the execution query interface from Plan 01)
|
||||
|
||||
3. Create `SearchController` in `com.cameleer3.server.app.controller`:
|
||||
3. Create `SearchController` in `com.cameleer.server.app.controller`:
|
||||
- Inject SearchService.
|
||||
- `GET /api/v1/search/executions` with @RequestParam for basic filters:
|
||||
- status (optional String)
|
||||
@@ -274,7 +274,7 @@ Established controller pattern (from Phase 1):
|
||||
- Assert response structure matches the envelope format.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer3-server && mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT</automated>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer-server && mvn test -pl cameleer-server-app -Dtest=SearchControllerIT</automated>
|
||||
</verify>
|
||||
<done>All search filter types work independently and in combination, response envelope has correct format, pagination works correctly, full-text search finds matches in all text fields, LIKE patterns are properly escaped</done>
|
||||
</task>
|
||||
@@ -282,10 +282,10 @@ Established controller pattern (from Phase 1):
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: DetailController, tree reconstruction, exchange snapshot endpoint, and integration tests</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DetailController.java,
|
||||
cameleer3-server-core/src/test/java/com/cameleer3/server/core/detail/TreeReconstructionTest.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DetailControllerIT.java
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DetailController.java,
|
||||
cameleer-server-core/src/test/java/com/cameleer/server/core/detail/TreeReconstructionTest.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DetailControllerIT.java
|
||||
</files>
|
||||
<behavior>
|
||||
- Unit test: reconstructTree with [root, child, grandchild], depths=[0,1,2], parents=[-1,0,1] produces single root with one child that has one grandchild
|
||||
@@ -308,7 +308,7 @@ Established controller pattern (from Phase 1):
|
||||
- Add `findRawById(String executionId)` method that queries all columns from route_executions WHERE execution_id = ?. Return Optional<RawExecutionRow> (use the record created in Plan 01 or create it here if needed). The RawExecutionRow should contain ALL columns including the parallel arrays for processors.
|
||||
- Add `findProcessorSnapshot(String executionId, int processorIndex)` method: queries processor_input_bodies[index+1], processor_output_bodies[index+1], processor_input_headers[index+1], processor_output_headers[index+1] for the given execution. Returns a DTO with inputBody, outputBody, inputHeaders, outputHeaders. ClickHouse arrays are 1-indexed in SQL, so add 1 to the Java 0-based index.
|
||||
|
||||
3. Create `DetailController` in `com.cameleer3.server.app.controller`:
|
||||
3. Create `DetailController` in `com.cameleer.server.app.controller`:
|
||||
- Inject DetailService.
|
||||
- `GET /api/v1/executions/{executionId}`: call detailService.getDetail(executionId). If empty, return 404. Otherwise return 200 with ExecutionDetail JSON. The processors field is a nested tree of ProcessorNode objects.
|
||||
- `GET /api/v1/executions/{executionId}/processors/{index}/snapshot`: call repository's findProcessorSnapshot. If execution not found or index out of bounds, return 404. Return JSON with inputBody, outputBody, inputHeaders, outputHeaders. Per user decision: exchange snapshot data fetched separately per processor, not inlined in detail response.
|
||||
@@ -323,7 +323,7 @@ Established controller pattern (from Phase 1):
|
||||
- Test GET /api/v1/executions/{id}/processors/999/snapshot: returns 404 for out-of-bounds index.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer3-server && mvn test -pl cameleer3-server-core -Dtest=TreeReconstructionTest && mvn test -pl cameleer3-server-app -Dtest=DetailControllerIT</automated>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer-server && mvn test -pl cameleer-server-core -Dtest=TreeReconstructionTest && mvn test -pl cameleer-server-app -Dtest=DetailControllerIT</automated>
|
||||
</verify>
|
||||
<done>Tree reconstruction correctly rebuilds nested processor trees from flat arrays, detail endpoint returns nested tree with all fields, snapshot endpoint returns per-processor exchange data, diagram hash included in detail response, all tests pass</done>
|
||||
</task>
|
||||
@@ -331,9 +331,9 @@ Established controller pattern (from Phase 1):
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `mvn test -pl cameleer3-server-core -Dtest=TreeReconstructionTest` passes (unit test for tree rebuild)
|
||||
- `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT` passes (all search filters)
|
||||
- `mvn test -pl cameleer3-server-app -Dtest=DetailControllerIT` passes (detail + snapshot)
|
||||
- `mvn test -pl cameleer-server-core -Dtest=TreeReconstructionTest` passes (unit test for tree rebuild)
|
||||
- `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT` passes (all search filters)
|
||||
- `mvn test -pl cameleer-server-app -Dtest=DetailControllerIT` passes (detail + snapshot)
|
||||
- `mvn clean verify` passes (full suite green)
|
||||
</verification>
|
||||
|
||||
|
||||
@@ -21,16 +21,16 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/ClickHouseSearchEngine.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/SearchController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/DetailController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/SearchBeanConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/SearchControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DetailControllerIT.java
|
||||
- cameleer3-server-core/src/test/java/com/cameleer3/server/core/detail/TreeReconstructionTest.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/search/ClickHouseSearchEngine.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/SearchController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/DetailController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/SearchBeanConfig.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DetailControllerIT.java
|
||||
- cameleer-server-core/src/test/java/com/cameleer/server/core/detail/TreeReconstructionTest.java
|
||||
modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer3-server-core/pom.xml
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer-server-core/pom.xml
|
||||
|
||||
key-decisions:
|
||||
- "Search tests use correlationId scoping and >= assertions for shared ClickHouse isolation"
|
||||
@@ -77,15 +77,15 @@ Each task was committed atomically:
|
||||
3. **Task 2 fix: Test isolation for shared ClickHouse** - `079dce5` (fix)
|
||||
|
||||
## Files Created/Modified
|
||||
- `cameleer3-server-app/.../search/ClickHouseSearchEngine.java` - Dynamic SQL search with LIKE escape, implements SearchEngine
|
||||
- `cameleer3-server-app/.../controller/SearchController.java` - GET + POST /api/v1/search/executions endpoints
|
||||
- `cameleer3-server-app/.../controller/DetailController.java` - GET /api/v1/executions/{id} and processor snapshot endpoints
|
||||
- `cameleer3-server-app/.../config/SearchBeanConfig.java` - Wires SearchEngine, SearchService, DetailService beans
|
||||
- `cameleer3-server-app/.../storage/ClickHouseExecutionRepository.java` - Added findRawById, findProcessorSnapshot, array extraction helpers
|
||||
- `cameleer3-server-app/.../controller/SearchControllerIT.java` - 13 integration tests for search
|
||||
- `cameleer3-server-app/.../controller/DetailControllerIT.java` - 6 integration tests for detail/snapshot
|
||||
- `cameleer3-server-core/.../detail/TreeReconstructionTest.java` - 5 unit tests for tree reconstruction
|
||||
- `cameleer3-server-core/pom.xml` - Added assertj and mockito test dependencies
|
||||
- `cameleer-server-app/.../search/ClickHouseSearchEngine.java` - Dynamic SQL search with LIKE escape, implements SearchEngine
|
||||
- `cameleer-server-app/.../controller/SearchController.java` - GET + POST /api/v1/search/executions endpoints
|
||||
- `cameleer-server-app/.../controller/DetailController.java` - GET /api/v1/executions/{id} and processor snapshot endpoints
|
||||
- `cameleer-server-app/.../config/SearchBeanConfig.java` - Wires SearchEngine, SearchService, DetailService beans
|
||||
- `cameleer-server-app/.../storage/ClickHouseExecutionRepository.java` - Added findRawById, findProcessorSnapshot, array extraction helpers
|
||||
- `cameleer-server-app/.../controller/SearchControllerIT.java` - 13 integration tests for search
|
||||
- `cameleer-server-app/.../controller/DetailControllerIT.java` - 6 integration tests for detail/snapshot
|
||||
- `cameleer-server-core/.../detail/TreeReconstructionTest.java` - 5 unit tests for tree reconstruction
|
||||
- `cameleer-server-core/pom.xml` - Added assertj and mockito test dependencies
|
||||
|
||||
## Decisions Made
|
||||
- Search tests use correlationId scoping and >= assertions to remain stable when other test classes seed data in the shared ClickHouse container
|
||||
@@ -99,8 +99,8 @@ Each task was committed atomically:
|
||||
**1. [Rule 3 - Blocking] Added assertj and mockito test dependencies to core module**
|
||||
- **Found during:** Task 2 (TreeReconstructionTest compilation)
|
||||
- **Issue:** Core module only had JUnit Jupiter as test dependency, TreeReconstructionTest needed assertj for assertions and mockito for mock(ExecutionRepository.class)
|
||||
- **Fix:** Added assertj-core and mockito-core test-scoped dependencies to cameleer3-server-core/pom.xml
|
||||
- **Files modified:** cameleer3-server-core/pom.xml
|
||||
- **Fix:** Added assertj-core and mockito-core test-scoped dependencies to cameleer-server-core/pom.xml
|
||||
- **Files modified:** cameleer-server-core/pom.xml
|
||||
- **Committed in:** 0615a98 (Task 2 commit)
|
||||
|
||||
**2. [Rule 1 - Bug] Fixed search tests failing with shared ClickHouse data**
|
||||
|
||||
@@ -5,9 +5,9 @@ type: execute
|
||||
wave: 1
|
||||
depends_on: ["02-01", "02-02", "02-03"]
|
||||
files_modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer3-server-app/pom.xml
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer-server-app/pom.xml
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/storage/DiagramLinkingIT.java
|
||||
autonomous: true
|
||||
gap_closure: true
|
||||
requirements: ["DIAG-02"]
|
||||
@@ -17,13 +17,13 @@ must_haves:
|
||||
- "Each transaction links to the RouteGraph version that was active at execution time"
|
||||
- "Full test suite passes with mvn clean verify (no classloader failures)"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java"
|
||||
provides: "Diagram hash lookup during batch insert"
|
||||
contains: "findContentHashForRoute"
|
||||
- path: "cameleer3-server-app/pom.xml"
|
||||
- path: "cameleer-server-app/pom.xml"
|
||||
provides: "Surefire fork configuration isolating ELK classloader"
|
||||
contains: "reuseForks"
|
||||
- path: "cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java"
|
||||
- path: "cameleer-server-app/src/test/java/com/cameleer/server/app/storage/DiagramLinkingIT.java"
|
||||
provides: "Integration test proving diagram hash is stored during ingestion"
|
||||
key_links:
|
||||
- from: "ClickHouseExecutionRepository"
|
||||
@@ -57,18 +57,18 @@ Prior plan summaries (needed — touches same files):
|
||||
<interfaces>
|
||||
<!-- Key types and contracts the executor needs. -->
|
||||
|
||||
From cameleer3-server-core/.../storage/DiagramRepository.java:
|
||||
From cameleer-server-core/.../storage/DiagramRepository.java:
|
||||
```java
|
||||
Optional<String> findContentHashForRoute(String routeId, String agentId);
|
||||
```
|
||||
|
||||
From cameleer3-server-app/.../storage/ClickHouseExecutionRepository.java (line 141):
|
||||
From cameleer-server-app/.../storage/ClickHouseExecutionRepository.java (line 141):
|
||||
```java
|
||||
ps.setString(col++, ""); // diagram_content_hash (wired later)
|
||||
```
|
||||
The class is @Repository annotated, constructor takes JdbcTemplate only. It needs DiagramRepository injected to perform the lookup.
|
||||
|
||||
From cameleer3-server-app/.../storage/ClickHouseDiagramRepository.java:
|
||||
From cameleer-server-app/.../storage/ClickHouseDiagramRepository.java:
|
||||
```java
|
||||
@Repository
|
||||
public class ClickHouseDiagramRepository implements DiagramRepository {
|
||||
@@ -83,9 +83,9 @@ public class ClickHouseDiagramRepository implements DiagramRepository {
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: Populate diagram_content_hash during ingestion and fix Surefire forks</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java,
|
||||
cameleer3-server-app/pom.xml,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java,
|
||||
cameleer-server-app/pom.xml,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/storage/DiagramLinkingIT.java
|
||||
</files>
|
||||
<behavior>
|
||||
- Test 1: When a RouteGraph is ingested before a RouteExecution for the same routeId+agentId, the execution's diagram_content_hash column contains the SHA-256 hash of the diagram (not empty string)
|
||||
@@ -117,7 +117,7 @@ public class ClickHouseDiagramRepository implements DiagramRepository {
|
||||
|
||||
**Gap 2 — Surefire classloader isolation:**
|
||||
|
||||
5. In `cameleer3-server-app/pom.xml`, add a `<build><plugins>` section (after the existing `spring-boot-maven-plugin`) with `maven-surefire-plugin` configuration:
|
||||
5. In `cameleer-server-app/pom.xml`, add a `<build><plugins>` section (after the existing `spring-boot-maven-plugin`) with `maven-surefire-plugin` configuration:
|
||||
```xml
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -131,12 +131,12 @@ public class ClickHouseDiagramRepository implements DiagramRepository {
|
||||
This forces Surefire to fork a fresh JVM for each test class, isolating ELK's static initializer (LayeredMetaDataProvider + xtext CollectionLiterals) from Spring Boot's classloader. Trade-off: slightly slower test execution, but correct results.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer3-server && mvn clean verify -pl cameleer3-server-app -am 2>&1 | tail -30</automated>
|
||||
<automated>cd C:/Users/Hendrik/Documents/projects/cameleer-server && mvn clean verify -pl cameleer-server-app -am 2>&1 | tail -30</automated>
|
||||
</verify>
|
||||
<done>
|
||||
- diagram_content_hash is populated with the active diagram's SHA-256 hash during ingestion (not empty string)
|
||||
- DiagramLinkingIT passes with both positive and negative cases
|
||||
- `mvn clean verify` passes for cameleer3-server-app (no classloader failures from ElkDiagramRendererTest)
|
||||
- `mvn clean verify` passes for cameleer-server-app (no classloader failures from ElkDiagramRendererTest)
|
||||
</done>
|
||||
</task>
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/storage/DiagramLinkingIT.java
|
||||
modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer3-server-app/pom.xml
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/IngestionSchemaIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/SearchControllerIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java
|
||||
- cameleer-server-app/pom.xml
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/storage/IngestionSchemaIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java
|
||||
|
||||
key-decisions:
|
||||
- "DiagramRepository injected via constructor into ClickHouseExecutionRepository for diagram hash lookup during batch insert"
|
||||
@@ -69,11 +69,11 @@ Each task was committed atomically:
|
||||
**Plan metadata:** (pending)
|
||||
|
||||
## Files Created/Modified
|
||||
- `cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java` - Added DiagramRepository injection, diagram hash lookup in insertBatch
|
||||
- `cameleer3-server-app/pom.xml` - Added maven-surefire-plugin and maven-failsafe-plugin with reuseForks=false
|
||||
- `cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java` - Integration test for diagram hash linking
|
||||
- `cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/IngestionSchemaIT.java` - Added ignoreExceptions + increased timeouts
|
||||
- `cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/SearchControllerIT.java` - Adjusted pagination assertion count
|
||||
- `cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java` - Added DiagramRepository injection, diagram hash lookup in insertBatch
|
||||
- `cameleer-server-app/pom.xml` - Added maven-surefire-plugin and maven-failsafe-plugin with reuseForks=false
|
||||
- `cameleer-server-app/src/test/java/com/cameleer/server/app/storage/DiagramLinkingIT.java` - Integration test for diagram hash linking
|
||||
- `cameleer-server-app/src/test/java/com/cameleer/server/app/storage/IngestionSchemaIT.java` - Added ignoreExceptions + increased timeouts
|
||||
- `cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java` - Adjusted pagination assertion count
|
||||
|
||||
## Decisions Made
|
||||
- DiagramRepository injected via constructor into ClickHouseExecutionRepository -- both are @Repository Spring beans, so constructor injection autowires cleanly
|
||||
|
||||
@@ -44,7 +44,7 @@ Users can find any transaction by status, time, duration, correlation ID, or con
|
||||
- No execution overlay in server-rendered SVG — the UI handles overlay with theme support (dark/light)
|
||||
- Top-to-bottom node layout flow
|
||||
- Nested processors (inside for-each, split, try-catch) rendered in swimlanes to highlight nesting/scope
|
||||
- Reference: cameleer3 agent repo `examples/route-diagram-example.html` for visual style inspiration (color-coded node types, EIP icons)
|
||||
- Reference: cameleer agent repo `examples/route-diagram-example.html` for visual style inspiration (color-coded node types, EIP icons)
|
||||
|
||||
### Claude's Discretion
|
||||
- Pagination implementation details (offset/limit vs cursor)
|
||||
@@ -58,7 +58,7 @@ Users can find any transaction by status, time, duration, correlation ID, or con
|
||||
<specifics>
|
||||
## Specific Ideas
|
||||
|
||||
- "We want a cmd+k type of search in the UI" — see `cameleer3/examples/cmd-k-search-example.html` for the target UX. Key features:
|
||||
- "We want a cmd+k type of search in the UI" — see `cameleer/examples/cmd-k-search-example.html` for the target UX. Key features:
|
||||
- Cross-entity search: single query hits Executions, Routes, Exchanges, Agents with scope tabs and counts
|
||||
- Filter chips in the input (e.g., `route:order` prefix filtering)
|
||||
- Inline preview pane with JSON syntax highlighting for selected result
|
||||
|
||||
@@ -112,7 +112,7 @@ The existing Phase 1 code provides a solid foundation: `ClickHouseExecutionRepos
|
||||
|
||||
### Recommended Project Structure (additions for Phase 2)
|
||||
```
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/
|
||||
├── search/
|
||||
│ ├── SearchService.java # Orchestrates search, delegates to SearchEngine
|
||||
│ ├── SearchEngine.java # Interface for search backends (ClickHouse now, OpenSearch later)
|
||||
@@ -127,7 +127,7 @@ cameleer3-server-core/src/main/java/com/cameleer3/server/core/
|
||||
├── ExecutionRepository.java # Extended with query methods
|
||||
└── DiagramRepository.java # Extended with lookup methods
|
||||
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/
|
||||
├── controller/
|
||||
│ ├── SearchController.java # GET + POST /api/v1/search/executions
|
||||
│ ├── DetailController.java # GET /api/v1/executions/{id}
|
||||
@@ -517,25 +517,25 @@ private void populateExchangeColumns(PreparedStatement ps, List<FlatProcessor> p
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Framework | JUnit 5 + Spring Boot Test + Testcontainers ClickHouse 25.3 |
|
||||
| Config file | cameleer3-server-app/pom.xml (testcontainers dep), AbstractClickHouseIT base class |
|
||||
| Quick run command | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT -Dfailsafe.skip=true` |
|
||||
| Config file | cameleer-server-app/pom.xml (testcontainers dep), AbstractClickHouseIT base class |
|
||||
| Quick run command | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT -Dfailsafe.skip=true` |
|
||||
| Full suite command | `mvn clean verify` |
|
||||
|
||||
### Phase Requirements -> Test Map
|
||||
| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|
||||
|--------|----------|-----------|-------------------|-------------|
|
||||
| SRCH-01 | Filter by status returns matching executions | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#searchByStatus` | No -- Wave 0 |
|
||||
| SRCH-02 | Filter by time range returns matching executions | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#searchByTimeRange` | No -- Wave 0 |
|
||||
| SRCH-03 | Filter by duration range returns matching | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#searchByDuration` | No -- Wave 0 |
|
||||
| SRCH-04 | Filter by correlationId returns correlated | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#searchByCorrelationId` | No -- Wave 0 |
|
||||
| SRCH-05 | Full-text search across bodies/headers/errors | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#fullTextSearch` | No -- Wave 0 |
|
||||
| SRCH-06 | Detail returns nested processor tree | integration | `mvn test -pl cameleer3-server-app -Dtest=DetailControllerIT#detailReturnsNestedTree` | No -- Wave 0 |
|
||||
| DIAG-01 | Content-hash dedup stores identical defs once | integration | `mvn test -pl cameleer3-server-app -Dtest=DiagramControllerIT#contentHashDedup` | Partial (ingestion test exists) |
|
||||
| DIAG-02 | Transaction links to active diagram version | integration | `mvn test -pl cameleer3-server-app -Dtest=DetailControllerIT#detailIncludesDiagramHash` | No -- Wave 0 |
|
||||
| DIAG-03 | Diagram rendered as SVG or JSON layout | integration | `mvn test -pl cameleer3-server-app -Dtest=DiagramRenderControllerIT#renderSvg` | No -- Wave 0 |
|
||||
| SRCH-01 | Filter by status returns matching executions | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#searchByStatus` | No -- Wave 0 |
|
||||
| SRCH-02 | Filter by time range returns matching executions | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#searchByTimeRange` | No -- Wave 0 |
|
||||
| SRCH-03 | Filter by duration range returns matching | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#searchByDuration` | No -- Wave 0 |
|
||||
| SRCH-04 | Filter by correlationId returns correlated | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#searchByCorrelationId` | No -- Wave 0 |
|
||||
| SRCH-05 | Full-text search across bodies/headers/errors | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#fullTextSearch` | No -- Wave 0 |
|
||||
| SRCH-06 | Detail returns nested processor tree | integration | `mvn test -pl cameleer-server-app -Dtest=DetailControllerIT#detailReturnsNestedTree` | No -- Wave 0 |
|
||||
| DIAG-01 | Content-hash dedup stores identical defs once | integration | `mvn test -pl cameleer-server-app -Dtest=DiagramControllerIT#contentHashDedup` | Partial (ingestion test exists) |
|
||||
| DIAG-02 | Transaction links to active diagram version | integration | `mvn test -pl cameleer-server-app -Dtest=DetailControllerIT#detailIncludesDiagramHash` | No -- Wave 0 |
|
||||
| DIAG-03 | Diagram rendered as SVG or JSON layout | integration | `mvn test -pl cameleer-server-app -Dtest=DiagramRenderControllerIT#renderSvg` | No -- Wave 0 |
|
||||
|
||||
### Sampling Rate
|
||||
- **Per task commit:** `mvn test -pl cameleer3-server-app -Dtest=<relevant>IT`
|
||||
- **Per task commit:** `mvn test -pl cameleer-server-app -Dtest=<relevant>IT`
|
||||
- **Per wave merge:** `mvn clean verify`
|
||||
- **Phase gate:** Full suite green before `/gsd:verify-work`
|
||||
|
||||
@@ -551,7 +551,7 @@ private void populateExchangeColumns(PreparedStatement ps, List<FlatProcessor> p
|
||||
|
||||
### Primary (HIGH confidence)
|
||||
- ClickHouse JDBC 0.9.7, ClickHouse 25.3 -- verified from project pom.xml and AbstractClickHouseIT
|
||||
- cameleer3-common 1.0-SNAPSHOT JAR -- decompiled to verify RouteGraph, RouteNode, RouteEdge, NodeType, ProcessorExecution, ExchangeSnapshot field structures
|
||||
- cameleer-common 1.0-SNAPSHOT JAR -- decompiled to verify RouteGraph, RouteNode, RouteEdge, NodeType, ProcessorExecution, ExchangeSnapshot field structures
|
||||
- Existing Phase 1 codebase -- ClickHouseExecutionRepository, ClickHouseDiagramRepository, schema, test patterns
|
||||
|
||||
### Secondary (MEDIUM confidence)
|
||||
|
||||
@@ -18,8 +18,8 @@ created: 2026-03-11
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Framework** | JUnit 5 + Spring Boot Test + Testcontainers ClickHouse 25.3 |
|
||||
| **Config file** | cameleer3-server-app/pom.xml (testcontainers dep), AbstractClickHouseIT base class |
|
||||
| **Quick run command** | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT` |
|
||||
| **Config file** | cameleer-server-app/pom.xml (testcontainers dep), AbstractClickHouseIT base class |
|
||||
| **Quick run command** | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT` |
|
||||
| **Full suite command** | `mvn clean verify` |
|
||||
| **Estimated runtime** | ~45 seconds |
|
||||
|
||||
@@ -27,7 +27,7 @@ created: 2026-03-11
|
||||
|
||||
## Sampling Rate
|
||||
|
||||
- **After every task commit:** Run `mvn test -pl cameleer3-server-app -Dtest=<relevant>IT`
|
||||
- **After every task commit:** Run `mvn test -pl cameleer-server-app -Dtest=<relevant>IT`
|
||||
- **After every plan wave:** Run `mvn clean verify`
|
||||
- **Before `/gsd:verify-work`:** Full suite must be green
|
||||
- **Max feedback latency:** 45 seconds
|
||||
@@ -38,15 +38,15 @@ created: 2026-03-11
|
||||
|
||||
| Task ID | Plan | Wave | Requirement | Test Type | Automated Command | File Exists | Status |
|
||||
|---------|------|------|-------------|-----------|-------------------|-------------|--------|
|
||||
| 02-01-01 | 01 | 1 | SRCH-01 | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#searchByStatus` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-02 | 01 | 1 | SRCH-02 | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#searchByTimeRange` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-03 | 01 | 1 | SRCH-03 | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#searchByDuration` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-04 | 01 | 1 | SRCH-04 | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#searchByCorrelationId` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-05 | 01 | 1 | SRCH-05 | integration | `mvn test -pl cameleer3-server-app -Dtest=SearchControllerIT#fullTextSearch` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-06 | 01 | 1 | SRCH-06 | integration | `mvn test -pl cameleer3-server-app -Dtest=DetailControllerIT#detailReturnsNestedTree` | ❌ W0 | ⬜ pending |
|
||||
| 02-02-01 | 02 | 1 | DIAG-01 | integration | `mvn test -pl cameleer3-server-app -Dtest=DiagramControllerIT#contentHashDedup` | Partial | ⬜ pending |
|
||||
| 02-02-02 | 02 | 1 | DIAG-02 | integration | `mvn test -pl cameleer3-server-app -Dtest=DetailControllerIT#detailIncludesDiagramHash` | ❌ W0 | ⬜ pending |
|
||||
| 02-02-03 | 02 | 1 | DIAG-03 | integration | `mvn test -pl cameleer3-server-app -Dtest=DiagramRenderControllerIT#renderSvg` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-01 | 01 | 1 | SRCH-01 | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#searchByStatus` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-02 | 01 | 1 | SRCH-02 | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#searchByTimeRange` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-03 | 01 | 1 | SRCH-03 | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#searchByDuration` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-04 | 01 | 1 | SRCH-04 | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#searchByCorrelationId` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-05 | 01 | 1 | SRCH-05 | integration | `mvn test -pl cameleer-server-app -Dtest=SearchControllerIT#fullTextSearch` | ❌ W0 | ⬜ pending |
|
||||
| 02-01-06 | 01 | 1 | SRCH-06 | integration | `mvn test -pl cameleer-server-app -Dtest=DetailControllerIT#detailReturnsNestedTree` | ❌ W0 | ⬜ pending |
|
||||
| 02-02-01 | 02 | 1 | DIAG-01 | integration | `mvn test -pl cameleer-server-app -Dtest=DiagramControllerIT#contentHashDedup` | Partial | ⬜ pending |
|
||||
| 02-02-02 | 02 | 1 | DIAG-02 | integration | `mvn test -pl cameleer-server-app -Dtest=DetailControllerIT#detailIncludesDiagramHash` | ❌ W0 | ⬜ pending |
|
||||
| 02-02-03 | 02 | 1 | DIAG-03 | integration | `mvn test -pl cameleer-server-app -Dtest=DiagramRenderControllerIT#renderSvg` | ❌ W0 | ⬜ pending |
|
||||
|
||||
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
|
||||
|
||||
|
||||
@@ -50,9 +50,9 @@ human_verification:
|
||||
|
||||
| Artifact | Status | Notes |
|
||||
|----------|--------|-------|
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseExecutionRepository.java` | VERIFIED | DiagramRepository injected via constructor (line 59); `findContentHashForRoute` called in `setValues()` (lines 144–147); former `""` placeholder removed |
|
||||
| `cameleer3-server-app/pom.xml` | VERIFIED | `maven-surefire-plugin` with `forkCount=1` `reuseForks=false` at lines 95–100; `maven-failsafe-plugin` same config at lines 103–108 |
|
||||
| `cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java` | VERIFIED | 152 lines; 2 integration tests; positive case asserts 64-char hex hash; negative case asserts empty string; uses `ignoreExceptions()` for ClickHouse eventual consistency |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/storage/ClickHouseExecutionRepository.java` | VERIFIED | DiagramRepository injected via constructor (line 59); `findContentHashForRoute` called in `setValues()` (lines 144–147); former `""` placeholder removed |
|
||||
| `cameleer-server-app/pom.xml` | VERIFIED | `maven-surefire-plugin` with `forkCount=1` `reuseForks=false` at lines 95–100; `maven-failsafe-plugin` same config at lines 103–108 |
|
||||
| `cameleer-server-app/src/test/java/com/cameleer/server/app/storage/DiagramLinkingIT.java` | VERIFIED | 152 lines; 2 integration tests; positive case asserts 64-char hex hash; negative case asserts empty string; uses `ignoreExceptions()` for ClickHouse eventual consistency |
|
||||
|
||||
### Key Link Verification
|
||||
|
||||
@@ -62,7 +62,7 @@ human_verification:
|
||||
| `SearchController` | `SearchService` | constructor injection, `searchService.search()` | WIRED | Previously verified; no regression |
|
||||
| `DetailController` | `DetailService` | constructor injection, `detailService.getDetail()` | WIRED | Previously verified; no regression |
|
||||
| `DiagramRenderController` | `DiagramRepository` + `DiagramRenderer` | `findByContentHash()` + `renderSvg()`/`layoutJson()` | WIRED | Previously verified; no regression |
|
||||
| `Surefire/Failsafe` | ELK classloader isolation | `reuseForks=false` forces fresh JVM per test class | WIRED | Lines 95–116 in `cameleer3-server-app/pom.xml` |
|
||||
| `Surefire/Failsafe` | ELK classloader isolation | `reuseForks=false` forces fresh JVM per test class | WIRED | Lines 95–116 in `cameleer-server-app/pom.xml` |
|
||||
|
||||
### Requirements Coverage
|
||||
|
||||
@@ -108,7 +108,7 @@ Two blockers from the initial verification (2026-03-11T16:00:00Z) have been reso
|
||||
|
||||
**Gap 1 resolved — DIAG-02 diagram hash linking:** `ClickHouseExecutionRepository` now injects `DiagramRepository` via constructor and calls `findContentHashForRoute(exec.getRouteId(), "")` in `insertBatch()`. Both the diagram store path and the execution ingest path use `agent_id=""` consistently, so the lookup is correct. `DiagramLinkingIT` provides integration test coverage for both the positive case (hash populated when diagram exists) and negative case (empty string when no diagram exists for the route).
|
||||
|
||||
**Gap 2 resolved — Test suite stability:** Both `maven-surefire-plugin` and `maven-failsafe-plugin` in `cameleer3-server-app/pom.xml` are now configured with `forkCount=1` `reuseForks=false`. This forces a fresh JVM per test class, isolating ELK's `LayeredMetaDataProvider` static initializer from Spring Boot's classloader. The SUMMARY reports 51 tests, 0 failures. Test count across 16 test files totals 80 `@Test` methods; the difference from 51 reflects how Surefire/Failsafe counts parameterized and nested tests vs. raw annotation count.
|
||||
**Gap 2 resolved — Test suite stability:** Both `maven-surefire-plugin` and `maven-failsafe-plugin` in `cameleer-server-app/pom.xml` are now configured with `forkCount=1` `reuseForks=false`. This forces a fresh JVM per test class, isolating ELK's `LayeredMetaDataProvider` static initializer from Spring Boot's classloader. The SUMMARY reports 51 tests, 0 failures. Test count across 16 test files totals 80 `@Test` methods; the difference from 51 reflects how Surefire/Failsafe counts parameterized and nested tests vs. raw annotation count.
|
||||
|
||||
No regressions were introduced. All 10 observable truths and all 9 phase requirements are now satisfied. Two items remain for human visual verification (SVG rendering correctness).
|
||||
|
||||
|
||||
@@ -5,21 +5,21 @@ type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentInfo.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentState.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentCommand.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/CommandStatus.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/CommandType.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentRegistryService.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventListener.java
|
||||
- cameleer3-server-core/src/test/java/com/cameleer3/server/core/agent/AgentRegistryServiceTest.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/AgentRegistryConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/AgentRegistryBeanConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/AgentLifecycleMonitor.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/Cameleer3ServerApplication.java
|
||||
- cameleer3-server-app/src/main/resources/application.yml
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentRegistrationControllerIT.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentInfo.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentState.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentCommand.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/CommandStatus.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/CommandType.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentRegistryService.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentEventListener.java
|
||||
- cameleer-server-core/src/test/java/com/cameleer/server/core/agent/AgentRegistryServiceTest.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryBeanConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/agent/AgentLifecycleMonitor.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/CameleerServerApplication.java
|
||||
- cameleer-server-app/src/main/resources/application.yml
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentRegistrationControllerIT.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- AGNT-01
|
||||
@@ -34,13 +34,13 @@ must_haves:
|
||||
- "Server transitions agents LIVE->STALE after 90s without heartbeat, STALE->DEAD 5 minutes after staleTransitionTime"
|
||||
- "Agent list endpoint GET /api/v1/agents returns all agents, filterable by ?status=LIVE|STALE|DEAD"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentRegistryService.java"
|
||||
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentRegistryService.java"
|
||||
provides: "Agent registration, heartbeat, lifecycle transitions, find/filter"
|
||||
- path: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentInfo.java"
|
||||
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentInfo.java"
|
||||
provides: "Agent record with id, name, group, version, routeIds, capabilities, state, timestamps"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java"
|
||||
provides: "POST /register, POST /{id}/heartbeat, GET /agents endpoints"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/AgentLifecycleMonitor.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/agent/AgentLifecycleMonitor.java"
|
||||
provides: "@Scheduled lifecycle transitions LIVE->STALE->DEAD"
|
||||
key_links:
|
||||
- from: "AgentRegistrationController"
|
||||
@@ -76,14 +76,14 @@ Output: Core domain types (AgentInfo, AgentState, AgentCommand, CommandStatus, C
|
||||
@.planning/phases/03-agent-registry-sse-push/03-CONTEXT.md
|
||||
@.planning/phases/03-agent-registry-sse-push/03-RESEARCH.md
|
||||
|
||||
@cameleer3-server-core/src/main/java/com/cameleer3/server/core/ingestion/IngestionService.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/IngestionBeanConfig.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/IngestionConfig.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/ingestion/ClickHouseFlushScheduler.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/Cameleer3ServerApplication.java
|
||||
@cameleer3-server-app/src/main/resources/application.yml
|
||||
@cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java
|
||||
@cameleer-server-core/src/main/java/com/cameleer/server/core/ingestion/IngestionService.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/config/IngestionBeanConfig.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/config/IngestionConfig.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/ingestion/ClickHouseFlushScheduler.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/CameleerServerApplication.java
|
||||
@cameleer-server-app/src/main/resources/application.yml
|
||||
@cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java
|
||||
|
||||
<interfaces>
|
||||
<!-- Established codebase patterns the executor must follow -->
|
||||
@@ -99,10 +99,10 @@ Pattern: Controller accepts raw String body:
|
||||
|
||||
Pattern: @Scheduled for periodic tasks:
|
||||
- ClickHouseFlushScheduler uses @Scheduled(fixedDelayString = "${ingestion.flush-interval-ms:1000}")
|
||||
- @EnableScheduling already on Cameleer3ServerApplication
|
||||
- @EnableScheduling already on CameleerServerApplication
|
||||
|
||||
Pattern: @EnableConfigurationProperties registration:
|
||||
- Cameleer3ServerApplication has @EnableConfigurationProperties(IngestionConfig.class)
|
||||
- CameleerServerApplication has @EnableConfigurationProperties(IngestionConfig.class)
|
||||
- New config classes must be added to this annotation
|
||||
|
||||
Pattern: ProtocolVersionInterceptor:
|
||||
@@ -116,14 +116,14 @@ Pattern: ProtocolVersionInterceptor:
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: Core domain types and AgentRegistryService with unit tests</name>
|
||||
<files>
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentInfo.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentState.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentCommand.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/CommandStatus.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/CommandType.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentRegistryService.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventListener.java,
|
||||
cameleer3-server-core/src/test/java/com/cameleer3/server/core/agent/AgentRegistryServiceTest.java
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentInfo.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentState.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentCommand.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/agent/CommandStatus.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/agent/CommandType.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentRegistryService.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentEventListener.java,
|
||||
cameleer-server-core/src/test/java/com/cameleer/server/core/agent/AgentRegistryServiceTest.java
|
||||
</files>
|
||||
<behavior>
|
||||
- register: new agent ID creates AgentInfo with state LIVE, returns AgentInfo
|
||||
@@ -142,7 +142,7 @@ Pattern: ProtocolVersionInterceptor:
|
||||
- findPendingCommands: returns PENDING commands for given agentId
|
||||
</behavior>
|
||||
<action>
|
||||
Create the agent domain model in the core module (package com.cameleer3.server.core.agent):
|
||||
Create the agent domain model in the core module (package com.cameleer.server.core.agent):
|
||||
|
||||
1. **AgentState enum**: LIVE, STALE, DEAD
|
||||
|
||||
@@ -182,7 +182,7 @@ Pattern: ProtocolVersionInterceptor:
|
||||
Write tests FIRST (RED), then implement (GREEN). Test class: AgentRegistryServiceTest.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>mvn test -pl cameleer3-server-core -Dtest=AgentRegistryServiceTest</automated>
|
||||
<automated>mvn test -pl cameleer-server-core -Dtest=AgentRegistryServiceTest</automated>
|
||||
</verify>
|
||||
<done>All unit tests pass: registration (new + re-register), heartbeat (known + unknown), lifecycle transitions (LIVE->STALE->DEAD, heartbeat revives STALE), findAll/findByState/findById, command add/acknowledge/expire. AgentEventListener interface defined.</done>
|
||||
</task>
|
||||
@@ -190,13 +190,13 @@ Pattern: ProtocolVersionInterceptor:
|
||||
<task type="auto">
|
||||
<name>Task 2: Registration/heartbeat/list controllers, config, lifecycle monitor, integration tests</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/AgentRegistryConfig.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/AgentRegistryBeanConfig.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/AgentLifecycleMonitor.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/Cameleer3ServerApplication.java,
|
||||
cameleer3-server-app/src/main/resources/application.yml,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentRegistrationControllerIT.java
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryConfig.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryBeanConfig.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/agent/AgentLifecycleMonitor.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/CameleerServerApplication.java,
|
||||
cameleer-server-app/src/main/resources/application.yml,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentRegistrationControllerIT.java
|
||||
</files>
|
||||
<action>
|
||||
Wire the agent registry into the Spring Boot app and create REST endpoints:
|
||||
@@ -214,7 +214,7 @@ Pattern: ProtocolVersionInterceptor:
|
||||
- @Bean AgentRegistryService: `new AgentRegistryService(config.getStaleThresholdMs(), config.getDeadThresholdMs(), config.getCommandExpiryMs())`
|
||||
Follow IngestionBeanConfig pattern.
|
||||
|
||||
3. **Update Cameleer3ServerApplication**: Add AgentRegistryConfig.class to @EnableConfigurationProperties.
|
||||
3. **Update CameleerServerApplication**: Add AgentRegistryConfig.class to @EnableConfigurationProperties.
|
||||
|
||||
4. **Update application.yml**: Add agent-registry section with all defaults (see RESEARCH.md code example). Also add `spring.mvc.async.request-timeout: -1` for SSE support (Plan 02 needs it, but set it now).
|
||||
|
||||
@@ -242,7 +242,7 @@ Pattern: ProtocolVersionInterceptor:
|
||||
- Use TestRestTemplate (already available from AbstractClickHouseIT's @SpringBootTest)
|
||||
</action>
|
||||
<verify>
|
||||
<automated>mvn test -pl cameleer3-server-core,cameleer3-server-app -Dtest="Agent*"</automated>
|
||||
<automated>mvn test -pl cameleer-server-core,cameleer-server-app -Dtest="Agent*"</automated>
|
||||
</verify>
|
||||
<done>POST /register returns 200 with agentId + sseEndpoint + heartbeatIntervalMs. POST /{id}/heartbeat returns 200 for known agents, 404 for unknown. GET /agents returns all agents with optional ?status= filter. AgentLifecycleMonitor runs on schedule. All integration tests pass. mvn clean verify passes.</done>
|
||||
</task>
|
||||
|
||||
@@ -27,22 +27,22 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentInfo.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentState.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentCommand.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/CommandStatus.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/CommandType.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentRegistryService.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventListener.java
|
||||
- cameleer3-server-core/src/test/java/com/cameleer3/server/core/agent/AgentRegistryServiceTest.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/AgentRegistryConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/AgentRegistryBeanConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/AgentLifecycleMonitor.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentRegistrationControllerIT.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentInfo.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentState.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentCommand.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/CommandStatus.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/CommandType.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentRegistryService.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentEventListener.java
|
||||
- cameleer-server-core/src/test/java/com/cameleer/server/core/agent/AgentRegistryServiceTest.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryBeanConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/agent/AgentLifecycleMonitor.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentRegistrationControllerIT.java
|
||||
modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/Cameleer3ServerApplication.java
|
||||
- cameleer3-server-app/src/main/resources/application.yml
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/CameleerServerApplication.java
|
||||
- cameleer-server-app/src/main/resources/application.yml
|
||||
|
||||
key-decisions:
|
||||
- "AgentInfo as Java record with wither-style methods for immutable ConcurrentHashMap swapping"
|
||||
@@ -103,7 +103,7 @@ _Note: Task 1 used TDD with separate RED/GREEN commits_
|
||||
- `AgentRegistrationController.java` - REST endpoints for agents
|
||||
- `AgentRegistryServiceTest.java` - 23 unit tests
|
||||
- `AgentRegistrationControllerIT.java` - 7 integration tests
|
||||
- `Cameleer3ServerApplication.java` - Added AgentRegistryConfig to @EnableConfigurationProperties
|
||||
- `CameleerServerApplication.java` - Added AgentRegistryConfig to @EnableConfigurationProperties
|
||||
- `application.yml` - Added agent-registry config section and spring.mvc.async.request-timeout
|
||||
|
||||
## Decisions Made
|
||||
|
||||
@@ -5,12 +5,12 @@ type: execute
|
||||
wave: 2
|
||||
depends_on: ["03-01"]
|
||||
files_modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentSseController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentCommandController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentSseControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentCommandControllerIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentSseController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentCommandController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentSseControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentCommandControllerIT.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- AGNT-04
|
||||
@@ -30,11 +30,11 @@ must_haves:
|
||||
- "SSE events include event ID for Last-Event-ID reconnection support (no replay of missed events)"
|
||||
- "Agent can acknowledge command receipt via POST /api/v1/agents/{id}/commands/{commandId}/ack"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java"
|
||||
provides: "Per-agent SseEmitter management, event sending, ping keepalive"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentSseController.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentSseController.java"
|
||||
provides: "GET /{id}/events SSE endpoint"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentCommandController.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentCommandController.java"
|
||||
provides: "POST command endpoints (single, group, broadcast) + ack endpoint"
|
||||
key_links:
|
||||
- from: "AgentCommandController"
|
||||
@@ -75,49 +75,49 @@ Output: SseConnectionManager, SSE endpoint, command controller (single/group/bro
|
||||
@.planning/phases/03-agent-registry-sse-push/03-RESEARCH.md
|
||||
@.planning/phases/03-agent-registry-sse-push/03-01-SUMMARY.md
|
||||
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
@cameleer3-server-app/src/main/resources/application.yml
|
||||
@cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
@cameleer-server-app/src/main/resources/application.yml
|
||||
@cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java
|
||||
|
||||
<interfaces>
|
||||
<!-- From Plan 01 (must exist before this plan executes) -->
|
||||
|
||||
From cameleer3-server-core/.../agent/AgentInfo.java:
|
||||
From cameleer-server-core/.../agent/AgentInfo.java:
|
||||
```java
|
||||
// Record or class with fields:
|
||||
// id, name, group, version, routeIds, capabilities, state, registeredAt, lastHeartbeat, staleTransitionTime
|
||||
// Methods: withState(), withLastHeartbeat(), etc.
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../agent/AgentState.java:
|
||||
From cameleer-server-core/.../agent/AgentState.java:
|
||||
```java
|
||||
public enum AgentState { LIVE, STALE, DEAD }
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../agent/CommandType.java:
|
||||
From cameleer-server-core/.../agent/CommandType.java:
|
||||
```java
|
||||
public enum CommandType { CONFIG_UPDATE, DEEP_TRACE, REPLAY }
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../agent/CommandStatus.java:
|
||||
From cameleer-server-core/.../agent/CommandStatus.java:
|
||||
```java
|
||||
public enum CommandStatus { PENDING, DELIVERED, ACKNOWLEDGED, EXPIRED }
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../agent/AgentCommand.java:
|
||||
From cameleer-server-core/.../agent/AgentCommand.java:
|
||||
```java
|
||||
// Record: id (UUID string), type (CommandType), payload (String JSON), targetAgentId, createdAt, status
|
||||
// Method: withStatus()
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../agent/AgentEventListener.java:
|
||||
From cameleer-server-core/.../agent/AgentEventListener.java:
|
||||
```java
|
||||
public interface AgentEventListener {
|
||||
void onCommandReady(String agentId, AgentCommand command);
|
||||
}
|
||||
```
|
||||
|
||||
From cameleer3-server-core/.../agent/AgentRegistryService.java:
|
||||
From cameleer-server-core/.../agent/AgentRegistryService.java:
|
||||
```java
|
||||
// Key methods:
|
||||
// register(id, name, group, version, routeIds, capabilities) -> AgentInfo
|
||||
@@ -131,7 +131,7 @@ From cameleer3-server-core/.../agent/AgentRegistryService.java:
|
||||
// setEventListener(listener) -> void
|
||||
```
|
||||
|
||||
From cameleer3-server-app/.../config/AgentRegistryConfig.java:
|
||||
From cameleer-server-app/.../config/AgentRegistryConfig.java:
|
||||
```java
|
||||
// @ConfigurationProperties(prefix = "agent-registry")
|
||||
// getPingIntervalMs(), getCommandExpiryMs(), etc.
|
||||
@@ -144,11 +144,11 @@ From cameleer3-server-app/.../config/AgentRegistryConfig.java:
|
||||
<task type="auto">
|
||||
<name>Task 1: SseConnectionManager, SSE controller, and command controller</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentSseController.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentCommandController.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/AgentRegistryBeanConfig.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentSseController.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentCommandController.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryBeanConfig.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
</files>
|
||||
<action>
|
||||
Build the SSE infrastructure and command delivery system:
|
||||
@@ -181,7 +181,7 @@ From cameleer3-server-app/.../config/AgentRegistryConfig.java:
|
||||
5. **Update WebConfig**: The SSE endpoint GET /api/v1/agents/{id}/events is already covered by the interceptor pattern "/api/v1/agents/**". Agents send the protocol version header on all requests (per research recommendation), so no exclusion needed. However, if the SSE GET causes issues because browsers/clients may not easily add custom headers to EventSource, add the SSE events path to excludePathPatterns: `/api/v1/agents/*/events`. This is a practical consideration -- add the exclusion to be safe.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>mvn compile -pl cameleer3-server-core,cameleer3-server-app</automated>
|
||||
<automated>mvn compile -pl cameleer-server-core,cameleer-server-app</automated>
|
||||
</verify>
|
||||
<done>SseConnectionManager, AgentSseController, and AgentCommandController compile. SSE endpoint returns SseEmitter. Command endpoints accept type/payload and deliver via SSE. Ping keepalive scheduled. WebConfig updated if needed.</done>
|
||||
</task>
|
||||
@@ -189,8 +189,8 @@ From cameleer3-server-app/.../config/AgentRegistryConfig.java:
|
||||
<task type="auto">
|
||||
<name>Task 2: Integration tests for SSE, commands, and full flow</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentSseControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentCommandControllerIT.java
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentSseControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentCommandControllerIT.java
|
||||
</files>
|
||||
<action>
|
||||
Write integration tests covering SSE connection, command delivery, ping, and acknowledgement:
|
||||
@@ -224,7 +224,7 @@ From cameleer3-server-app/.../config/AgentRegistryConfig.java:
|
||||
**Test configuration**: If ping interval needs to be shorter for tests, add to test application.yml or use @TestPropertySource with agent-registry.ping-interval-ms=1000.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>mvn test -pl cameleer3-server-core,cameleer3-server-app -Dtest="Agent*"</automated>
|
||||
<automated>mvn test -pl cameleer-server-core,cameleer-server-app -Dtest="Agent*"</automated>
|
||||
</verify>
|
||||
<done>All SSE integration tests pass: connect/disconnect, config-update/deep-trace/replay delivery via SSE, ping keepalive received, Last-Event-ID accepted, command targeting (single/group/broadcast), command acknowledgement. mvn clean verify passes with all existing tests still green.</done>
|
||||
</task>
|
||||
|
||||
@@ -24,14 +24,14 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentSseController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentCommandController.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentSseControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentCommandControllerIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentSseController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentCommandController.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentSseControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentCommandControllerIT.java
|
||||
modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
- cameleer3-server-app/src/test/resources/application-test.yml
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
- cameleer-server-app/src/test/resources/application-test.yml
|
||||
|
||||
key-decisions:
|
||||
- "SSE events path excluded from ProtocolVersionInterceptor for EventSource client compatibility"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## Summary
|
||||
|
||||
This phase adds agent registration, heartbeat-based lifecycle management (LIVE/STALE/DEAD), and real-time command push via SSE to the Cameleer3 server. The technology stack is straightforward: Spring MVC's `SseEmitter` for server-push, `ConcurrentHashMap` for the in-memory agent registry, and `@Scheduled` for periodic lifecycle checks (same pattern already used by `ClickHouseFlushScheduler`).
|
||||
This phase adds agent registration, heartbeat-based lifecycle management (LIVE/STALE/DEAD), and real-time command push via SSE to the Cameleer server. The technology stack is straightforward: Spring MVC's `SseEmitter` for server-push, `ConcurrentHashMap` for the in-memory agent registry, and `@Scheduled` for periodic lifecycle checks (same pattern already used by `ClickHouseFlushScheduler`).
|
||||
|
||||
The main architectural challenge is managing per-agent SSE connections reliably -- handling disconnections, timeouts, and cleanup without leaking threads or emitters. The command delivery model (PENDING with 60s expiry, acknowledgement) adds a second concurrent data structure to manage alongside the registry itself.
|
||||
|
||||
@@ -93,7 +93,7 @@ No new dependencies required. Everything is already on the classpath.
|
||||
|
||||
### Recommended Project Structure
|
||||
```
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/
|
||||
├── agent/
|
||||
│ ├── AgentInfo.java # Record: id, name, group, version, routeIds, capabilities, state, timestamps
|
||||
│ ├── AgentState.java # Enum: LIVE, STALE, DEAD
|
||||
@@ -101,7 +101,7 @@ cameleer3-server-core/src/main/java/com/cameleer3/server/core/
|
||||
│ ├── AgentCommand.java # Record: id, type, payload, targetAgentId, createdAt, status
|
||||
│ └── CommandStatus.java # Enum: PENDING, DELIVERED, ACKNOWLEDGED, EXPIRED
|
||||
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/
|
||||
├── config/
|
||||
│ ├── AgentRegistryConfig.java # @ConfigurationProperties(prefix = "agent-registry")
|
||||
│ └── AgentRegistryBeanConfig.java # @Configuration: wires AgentRegistryService as bean
|
||||
@@ -452,30 +452,30 @@ spring:
|
||||
|----------|-------|
|
||||
| Framework | JUnit 5 + Spring Boot Test (via spring-boot-starter-test) |
|
||||
| Config file | pom.xml (Surefire + Failsafe configured) |
|
||||
| Quick run command | `mvn test -pl cameleer3-server-core -Dtest=AgentRegistryServiceTest` |
|
||||
| Quick run command | `mvn test -pl cameleer-server-core -Dtest=AgentRegistryServiceTest` |
|
||||
| Full suite command | `mvn clean verify` |
|
||||
|
||||
### Phase Requirements to Test Map
|
||||
| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|
||||
|--------|----------|-----------|-------------------|-------------|
|
||||
| AGNT-01 | Agent registers and gets response | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentRegistrationControllerIT#registerAgent*` | No - Wave 0 |
|
||||
| AGNT-02 | Lifecycle transitions LIVE/STALE/DEAD | unit | `mvn test -pl cameleer3-server-core -Dtest=AgentRegistryServiceTest#lifecycle*` | No - Wave 0 |
|
||||
| AGNT-03 | Heartbeat updates timestamp, returns 200/404 | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentRegistrationControllerIT#heartbeat*` | No - Wave 0 |
|
||||
| AGNT-04 | Config-update pushed via SSE | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentSseControllerIT#configUpdate*` | No - Wave 0 |
|
||||
| AGNT-05 | Deep-trace command pushed via SSE | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentSseControllerIT#deepTrace*` | No - Wave 0 |
|
||||
| AGNT-06 | Replay command pushed via SSE | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentSseControllerIT#replay*` | No - Wave 0 |
|
||||
| AGNT-07 | SSE ping keepalive + Last-Event-ID | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentSseControllerIT#pingKeepalive*` | No - Wave 0 |
|
||||
| AGNT-01 | Agent registers and gets response | integration | `mvn test -pl cameleer-server-app -Dtest=AgentRegistrationControllerIT#registerAgent*` | No - Wave 0 |
|
||||
| AGNT-02 | Lifecycle transitions LIVE/STALE/DEAD | unit | `mvn test -pl cameleer-server-core -Dtest=AgentRegistryServiceTest#lifecycle*` | No - Wave 0 |
|
||||
| AGNT-03 | Heartbeat updates timestamp, returns 200/404 | integration | `mvn test -pl cameleer-server-app -Dtest=AgentRegistrationControllerIT#heartbeat*` | No - Wave 0 |
|
||||
| AGNT-04 | Config-update pushed via SSE | integration | `mvn test -pl cameleer-server-app -Dtest=AgentSseControllerIT#configUpdate*` | No - Wave 0 |
|
||||
| AGNT-05 | Deep-trace command pushed via SSE | integration | `mvn test -pl cameleer-server-app -Dtest=AgentSseControllerIT#deepTrace*` | No - Wave 0 |
|
||||
| AGNT-06 | Replay command pushed via SSE | integration | `mvn test -pl cameleer-server-app -Dtest=AgentSseControllerIT#replay*` | No - Wave 0 |
|
||||
| AGNT-07 | SSE ping keepalive + Last-Event-ID | integration | `mvn test -pl cameleer-server-app -Dtest=AgentSseControllerIT#pingKeepalive*` | No - Wave 0 |
|
||||
|
||||
### Sampling Rate
|
||||
- **Per task commit:** `mvn test -pl cameleer3-server-core,cameleer3-server-app -Dtest="Agent*"` (agent-related tests only)
|
||||
- **Per task commit:** `mvn test -pl cameleer-server-core,cameleer-server-app -Dtest="Agent*"` (agent-related tests only)
|
||||
- **Per wave merge:** `mvn clean verify`
|
||||
- **Phase gate:** Full suite green before /gsd:verify-work
|
||||
|
||||
### Wave 0 Gaps
|
||||
- [ ] `cameleer3-server-core/.../agent/AgentRegistryServiceTest.java` -- covers AGNT-02, AGNT-03 (unit tests for registry logic)
|
||||
- [ ] `cameleer3-server-app/.../controller/AgentRegistrationControllerIT.java` -- covers AGNT-01, AGNT-03
|
||||
- [ ] `cameleer3-server-app/.../controller/AgentSseControllerIT.java` -- covers AGNT-04, AGNT-05, AGNT-06, AGNT-07
|
||||
- [ ] `cameleer3-server-app/.../controller/AgentCommandControllerIT.java` -- covers command targeting (single, group, all)
|
||||
- [ ] `cameleer-server-core/.../agent/AgentRegistryServiceTest.java` -- covers AGNT-02, AGNT-03 (unit tests for registry logic)
|
||||
- [ ] `cameleer-server-app/.../controller/AgentRegistrationControllerIT.java` -- covers AGNT-01, AGNT-03
|
||||
- [ ] `cameleer-server-app/.../controller/AgentSseControllerIT.java` -- covers AGNT-04, AGNT-05, AGNT-06, AGNT-07
|
||||
- [ ] `cameleer-server-app/.../controller/AgentCommandControllerIT.java` -- covers command targeting (single, group, all)
|
||||
- [ ] No new framework install needed -- JUnit 5 + Spring Boot Test + Awaitility already in place
|
||||
|
||||
### SSE Test Strategy
|
||||
|
||||
@@ -18,8 +18,8 @@ created: 2026-03-11
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Framework** | JUnit 5 + Spring Boot Test + Testcontainers ClickHouse 25.3 |
|
||||
| **Config file** | cameleer3-server-app/pom.xml (Surefire + Failsafe configured) |
|
||||
| **Quick run command** | `mvn test -pl cameleer3-server-core -Dtest=AgentRegistryServiceTest` |
|
||||
| **Config file** | cameleer-server-app/pom.xml (Surefire + Failsafe configured) |
|
||||
| **Quick run command** | `mvn test -pl cameleer-server-core -Dtest=AgentRegistryServiceTest` |
|
||||
| **Full suite command** | `mvn clean verify` |
|
||||
| **Estimated runtime** | ~50 seconds |
|
||||
|
||||
@@ -27,7 +27,7 @@ created: 2026-03-11
|
||||
|
||||
## Sampling Rate
|
||||
|
||||
- **After every task commit:** Run `mvn test -pl cameleer3-server-core,cameleer3-server-app -Dtest="Agent*"`
|
||||
- **After every task commit:** Run `mvn test -pl cameleer-server-core,cameleer-server-app -Dtest="Agent*"`
|
||||
- **After every plan wave:** Run `mvn clean verify`
|
||||
- **Before `/gsd:verify-work`:** Full suite must be green
|
||||
- **Max feedback latency:** 50 seconds
|
||||
@@ -38,13 +38,13 @@ created: 2026-03-11
|
||||
|
||||
| Task ID | Plan | Wave | Requirement | Test Type | Automated Command | File Exists | Status |
|
||||
|---------|------|------|-------------|-----------|-------------------|-------------|--------|
|
||||
| 03-01-01 | 01 | 1 | AGNT-01 | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentRegistrationControllerIT#registerAgent*` | ❌ W0 | ⬜ pending |
|
||||
| 03-01-02 | 01 | 1 | AGNT-02 | unit | `mvn test -pl cameleer3-server-core -Dtest=AgentRegistryServiceTest#lifecycle*` | ❌ W0 | ⬜ pending |
|
||||
| 03-01-03 | 01 | 1 | AGNT-03 | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentRegistrationControllerIT#heartbeat*` | ❌ W0 | ⬜ pending |
|
||||
| 03-02-01 | 02 | 1 | AGNT-04 | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentSseControllerIT#configUpdate*` | ❌ W0 | ⬜ pending |
|
||||
| 03-02-02 | 02 | 1 | AGNT-05 | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentSseControllerIT#deepTrace*` | ❌ W0 | ⬜ pending |
|
||||
| 03-02-03 | 02 | 1 | AGNT-06 | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentSseControllerIT#replay*` | ❌ W0 | ⬜ pending |
|
||||
| 03-02-04 | 02 | 1 | AGNT-07 | integration | `mvn test -pl cameleer3-server-app -Dtest=AgentSseControllerIT#pingKeepalive*` | ❌ W0 | ⬜ pending |
|
||||
| 03-01-01 | 01 | 1 | AGNT-01 | integration | `mvn test -pl cameleer-server-app -Dtest=AgentRegistrationControllerIT#registerAgent*` | ❌ W0 | ⬜ pending |
|
||||
| 03-01-02 | 01 | 1 | AGNT-02 | unit | `mvn test -pl cameleer-server-core -Dtest=AgentRegistryServiceTest#lifecycle*` | ❌ W0 | ⬜ pending |
|
||||
| 03-01-03 | 01 | 1 | AGNT-03 | integration | `mvn test -pl cameleer-server-app -Dtest=AgentRegistrationControllerIT#heartbeat*` | ❌ W0 | ⬜ pending |
|
||||
| 03-02-01 | 02 | 1 | AGNT-04 | integration | `mvn test -pl cameleer-server-app -Dtest=AgentSseControllerIT#configUpdate*` | ❌ W0 | ⬜ pending |
|
||||
| 03-02-02 | 02 | 1 | AGNT-05 | integration | `mvn test -pl cameleer-server-app -Dtest=AgentSseControllerIT#deepTrace*` | ❌ W0 | ⬜ pending |
|
||||
| 03-02-03 | 02 | 1 | AGNT-06 | integration | `mvn test -pl cameleer-server-app -Dtest=AgentSseControllerIT#replay*` | ❌ W0 | ⬜ pending |
|
||||
| 03-02-04 | 02 | 1 | AGNT-07 | integration | `mvn test -pl cameleer-server-app -Dtest=AgentSseControllerIT#pingKeepalive*` | ❌ W0 | ⬜ pending |
|
||||
|
||||
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
|
||||
|
||||
|
||||
@@ -51,18 +51,18 @@ re_verification: false
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|----------|----------|--------|---------|
|
||||
| `cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentRegistryService.java` | Registration, heartbeat, lifecycle, find/filter, commands | VERIFIED | 281 lines; full implementation with ConcurrentHashMap, compute-based atomic swaps, eventListener bridge |
|
||||
| `cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentInfo.java` | Immutable record with all fields and wither methods | VERIFIED | 63 lines; record with 10 fields and 5 wither-style methods |
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java` | POST /register, POST /{id}/heartbeat, GET /agents | VERIFIED | 153 lines; all three endpoints implemented with OpenAPI annotations |
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/AgentLifecycleMonitor.java` | @Scheduled LIVE->STALE->DEAD transitions | VERIFIED | 37 lines; calls `registryService.checkLifecycle()` and `expireOldCommands()` on schedule |
|
||||
| `cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentRegistryService.java` | Registration, heartbeat, lifecycle, find/filter, commands | VERIFIED | 281 lines; full implementation with ConcurrentHashMap, compute-based atomic swaps, eventListener bridge |
|
||||
| `cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentInfo.java` | Immutable record with all fields and wither methods | VERIFIED | 63 lines; record with 10 fields and 5 wither-style methods |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java` | POST /register, POST /{id}/heartbeat, GET /agents | VERIFIED | 153 lines; all three endpoints implemented with OpenAPI annotations |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/agent/AgentLifecycleMonitor.java` | @Scheduled LIVE->STALE->DEAD transitions | VERIFIED | 37 lines; calls `registryService.checkLifecycle()` and `expireOldCommands()` on schedule |
|
||||
|
||||
### Plan 02 Artifacts
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|----------|----------|--------|---------|
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java` | Per-agent SseEmitter management, event sending, ping | VERIFIED | 158 lines; implements AgentEventListener, reference-equality removal, @PostConstruct registration |
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentSseController.java` | GET /{id}/events SSE endpoint | VERIFIED | 67 lines; checks agent exists, delegates to connectionManager.connect() |
|
||||
| `cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentCommandController.java` | POST commands (single/group/broadcast) + ack | VERIFIED | 182 lines; all four endpoints implemented |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java` | Per-agent SseEmitter management, event sending, ping | VERIFIED | 158 lines; implements AgentEventListener, reference-equality removal, @PostConstruct registration |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentSseController.java` | GET /{id}/events SSE endpoint | VERIFIED | 67 lines; checks agent exists, delegates to connectionManager.connect() |
|
||||
| `cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentCommandController.java` | POST commands (single/group/broadcast) + ack | VERIFIED | 182 lines; all four endpoints implemented |
|
||||
|
||||
### Supporting Artifacts (confirmed present)
|
||||
|
||||
@@ -77,7 +77,7 @@ re_verification: false
|
||||
| `AgentRegistryBeanConfig.java` (@Configuration) | VERIFIED — creates AgentRegistryService with config values |
|
||||
| `application.yml` | VERIFIED — agent-registry section present; `spring.mvc.async.request-timeout: -1` present |
|
||||
| `application-test.yml` | VERIFIED — `agent-registry.ping-interval-ms: 1000` for fast SSE test assertions |
|
||||
| `Cameleer3ServerApplication.java` | VERIFIED — `AgentRegistryConfig.class` added to `@EnableConfigurationProperties` |
|
||||
| `CameleerServerApplication.java` | VERIFIED — `AgentRegistryConfig.class` added to `@EnableConfigurationProperties` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -5,19 +5,19 @@ type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- cameleer3-server-app/pom.xml
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/security/JwtService.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/security/Ed25519SigningService.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/JwtServiceImpl.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/Ed25519SigningServiceImpl.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/BootstrapTokenValidator.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityProperties.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityBeanConfig.java
|
||||
- cameleer3-server-app/src/main/resources/application.yml
|
||||
- cameleer3-server-app/src/test/resources/application-test.yml
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/JwtServiceTest.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/Ed25519SigningServiceTest.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/BootstrapTokenValidatorTest.java
|
||||
- cameleer-server-app/pom.xml
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/security/JwtService.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/security/Ed25519SigningService.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/JwtServiceImpl.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/Ed25519SigningServiceImpl.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/BootstrapTokenValidator.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityProperties.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityBeanConfig.java
|
||||
- cameleer-server-app/src/main/resources/application.yml
|
||||
- cameleer-server-app/src/test/resources/application-test.yml
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtServiceTest.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/Ed25519SigningServiceTest.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/BootstrapTokenValidatorTest.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- SECU-03
|
||||
@@ -31,15 +31,15 @@ must_haves:
|
||||
- "BootstrapTokenValidator accepts CAMELEER_AUTH_TOKEN and optionally CAMELEER_AUTH_TOKEN_PREVIOUS using constant-time comparison"
|
||||
- "Server fails fast on startup if CAMELEER_AUTH_TOKEN is not set"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/security/JwtService.java"
|
||||
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/security/JwtService.java"
|
||||
provides: "JWT service interface with createAccessToken, createRefreshToken, validateAndExtractAgentId"
|
||||
- path: "cameleer3-server-core/src/main/java/com/cameleer3/server/core/security/Ed25519SigningService.java"
|
||||
- path: "cameleer-server-core/src/main/java/com/cameleer/server/core/security/Ed25519SigningService.java"
|
||||
provides: "Ed25519 signing interface with sign(payload) and getPublicKeyBase64()"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/JwtServiceImpl.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/security/JwtServiceImpl.java"
|
||||
provides: "Nimbus JOSE+JWT HMAC-SHA256 implementation"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/Ed25519SigningServiceImpl.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/security/Ed25519SigningServiceImpl.java"
|
||||
provides: "JDK 17 Ed25519 KeyPairGenerator implementation"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/BootstrapTokenValidator.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/security/BootstrapTokenValidator.java"
|
||||
provides: "Constant-time bootstrap token validation with dual-token rotation"
|
||||
key_links:
|
||||
- from: "JwtServiceImpl"
|
||||
@@ -76,10 +76,10 @@ Output: Working JwtService, Ed25519SigningService, BootstrapTokenValidator with
|
||||
@.planning/phases/04-security/04-RESEARCH.md
|
||||
@.planning/phases/04-security/04-VALIDATION.md
|
||||
|
||||
@cameleer3-server-app/pom.xml
|
||||
@cameleer3-server-app/src/main/resources/application.yml
|
||||
@cameleer3-server-app/src/test/resources/application-test.yml
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/AgentRegistryConfig.java
|
||||
@cameleer-server-app/pom.xml
|
||||
@cameleer-server-app/src/main/resources/application.yml
|
||||
@cameleer-server-app/src/test/resources/application-test.yml
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryConfig.java
|
||||
|
||||
<interfaces>
|
||||
<!-- Existing patterns to follow: core module = interfaces/domain, app module = Spring implementations -->
|
||||
@@ -106,19 +106,19 @@ public class AgentRegistryConfig { ... }
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: Core interfaces + app implementations + Maven deps</name>
|
||||
<files>
|
||||
cameleer3-server-app/pom.xml,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/security/JwtService.java,
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/security/Ed25519SigningService.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/JwtServiceImpl.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/Ed25519SigningServiceImpl.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/BootstrapTokenValidator.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityProperties.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityBeanConfig.java,
|
||||
cameleer3-server-app/src/main/resources/application.yml,
|
||||
cameleer3-server-app/src/test/resources/application-test.yml,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/JwtServiceTest.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/Ed25519SigningServiceTest.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/BootstrapTokenValidatorTest.java
|
||||
cameleer-server-app/pom.xml,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/security/JwtService.java,
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/security/Ed25519SigningService.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/security/JwtServiceImpl.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/security/Ed25519SigningServiceImpl.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/security/BootstrapTokenValidator.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityProperties.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityBeanConfig.java,
|
||||
cameleer-server-app/src/main/resources/application.yml,
|
||||
cameleer-server-app/src/test/resources/application-test.yml,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtServiceTest.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/security/Ed25519SigningServiceTest.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/security/BootstrapTokenValidatorTest.java
|
||||
</files>
|
||||
<behavior>
|
||||
JwtService tests:
|
||||
@@ -145,7 +145,7 @@ public class AgentRegistryConfig { ... }
|
||||
- Uses constant-time comparison (MessageDigest.isEqual)
|
||||
</behavior>
|
||||
<action>
|
||||
1. Add Maven dependencies to cameleer3-server-app/pom.xml:
|
||||
1. Add Maven dependencies to cameleer-server-app/pom.xml:
|
||||
- `spring-boot-starter-security` (managed version)
|
||||
- `com.nimbusds:nimbus-jose-jwt:9.47` (explicit, may not be transitive without OAuth2 resource server)
|
||||
- `spring-security-test` scope test (managed version)
|
||||
@@ -165,12 +165,12 @@ public class AgentRegistryConfig { ... }
|
||||
|
||||
5. Update application-test.yml: Add `security.bootstrap-token: test-bootstrap-token`, `security.bootstrap-token-previous: old-bootstrap-token`. Also set `CAMELEER_AUTH_TOKEN: test-bootstrap-token` as an env override if needed.
|
||||
|
||||
6. IMPORTANT: Adding spring-boot-starter-security will break ALL existing tests immediately (401 on all endpoints). To prevent this during Plan 01 (before the security filter chain is configured in Plan 02), add a temporary test security config class `src/test/java/com/cameleer3/server/app/security/TestSecurityConfig.java` annotated `@TestConfiguration` that creates a `SecurityFilterChain` permitting all requests. This keeps existing tests green while security services are built. Plan 02 will replace this with real security config and update tests.
|
||||
6. IMPORTANT: Adding spring-boot-starter-security will break ALL existing tests immediately (401 on all endpoints). To prevent this during Plan 01 (before the security filter chain is configured in Plan 02), add a temporary test security config class `src/test/java/com/cameleer/server/app/security/TestSecurityConfig.java` annotated `@TestConfiguration` that creates a `SecurityFilterChain` permitting all requests. This keeps existing tests green while security services are built. Plan 02 will replace this with real security config and update tests.
|
||||
|
||||
7. Write unit tests per the behavior spec above. Tests should NOT require Spring context -- construct implementations directly with test SecurityProperties.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /c/Users/Hendrik/Documents/projects/cameleer3-server && mvn test -pl cameleer3-server-app -Dtest="JwtServiceTest,Ed25519SigningServiceTest,BootstrapTokenValidatorTest" -Dsurefire.reuseForks=false</automated>
|
||||
<automated>cd /c/Users/Hendrik/Documents/projects/cameleer-server && mvn test -pl cameleer-server-app -Dtest="JwtServiceTest,Ed25519SigningServiceTest,BootstrapTokenValidatorTest" -Dsurefire.reuseForks=false</automated>
|
||||
</verify>
|
||||
<done>
|
||||
- JwtService creates and validates access/refresh JWTs with correct claims and expiry
|
||||
|
||||
@@ -25,22 +25,22 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/security/JwtService.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/security/Ed25519SigningService.java
|
||||
- cameleer3-server-core/src/main/java/com/cameleer3/server/core/security/InvalidTokenException.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/JwtServiceImpl.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/Ed25519SigningServiceImpl.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/BootstrapTokenValidator.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityProperties.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityBeanConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/TestSecurityConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/JwtServiceTest.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/Ed25519SigningServiceTest.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/BootstrapTokenValidatorTest.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/security/JwtService.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/security/Ed25519SigningService.java
|
||||
- cameleer-server-core/src/main/java/com/cameleer/server/core/security/InvalidTokenException.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/JwtServiceImpl.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/Ed25519SigningServiceImpl.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/BootstrapTokenValidator.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityProperties.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityBeanConfig.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/TestSecurityConfig.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtServiceTest.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/Ed25519SigningServiceTest.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/BootstrapTokenValidatorTest.java
|
||||
modified:
|
||||
- cameleer3-server-app/pom.xml
|
||||
- cameleer3-server-app/src/main/resources/application.yml
|
||||
- cameleer3-server-app/src/test/resources/application-test.yml
|
||||
- cameleer-server-app/pom.xml
|
||||
- cameleer-server-app/src/main/resources/application.yml
|
||||
- cameleer-server-app/src/test/resources/application-test.yml
|
||||
|
||||
key-decisions:
|
||||
- "HMAC-SHA256 with ephemeral 256-bit secret for JWT signing (simpler than Ed25519 for tokens, Ed25519 reserved for config signing)"
|
||||
@@ -91,21 +91,21 @@ _No REFACTOR commit needed -- implementations are clean and minimal._
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `cameleer3-server-core/.../security/JwtService.java` - JWT service interface with create/validate methods
|
||||
- `cameleer3-server-core/.../security/Ed25519SigningService.java` - Ed25519 signing interface with sign/getPublicKeyBase64
|
||||
- `cameleer3-server-core/.../security/InvalidTokenException.java` - Runtime exception for invalid/expired/wrong-type tokens
|
||||
- `cameleer3-server-app/.../security/JwtServiceImpl.java` - Nimbus JOSE+JWT HMAC-SHA256 implementation
|
||||
- `cameleer3-server-app/.../security/Ed25519SigningServiceImpl.java` - JDK 17 Ed25519 KeyPairGenerator implementation
|
||||
- `cameleer3-server-app/.../security/BootstrapTokenValidator.java` - Constant-time bootstrap token validation
|
||||
- `cameleer3-server-app/.../security/SecurityProperties.java` - Config properties for token expiry and bootstrap tokens
|
||||
- `cameleer3-server-app/.../security/SecurityBeanConfig.java` - Bean wiring with fail-fast startup validation
|
||||
- `cameleer3-server-app/.../security/TestSecurityConfig.java` - Temporary permit-all for existing test compatibility
|
||||
- `cameleer3-server-app/pom.xml` - Added nimbus-jose-jwt, spring-boot-starter-security, spring-security-test
|
||||
- `cameleer3-server-app/.../application.yml` - Security config section with env var mapping
|
||||
- `cameleer3-server-app/.../application-test.yml` - Test bootstrap token values
|
||||
- `cameleer3-server-app/.../security/JwtServiceTest.java` - 7 unit tests for JWT creation/validation
|
||||
- `cameleer3-server-app/.../security/Ed25519SigningServiceTest.java` - 5 unit tests for signing/verification
|
||||
- `cameleer3-server-app/.../security/BootstrapTokenValidatorTest.java` - 6 unit tests for token matching
|
||||
- `cameleer-server-core/.../security/JwtService.java` - JWT service interface with create/validate methods
|
||||
- `cameleer-server-core/.../security/Ed25519SigningService.java` - Ed25519 signing interface with sign/getPublicKeyBase64
|
||||
- `cameleer-server-core/.../security/InvalidTokenException.java` - Runtime exception for invalid/expired/wrong-type tokens
|
||||
- `cameleer-server-app/.../security/JwtServiceImpl.java` - Nimbus JOSE+JWT HMAC-SHA256 implementation
|
||||
- `cameleer-server-app/.../security/Ed25519SigningServiceImpl.java` - JDK 17 Ed25519 KeyPairGenerator implementation
|
||||
- `cameleer-server-app/.../security/BootstrapTokenValidator.java` - Constant-time bootstrap token validation
|
||||
- `cameleer-server-app/.../security/SecurityProperties.java` - Config properties for token expiry and bootstrap tokens
|
||||
- `cameleer-server-app/.../security/SecurityBeanConfig.java` - Bean wiring with fail-fast startup validation
|
||||
- `cameleer-server-app/.../security/TestSecurityConfig.java` - Temporary permit-all for existing test compatibility
|
||||
- `cameleer-server-app/pom.xml` - Added nimbus-jose-jwt, spring-boot-starter-security, spring-security-test
|
||||
- `cameleer-server-app/.../application.yml` - Security config section with env var mapping
|
||||
- `cameleer-server-app/.../application-test.yml` - Test bootstrap token values
|
||||
- `cameleer-server-app/.../security/JwtServiceTest.java` - 7 unit tests for JWT creation/validation
|
||||
- `cameleer-server-app/.../security/Ed25519SigningServiceTest.java` - 5 unit tests for signing/verification
|
||||
- `cameleer-server-app/.../security/BootstrapTokenValidatorTest.java` - 6 unit tests for token matching
|
||||
|
||||
## Decisions Made
|
||||
|
||||
|
||||
@@ -5,17 +5,17 @@ type: execute
|
||||
wave: 2
|
||||
depends_on: ["04-01"]
|
||||
files_modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/JwtAuthenticationFilter.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityConfig.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentSseController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/SecurityFilterIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/JwtRefreshIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/RegistrationSecurityIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/BootstrapTokenIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/TestSecurityHelper.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/TestSecurityConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/JwtAuthenticationFilter.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityConfig.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentSseController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/SecurityFilterIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtRefreshIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/RegistrationSecurityIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/BootstrapTokenIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/TestSecurityHelper.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/TestSecurityConfig.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- SECU-01
|
||||
@@ -30,11 +30,11 @@ must_haves:
|
||||
- "SSE endpoint accepts JWT via ?token= query parameter"
|
||||
- "Health endpoint and Swagger UI remain publicly accessible"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/JwtAuthenticationFilter.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/security/JwtAuthenticationFilter.java"
|
||||
provides: "OncePerRequestFilter extracting JWT from header or query param"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityConfig.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityConfig.java"
|
||||
provides: "SecurityFilterChain with permitAll for public paths, authenticated for rest"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java"
|
||||
provides: "Updated register endpoint with bootstrap token validation, JWT issuance, public key"
|
||||
key_links:
|
||||
- from: "JwtAuthenticationFilter"
|
||||
@@ -76,11 +76,11 @@ Output: Working security filter chain with protected/public endpoints, registrat
|
||||
@.planning/phases/04-security/04-VALIDATION.md
|
||||
@.planning/phases/04-security/04-01-SUMMARY.md
|
||||
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentSseController.java
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
@cameleer3-server-app/src/test/java/com/cameleer3/server/app/AbstractClickHouseIT.java
|
||||
@cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentRegistrationControllerIT.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentSseController.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
@cameleer-server-app/src/test/java/com/cameleer/server/app/AbstractClickHouseIT.java
|
||||
@cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentRegistrationControllerIT.java
|
||||
|
||||
<interfaces>
|
||||
<!-- From Plan 01 (will exist after execution): -->
|
||||
@@ -136,11 +136,11 @@ public class AgentRegistryService {
|
||||
<task type="auto">
|
||||
<name>Task 1: SecurityFilterChain + JwtAuthenticationFilter + registration/refresh integration</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/JwtAuthenticationFilter.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityConfig.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentSseController.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/security/JwtAuthenticationFilter.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityConfig.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentSseController.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
</files>
|
||||
<action>
|
||||
1. Create `JwtAuthenticationFilter extends OncePerRequestFilter` (NOT annotated @Component -- constructed in SecurityConfig to avoid double registration):
|
||||
@@ -176,7 +176,7 @@ public class AgentRegistryService {
|
||||
6. Update `WebConfig` if needed: The `ProtocolVersionInterceptor` excluded paths should align with Spring Security public paths. The SSE events path is already excluded from protocol version check (Phase 3 decision). Verify no conflicts.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /c/Users/Hendrik/Documents/projects/cameleer3-server && mvn clean compile -pl cameleer3-server-app</automated>
|
||||
<automated>cd /c/Users/Hendrik/Documents/projects/cameleer-server && mvn clean compile -pl cameleer-server-app</automated>
|
||||
</verify>
|
||||
<done>
|
||||
- SecurityConfig creates stateless filter chain with correct public/protected path split
|
||||
@@ -190,28 +190,28 @@ public class AgentRegistryService {
|
||||
<task type="auto">
|
||||
<name>Task 2: Security integration tests + existing test adaptation</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/TestSecurityHelper.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/TestSecurityConfig.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/SecurityFilterIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/JwtRefreshIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/RegistrationSecurityIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/BootstrapTokenIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentRegistrationControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ExecutionControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/MetricsControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/BackpressureIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramRenderControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DetailControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/SearchControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentCommandControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentSseControllerIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/IngestionSchemaIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/interceptor/ProtocolVersionIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/OpenApiIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ForwardCompatIT.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/HealthControllerIT.java
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/TestSecurityHelper.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/security/TestSecurityConfig.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/security/SecurityFilterIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtRefreshIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/security/RegistrationSecurityIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/security/BootstrapTokenIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentRegistrationControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ExecutionControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/MetricsControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/BackpressureIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramRenderControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DetailControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentCommandControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentSseControllerIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/storage/DiagramLinkingIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/storage/IngestionSchemaIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/interceptor/ProtocolVersionIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/OpenApiIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ForwardCompatIT.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/controller/HealthControllerIT.java
|
||||
</files>
|
||||
<action>
|
||||
1. Replace the Plan 01 temporary `TestSecurityConfig` (permit-all) with real security active in tests. Remove the permit-all override so tests run with actual security enforcement.
|
||||
@@ -259,7 +259,7 @@ public class AgentRegistryService {
|
||||
- Test: New access token from refresh can access protected endpoints
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /c/Users/Hendrik/Documents/projects/cameleer3-server && mvn clean verify</automated>
|
||||
<automated>cd /c/Users/Hendrik/Documents/projects/cameleer-server && mvn clean verify</automated>
|
||||
</verify>
|
||||
<done>
|
||||
- All 17 existing ITs pass with JWT authentication
|
||||
|
||||
@@ -25,31 +25,31 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/JwtAuthenticationFilter.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/TestSecurityHelper.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/SecurityFilterIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/BootstrapTokenIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/RegistrationSecurityIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/JwtRefreshIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/JwtAuthenticationFilter.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityConfig.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/TestSecurityHelper.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/SecurityFilterIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/BootstrapTokenIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/RegistrationSecurityIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtRefreshIT.java
|
||||
modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/TestSecurityConfig.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentRegistrationControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ExecutionControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/MetricsControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/BackpressureIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramRenderControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DetailControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/SearchControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentCommandControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentSseControllerIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/IngestionSchemaIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/interceptor/ProtocolVersionIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ForwardCompatIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/TestSecurityConfig.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentRegistrationControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ExecutionControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/MetricsControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/BackpressureIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramRenderControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DetailControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentCommandControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentSseControllerIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/storage/DiagramLinkingIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/storage/IngestionSchemaIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/interceptor/ProtocolVersionIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ForwardCompatIT.java
|
||||
|
||||
key-decisions:
|
||||
- "Added /error to SecurityConfig permitAll to allow Spring Boot error page forwarding through security"
|
||||
|
||||
@@ -5,10 +5,10 @@ type: execute
|
||||
wave: 2
|
||||
depends_on: ["04-01"]
|
||||
files_modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SsePayloadSigner.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/SseSigningIT.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/agent/SsePayloadSignerTest.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SsePayloadSigner.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/SseSigningIT.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/agent/SsePayloadSignerTest.java
|
||||
autonomous: true
|
||||
requirements:
|
||||
- SECU-04
|
||||
@@ -19,9 +19,9 @@ must_haves:
|
||||
- "Signature is computed over the payload JSON without the signature field, then added as a 'signature' field"
|
||||
- "Agent can verify the signature using the public key received at registration"
|
||||
artifacts:
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SsePayloadSigner.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SsePayloadSigner.java"
|
||||
provides: "Component that signs SSE command payloads before delivery"
|
||||
- path: "cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java"
|
||||
- path: "cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java"
|
||||
provides: "Updated onCommandReady with signing before sendEvent"
|
||||
key_links:
|
||||
- from: "SseConnectionManager.onCommandReady"
|
||||
@@ -54,7 +54,7 @@ Output: All SSE command events carry verifiable Ed25519 signatures.
|
||||
@.planning/phases/04-security/04-RESEARCH.md
|
||||
@.planning/phases/04-security/04-01-SUMMARY.md
|
||||
|
||||
@cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java
|
||||
@cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java
|
||||
|
||||
<interfaces>
|
||||
<!-- From Plan 01 (will exist after execution): -->
|
||||
@@ -98,10 +98,10 @@ public record AgentCommand(String id, CommandType type, String payload, String a
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: SsePayloadSigner + signing integration in SseConnectionManager</name>
|
||||
<files>
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SsePayloadSigner.java,
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/agent/SsePayloadSignerTest.java,
|
||||
cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/SseSigningIT.java
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SsePayloadSigner.java,
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/agent/SsePayloadSignerTest.java,
|
||||
cameleer-server-app/src/test/java/com/cameleer/server/app/security/SseSigningIT.java
|
||||
</files>
|
||||
<behavior>
|
||||
SsePayloadSigner unit tests:
|
||||
@@ -155,7 +155,7 @@ public record AgentCommand(String id, CommandType type, String payload, String a
|
||||
- NOTE: This test depends on Plan 02's bootstrap token and JWT auth being in place. If Plan 03 executes before Plan 02, the test will need the TestSecurityHelper or a different auth approach. Since both are Wave 2 but independent, document this: "If Plan 02 is not yet complete, use TestSecurityHelper from Plan 01's temporary permit-all config."
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /c/Users/Hendrik/Documents/projects/cameleer3-server && mvn test -pl cameleer3-server-app -Dtest="SsePayloadSignerTest,SseSigningIT" -Dsurefire.reuseForks=false</automated>
|
||||
<automated>cd /c/Users/Hendrik/Documents/projects/cameleer-server && mvn test -pl cameleer-server-app -Dtest="SsePayloadSignerTest,SseSigningIT" -Dsurefire.reuseForks=false</automated>
|
||||
</verify>
|
||||
<done>
|
||||
- SsePayloadSigner signs JSON payloads with Ed25519 and adds signature field
|
||||
|
||||
@@ -22,11 +22,11 @@ tech-stack:
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SsePayloadSigner.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/agent/SsePayloadSignerTest.java
|
||||
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/SseSigningIT.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SsePayloadSigner.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/agent/SsePayloadSignerTest.java
|
||||
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/SseSigningIT.java
|
||||
modified:
|
||||
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/agent/SseConnectionManager.java
|
||||
- cameleer-server-app/src/main/java/com/cameleer/server/app/agent/SseConnectionManager.java
|
||||
|
||||
key-decisions:
|
||||
- "Signed payload parsed to JsonNode before passing to SseEmitter to avoid double-quoting raw JSON strings"
|
||||
@@ -73,10 +73,10 @@ _No REFACTOR commit needed -- implementation is clean and minimal._
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `cameleer3-server-app/.../agent/SsePayloadSigner.java` - Component that signs JSON payloads with Ed25519 and adds signature field
|
||||
- `cameleer3-server-app/.../agent/SseConnectionManager.java` - Updated onCommandReady to sign payload before SSE delivery
|
||||
- `cameleer3-server-app/.../agent/SsePayloadSignerTest.java` - 7 unit tests for signing behavior and edge cases
|
||||
- `cameleer3-server-app/.../security/SseSigningIT.java` - 2 integration tests for end-to-end signature verification
|
||||
- `cameleer-server-app/.../agent/SsePayloadSigner.java` - Component that signs JSON payloads with Ed25519 and adds signature field
|
||||
- `cameleer-server-app/.../agent/SseConnectionManager.java` - Updated onCommandReady to sign payload before SSE delivery
|
||||
- `cameleer-server-app/.../agent/SsePayloadSignerTest.java` - 7 unit tests for signing behavior and edge cases
|
||||
- `cameleer-server-app/.../security/SseSigningIT.java` - 2 integration tests for end-to-end signature verification
|
||||
|
||||
## Decisions Made
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## Summary
|
||||
|
||||
This phase adds authentication and integrity protection to the Cameleer3 server. The implementation uses Spring Security 6.4.3 (managed by Spring Boot 3.4.3) with a custom `OncePerRequestFilter` for JWT validation, JDK 17 built-in Ed25519 for signing SSE payloads, and environment variable-based bootstrap tokens for agent registration. The approach is deliberately simple -- no OAuth2 resource server, no external identity provider, just symmetric HMAC JWTs for access control and Ed25519 signatures for payload integrity.
|
||||
This phase adds authentication and integrity protection to the Cameleer server. The implementation uses Spring Security 6.4.3 (managed by Spring Boot 3.4.3) with a custom `OncePerRequestFilter` for JWT validation, JDK 17 built-in Ed25519 for signing SSE payloads, and environment variable-based bootstrap tokens for agent registration. The approach is deliberately simple -- no OAuth2 resource server, no external identity provider, just symmetric HMAC JWTs for access control and Ed25519 signatures for payload integrity.
|
||||
|
||||
The existing codebase has clear integration points: `AgentRegistrationController.register()` already returns `serverPublicKey: null` as a placeholder, `SseConnectionManager.onCommandReady()` is the signing hook for SSE events, and `WebConfig` already defines excluded paths that align with the public endpoint list. Spring Security's `SecurityFilterChain` replaces the need for hand-rolled authorization logic -- endpoints are protected by default, with explicit `permitAll()` for health, register, and docs.
|
||||
|
||||
@@ -89,7 +89,7 @@ The existing codebase has clear integration points: `AgentRegistrationController
|
||||
- **Ed25519 library:** Use JDK built-in. Zero external dependencies, native performance, well-tested in JDK 17+.
|
||||
- **Refresh token storage:** Use stateless signed refresh tokens (also HMAC-signed JWTs with different claims/expiry). This avoids any in-memory storage for refresh tokens and scales naturally. The refresh token is just a JWT with `type=refresh`, `sub=agentId`, and 7-day expiry. On refresh, validate the refresh JWT, check agent still exists, issue new access JWT.
|
||||
|
||||
**Installation (add to cameleer3-server-app pom.xml):**
|
||||
**Installation (add to cameleer-server-app pom.xml):**
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -108,12 +108,12 @@ Note: If `spring-boot-starter-security` brings Nimbus transitively (via `spring-
|
||||
|
||||
### Recommended Project Structure
|
||||
```
|
||||
cameleer3-server-core/src/main/java/com/cameleer3/server/core/
|
||||
cameleer-server-core/src/main/java/com/cameleer/server/core/
|
||||
security/
|
||||
JwtService.java # Interface: createAccessToken, createRefreshToken, validateToken, extractAgentId
|
||||
Ed25519SigningService.java # Interface: sign(payload) -> signature, getPublicKeyBase64()
|
||||
|
||||
cameleer3-server-app/src/main/java/com/cameleer3/server/app/
|
||||
cameleer-server-app/src/main/java/com/cameleer/server/app/
|
||||
security/
|
||||
JwtServiceImpl.java # Nimbus JOSE+JWT HMAC implementation
|
||||
Ed25519SigningServiceImpl.java # JDK Ed25519 keypair + signing implementation
|
||||
@@ -439,23 +439,23 @@ public boolean validateBootstrapToken(String provided) {
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Framework | JUnit 5 + Spring Boot Test (spring-boot-starter-test) |
|
||||
| Config file | `cameleer3-server-app/src/test/resources/application-test.yml` |
|
||||
| Quick run command | `mvn test -pl cameleer3-server-app -Dtest=Security*Test -Dsurefire.reuseForks=false` |
|
||||
| Config file | `cameleer-server-app/src/test/resources/application-test.yml` |
|
||||
| Quick run command | `mvn test -pl cameleer-server-app -Dtest=Security*Test -Dsurefire.reuseForks=false` |
|
||||
| Full suite command | `mvn clean verify` |
|
||||
|
||||
### Phase Requirements to Test Map
|
||||
| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|
||||
|--------|----------|-----------|-------------------|-------------|
|
||||
| SECU-01 | Protected endpoints reject requests without JWT; public endpoints accessible | integration | `mvn test -pl cameleer3-server-app -Dtest=SecurityFilterIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| SECU-02 | Refresh endpoint issues new access JWT from valid refresh token | integration | `mvn test -pl cameleer3-server-app -Dtest=JwtRefreshIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| SECU-03 | Ed25519 keypair generated at startup; public key in registration response | integration | `mvn test -pl cameleer3-server-app -Dtest=RegistrationSecurityIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| SECU-04 | SSE payloads carry valid Ed25519 signature | integration | `mvn test -pl cameleer3-server-app -Dtest=SseSigningIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| SECU-05 | Bootstrap token required for registration; rejects invalid/missing tokens | integration | `mvn test -pl cameleer3-server-app -Dtest=BootstrapTokenIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| N/A | JWT creation, validation, expiry logic | unit | `mvn test -pl cameleer3-server-app -Dtest=JwtServiceTest -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| N/A | Ed25519 signing and verification roundtrip | unit | `mvn test -pl cameleer3-server-app -Dtest=Ed25519SigningServiceTest -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| SECU-01 | Protected endpoints reject requests without JWT; public endpoints accessible | integration | `mvn test -pl cameleer-server-app -Dtest=SecurityFilterIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| SECU-02 | Refresh endpoint issues new access JWT from valid refresh token | integration | `mvn test -pl cameleer-server-app -Dtest=JwtRefreshIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| SECU-03 | Ed25519 keypair generated at startup; public key in registration response | integration | `mvn test -pl cameleer-server-app -Dtest=RegistrationSecurityIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| SECU-04 | SSE payloads carry valid Ed25519 signature | integration | `mvn test -pl cameleer-server-app -Dtest=SseSigningIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| SECU-05 | Bootstrap token required for registration; rejects invalid/missing tokens | integration | `mvn test -pl cameleer-server-app -Dtest=BootstrapTokenIT -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| N/A | JWT creation, validation, expiry logic | unit | `mvn test -pl cameleer-server-app -Dtest=JwtServiceTest -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
| N/A | Ed25519 signing and verification roundtrip | unit | `mvn test -pl cameleer-server-app -Dtest=Ed25519SigningServiceTest -Dsurefire.reuseForks=false` | No -- Wave 0 |
|
||||
|
||||
### Sampling Rate
|
||||
- **Per task commit:** `mvn test -pl cameleer3-server-app -Dsurefire.reuseForks=false`
|
||||
- **Per task commit:** `mvn test -pl cameleer-server-app -Dsurefire.reuseForks=false`
|
||||
- **Per wave merge:** `mvn clean verify`
|
||||
- **Phase gate:** Full suite green before `/gsd:verify-work`
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ created: 2026-03-11
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Framework** | JUnit 5 + Spring Boot Test + Spring Security Test |
|
||||
| **Config file** | cameleer3-server-app/src/test/resources/application-test.yml |
|
||||
| **Quick run command** | `mvn test -pl cameleer3-server-app -Dtest="Security*,Jwt*,Bootstrap*,Ed25519*" -Dsurefire.reuseForks=false` |
|
||||
| **Config file** | cameleer-server-app/src/test/resources/application-test.yml |
|
||||
| **Quick run command** | `mvn test -pl cameleer-server-app -Dtest="Security*,Jwt*,Bootstrap*,Ed25519*" -Dsurefire.reuseForks=false` |
|
||||
| **Full suite command** | `mvn clean verify` |
|
||||
| **Estimated runtime** | ~60 seconds |
|
||||
|
||||
@@ -27,7 +27,7 @@ created: 2026-03-11
|
||||
|
||||
## Sampling Rate
|
||||
|
||||
- **After every task commit:** Run `mvn test -pl cameleer3-server-app -Dsurefire.reuseForks=false`
|
||||
- **After every task commit:** Run `mvn test -pl cameleer-server-app -Dsurefire.reuseForks=false`
|
||||
- **After every plan wave:** Run `mvn clean verify`
|
||||
- **Before `/gsd:verify-work`:** Full suite must be green
|
||||
- **Max feedback latency:** 60 seconds
|
||||
@@ -38,13 +38,13 @@ created: 2026-03-11
|
||||
|
||||
| Task ID | Plan | Wave | Requirement | Test Type | Automated Command | File Exists | Status |
|
||||
|---------|------|------|-------------|-----------|-------------------|-------------|--------|
|
||||
| 04-01-01 | 01 | 1 | SECU-03 | unit | `mvn test -pl cameleer3-server-app -Dtest=Ed25519SigningServiceTest -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-02 | 01 | 1 | SECU-01 | unit | `mvn test -pl cameleer3-server-app -Dtest=JwtServiceTest -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-03 | 01 | 1 | SECU-05 | integration | `mvn test -pl cameleer3-server-app -Dtest=BootstrapTokenIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-04 | 01 | 1 | SECU-01 | integration | `mvn test -pl cameleer3-server-app -Dtest=SecurityFilterIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-05 | 01 | 1 | SECU-02 | integration | `mvn test -pl cameleer3-server-app -Dtest=JwtRefreshIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-06 | 01 | 1 | SECU-04 | integration | `mvn test -pl cameleer3-server-app -Dtest=SseSigningIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-07 | 01 | 1 | N/A | integration | `mvn test -pl cameleer3-server-app -Dtest=RegistrationSecurityIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-01 | 01 | 1 | SECU-03 | unit | `mvn test -pl cameleer-server-app -Dtest=Ed25519SigningServiceTest -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-02 | 01 | 1 | SECU-01 | unit | `mvn test -pl cameleer-server-app -Dtest=JwtServiceTest -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-03 | 01 | 1 | SECU-05 | integration | `mvn test -pl cameleer-server-app -Dtest=BootstrapTokenIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-04 | 01 | 1 | SECU-01 | integration | `mvn test -pl cameleer-server-app -Dtest=SecurityFilterIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-05 | 01 | 1 | SECU-02 | integration | `mvn test -pl cameleer-server-app -Dtest=JwtRefreshIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-06 | 01 | 1 | SECU-04 | integration | `mvn test -pl cameleer-server-app -Dtest=SseSigningIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
| 04-01-07 | 01 | 1 | N/A | integration | `mvn test -pl cameleer-server-app -Dtest=RegistrationSecurityIT -Dsurefire.reuseForks=false` | ❌ W0 | ⬜ pending |
|
||||
|
||||
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
|
||||
|
||||
|
||||
@@ -39,19 +39,19 @@ All truths drawn from PLAN frontmatter must_haves across plans 01, 02, and 03.
|
||||
|
||||
| Artifact | Provides | Status | Details |
|
||||
|----------|----------|--------|---------|
|
||||
| `cameleer3-server-core/.../security/JwtService.java` | JWT interface: createAccessToken, createRefreshToken, validateAndExtractAgentId, validateRefreshToken | VERIFIED | 49 lines, substantive interface with 4 methods |
|
||||
| `cameleer3-server-core/.../security/Ed25519SigningService.java` | Ed25519 interface: sign(payload), getPublicKeyBase64() | VERIFIED | 29 lines, substantive interface with 2 methods |
|
||||
| `cameleer3-server-app/.../security/JwtServiceImpl.java` | Nimbus JOSE+JWT HMAC-SHA256 implementation | VERIFIED | 120 lines; uses `MACSigner`/`MACVerifier`, ephemeral 256-bit secret, correct claims |
|
||||
| `cameleer3-server-app/.../security/Ed25519SigningServiceImpl.java` | JDK 17 Ed25519 KeyPairGenerator implementation | VERIFIED | 54 lines; `KeyPairGenerator.getInstance("Ed25519")`, `Signature.getInstance("Ed25519")`, Base64-encoded output |
|
||||
| `cameleer3-server-app/.../security/BootstrapTokenValidator.java` | Constant-time bootstrap token validation with dual-token rotation | VERIFIED | 50 lines; `MessageDigest.isEqual()`, checks current and previous token, null/blank guard |
|
||||
| `cameleer3-server-app/.../security/SecurityProperties.java` | Config binding with env var mapping | VERIFIED | 48 lines; `@ConfigurationProperties(prefix="security")`; all 4 fields with defaults |
|
||||
| `cameleer3-server-app/.../security/SecurityBeanConfig.java` | Bean wiring with fail-fast validation | VERIFIED | 43 lines; `@EnableConfigurationProperties`, all 3 service beans, `InitializingBean` check |
|
||||
| `cameleer3-server-app/.../security/JwtAuthenticationFilter.java` | OncePerRequestFilter extracting JWT from header or query param | VERIFIED | 72 lines; extracts from `Authorization: Bearer` then `?token=` query param; sets `SecurityContextHolder` |
|
||||
| `cameleer3-server-app/.../security/SecurityConfig.java` | SecurityFilterChain with permitAll for public paths, authenticated for rest | VERIFIED | 54 lines; stateless, CSRF disabled, correct permitAll list, `addFilterBefore` JwtAuthenticationFilter |
|
||||
| `cameleer3-server-app/.../controller/AgentRegistrationController.java` | Updated register endpoint with bootstrap token validation, JWT issuance, public key; refresh endpoint | VERIFIED | 230 lines; both `/register` and `/{id}/refresh` endpoints fully wired |
|
||||
| `cameleer3-server-app/.../agent/SsePayloadSigner.java` | Component that signs SSE command payloads | VERIFIED | 77 lines; `@Component`, signs then adds field, defensive null/blank handling |
|
||||
| `cameleer3-server-app/.../agent/SseConnectionManager.java` | Updated onCommandReady with signing before sendEvent | VERIFIED | `onCommandReady()` calls `ssePayloadSigner.signPayload()`, parses to `JsonNode` to avoid double-quoting |
|
||||
| `cameleer3-server-app/.../resources/application.yml` | Security config with env var mapping | VERIFIED | `security.bootstrap-token: ${CAMELEER_AUTH_TOKEN:}` and `security.bootstrap-token-previous: ${CAMELEER_AUTH_TOKEN_PREVIOUS:}` present |
|
||||
| `cameleer-server-core/.../security/JwtService.java` | JWT interface: createAccessToken, createRefreshToken, validateAndExtractAgentId, validateRefreshToken | VERIFIED | 49 lines, substantive interface with 4 methods |
|
||||
| `cameleer-server-core/.../security/Ed25519SigningService.java` | Ed25519 interface: sign(payload), getPublicKeyBase64() | VERIFIED | 29 lines, substantive interface with 2 methods |
|
||||
| `cameleer-server-app/.../security/JwtServiceImpl.java` | Nimbus JOSE+JWT HMAC-SHA256 implementation | VERIFIED | 120 lines; uses `MACSigner`/`MACVerifier`, ephemeral 256-bit secret, correct claims |
|
||||
| `cameleer-server-app/.../security/Ed25519SigningServiceImpl.java` | JDK 17 Ed25519 KeyPairGenerator implementation | VERIFIED | 54 lines; `KeyPairGenerator.getInstance("Ed25519")`, `Signature.getInstance("Ed25519")`, Base64-encoded output |
|
||||
| `cameleer-server-app/.../security/BootstrapTokenValidator.java` | Constant-time bootstrap token validation with dual-token rotation | VERIFIED | 50 lines; `MessageDigest.isEqual()`, checks current and previous token, null/blank guard |
|
||||
| `cameleer-server-app/.../security/SecurityProperties.java` | Config binding with env var mapping | VERIFIED | 48 lines; `@ConfigurationProperties(prefix="security")`; all 4 fields with defaults |
|
||||
| `cameleer-server-app/.../security/SecurityBeanConfig.java` | Bean wiring with fail-fast validation | VERIFIED | 43 lines; `@EnableConfigurationProperties`, all 3 service beans, `InitializingBean` check |
|
||||
| `cameleer-server-app/.../security/JwtAuthenticationFilter.java` | OncePerRequestFilter extracting JWT from header or query param | VERIFIED | 72 lines; extracts from `Authorization: Bearer` then `?token=` query param; sets `SecurityContextHolder` |
|
||||
| `cameleer-server-app/.../security/SecurityConfig.java` | SecurityFilterChain with permitAll for public paths, authenticated for rest | VERIFIED | 54 lines; stateless, CSRF disabled, correct permitAll list, `addFilterBefore` JwtAuthenticationFilter |
|
||||
| `cameleer-server-app/.../controller/AgentRegistrationController.java` | Updated register endpoint with bootstrap token validation, JWT issuance, public key; refresh endpoint | VERIFIED | 230 lines; both `/register` and `/{id}/refresh` endpoints fully wired |
|
||||
| `cameleer-server-app/.../agent/SsePayloadSigner.java` | Component that signs SSE command payloads | VERIFIED | 77 lines; `@Component`, signs then adds field, defensive null/blank handling |
|
||||
| `cameleer-server-app/.../agent/SseConnectionManager.java` | Updated onCommandReady with signing before sendEvent | VERIFIED | `onCommandReady()` calls `ssePayloadSigner.signPayload()`, parses to `JsonNode` to avoid double-quoting |
|
||||
| `cameleer-server-app/.../resources/application.yml` | Security config with env var mapping | VERIFIED | `security.bootstrap-token: ${CAMELEER_AUTH_TOKEN:}` and `security.bootstrap-token-previous: ${CAMELEER_AUTH_TOKEN_PREVIOUS:}` present |
|
||||
|
||||
### Key Link Verification
|
||||
|
||||
|
||||
Reference in New Issue
Block a user