From 968117c41a7f9971ae78522d1af32d13e51b3aed Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Tue, 31 Mar 2026 23:44:10 +0200 Subject: [PATCH] feat(clickhouse): wire Phase 4 stores with feature flags Add conditional beans for ClickHouseDiagramStore, ClickHouseAgentEventRepository, and ClickHouseLogStore. All default to ClickHouse (matchIfMissing=true). PG/OS stores activate only when explicitly configured. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../server/app/config/StorageBeanConfig.java | 32 +++++++++++++++++++ .../server/app/search/OpenSearchLogIndex.java | 2 ++ .../storage/PostgresAgentEventRepository.java | 2 ++ .../app/storage/PostgresDiagramStore.java | 2 ++ .../src/main/resources/application.yml | 3 ++ deploy/base/server.yaml | 6 ++++ 6 files changed, 47 insertions(+) diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/StorageBeanConfig.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/StorageBeanConfig.java index c0cf7c5d..ef51461b 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/StorageBeanConfig.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/StorageBeanConfig.java @@ -1,5 +1,8 @@ package com.cameleer3.server.app.config; +import com.cameleer3.server.app.search.ClickHouseLogStore; +import com.cameleer3.server.app.storage.ClickHouseAgentEventRepository; +import com.cameleer3.server.app.storage.ClickHouseDiagramStore; import com.cameleer3.server.app.storage.ClickHouseMetricsQueryStore; import com.cameleer3.server.app.storage.ClickHouseMetricsStore; import com.cameleer3.server.app.storage.ClickHouseStatsStore; @@ -7,6 +10,7 @@ import com.cameleer3.server.app.storage.PostgresMetricsQueryStore; import com.cameleer3.server.app.storage.PostgresMetricsStore; import com.cameleer3.server.core.admin.AuditRepository; import com.cameleer3.server.core.admin.AuditService; +import com.cameleer3.server.core.agent.AgentEventRepository; import com.cameleer3.server.core.detail.DetailService; import com.cameleer3.server.core.indexing.SearchIndexer; import com.cameleer3.server.app.ingestion.ExecutionFlushScheduler; @@ -17,6 +21,7 @@ import com.cameleer3.server.core.ingestion.IngestionService; import com.cameleer3.server.core.ingestion.MergedExecution; import com.cameleer3.server.core.ingestion.WriteBuffer; import com.cameleer3.server.core.storage.*; +import com.cameleer3.server.core.storage.LogIndex; import com.cameleer3.server.core.storage.StatsStore; import com.cameleer3.server.core.storage.model.MetricsSnapshot; import org.springframework.beans.factory.annotation.Qualifier; @@ -129,4 +134,31 @@ public class StorageBeanConfig { @Qualifier("clickHouseJdbcTemplate") JdbcTemplate clickHouseJdbc) { return new ClickHouseStatsStore(clickHouseJdbc); } + + // ── ClickHouse Diagram Store ────────────────────────────────────── + + @Bean + @ConditionalOnProperty(name = "cameleer.storage.diagrams", havingValue = "clickhouse", matchIfMissing = true) + public DiagramStore clickHouseDiagramStore( + @Qualifier("clickHouseJdbcTemplate") JdbcTemplate clickHouseJdbc) { + return new ClickHouseDiagramStore(clickHouseJdbc); + } + + // ── ClickHouse Agent Event Repository ───────────────────────────── + + @Bean + @ConditionalOnProperty(name = "cameleer.storage.events", havingValue = "clickhouse", matchIfMissing = true) + public AgentEventRepository clickHouseAgentEventRepository( + @Qualifier("clickHouseJdbcTemplate") JdbcTemplate clickHouseJdbc) { + return new ClickHouseAgentEventRepository(clickHouseJdbc); + } + + // ── ClickHouse Log Store ────────────────────────────────────────── + + @Bean + @ConditionalOnProperty(name = "cameleer.storage.logs", havingValue = "clickhouse", matchIfMissing = true) + public LogIndex clickHouseLogStore( + @Qualifier("clickHouseJdbcTemplate") JdbcTemplate clickHouseJdbc) { + return new ClickHouseLogStore(clickHouseJdbc); + } } diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/OpenSearchLogIndex.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/OpenSearchLogIndex.java index 46550010..f5cfd891 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/OpenSearchLogIndex.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/OpenSearchLogIndex.java @@ -19,6 +19,7 @@ import org.opensearch.client.opensearch.indices.PutIndexTemplateRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Repository; import java.io.IOException; @@ -31,6 +32,7 @@ import java.util.List; import java.util.Map; @Repository +@ConditionalOnProperty(name = "cameleer.storage.logs", havingValue = "opensearch") public class OpenSearchLogIndex implements LogIndex { private static final Logger log = LoggerFactory.getLogger(OpenSearchLogIndex.class); diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/PostgresAgentEventRepository.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/PostgresAgentEventRepository.java index 84c32de3..c5b03657 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/PostgresAgentEventRepository.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/PostgresAgentEventRepository.java @@ -2,6 +2,7 @@ package com.cameleer3.server.app.storage; import com.cameleer3.server.core.agent.AgentEventRecord; import com.cameleer3.server.core.agent.AgentEventRepository; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @@ -11,6 +12,7 @@ import java.util.ArrayList; import java.util.List; @Repository +@ConditionalOnProperty(name = "cameleer.storage.events", havingValue = "postgres") public class PostgresAgentEventRepository implements AgentEventRepository { private final JdbcTemplate jdbc; diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/PostgresDiagramStore.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/PostgresDiagramStore.java index c4219482..5c7128b1 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/PostgresDiagramStore.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/PostgresDiagramStore.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @@ -29,6 +30,7 @@ import java.util.Optional; * Uses {@code ON CONFLICT (content_hash) DO NOTHING} for idempotent inserts. */ @Repository +@ConditionalOnProperty(name = "cameleer.storage.diagrams", havingValue = "postgres") public class PostgresDiagramStore implements DiagramStore { private static final Logger log = LoggerFactory.getLogger(PostgresDiagramStore.class); diff --git a/cameleer3-server-app/src/main/resources/application.yml b/cameleer3-server-app/src/main/resources/application.yml index fb33265c..99e64c9e 100644 --- a/cameleer3-server-app/src/main/resources/application.yml +++ b/cameleer3-server-app/src/main/resources/application.yml @@ -52,6 +52,9 @@ cameleer: metrics: ${CAMELEER_STORAGE_METRICS:postgres} search: ${CAMELEER_STORAGE_SEARCH:opensearch} stats: ${CAMELEER_STORAGE_STATS:clickhouse} + diagrams: ${CAMELEER_STORAGE_DIAGRAMS:clickhouse} + events: ${CAMELEER_STORAGE_EVENTS:clickhouse} + logs: ${CAMELEER_STORAGE_LOGS:clickhouse} security: access-token-expiry-ms: 3600000 diff --git a/deploy/base/server.yaml b/deploy/base/server.yaml index df54842d..9991967d 100644 --- a/deploy/base/server.yaml +++ b/deploy/base/server.yaml @@ -95,6 +95,12 @@ spec: value: "clickhouse" - name: CAMELEER_STORAGE_STATS value: "clickhouse" + - name: CAMELEER_STORAGE_DIAGRAMS + value: "clickhouse" + - name: CAMELEER_STORAGE_EVENTS + value: "clickhouse" + - name: CAMELEER_STORAGE_LOGS + value: "clickhouse" resources: requests: