api-reference/decision-engine-api-reference/clickhouse-analytics.mdx
Decision Engine uses a Kafka to ClickHouse analytics pipeline:
ClickHouse remains the analytics read store for:
The analytics read path uses the two raw tables:
analytics_domain_eventsanalytics_api_eventsThe ingestion path is explicit in ClickHouse too:
analytics_domain_events_queueanalytics_api_events_queueanalytics_payment_audit_summary_bucketsanalytics_domain_events_mvanalytics_api_events_mvanalytics_payment_audit_summary_buckets_mvPayment Audit and Preview Trace now use a two-layer read shape:
analytics_domain_eventsanalytics_payment_audit_summary_bucketsThe correlation key for those reads is the write-time lookup_key:
payment_id when presentrequest_idStart the local analytics stack:
COMPOSE_PROFILES= docker compose --profile analytics-clickhouse up -d
That profile now includes ClickHouse, Kafka, and topic creation. The full runtime profiles use the same ClickHouse-native ingestion path. There is no separate Rust worker process anymore.
Local Compose versions:
clickhouse/clickhouse-server:26.1apache/kafka:3.8.1defaultThe bootstrap DDL now lives in:
clickhouse/scripts/ClickHouse loads those shell scripts on first boot through /docker-entrypoint-initdb.d. They create the raw tables, recreate the Kafka queue tables and materialized views, create the payment-audit summary bucket table, and bind the queue tables to the configured Kafka brokers and topics.
The analytics data volume is persistent, so normal restarts keep historical data.
If you need a clean reset:
make reset-analytics-clickhouse
Relevant config lives under:
[analytics]
enabled = true
[analytics.capture]
details_max_bytes = 65536
[analytics.kafka]
# container-to-container traffic uses the internal listener
brokers = "kafka:19092"
client_id = "decision-engine"
api_topic = "api"
domain_topic = "domain"
acks = "all"
compression = "lz4"
message_timeout_ms = 5000
queue_capacity = 250
[analytics.clickhouse]
url = "http://clickhouse:8123"
database = "default"
user = "decision_engine"
password = "decision_engine"
There is no direct API-server write path to ClickHouse anymore. ClickHouse owns Kafka consumption through the queue tables and materialized views.
The raw analytics tables retain data for 18 months:
analytics_api_eventsanalytics_domain_eventsCustom query windows are normalized to the same 18-month lookback horizon.
Useful checks when ingestion looks stalled:
SHOW TABLES FROM default;
SELECT * FROM system.kafka_consumers WHERE database = 'default';
SELECT count() FROM default.analytics_api_events;
SELECT count() FROM default.analytics_domain_events;
SELECT count() FROM default.analytics_payment_audit_summary_buckets;
SELECT name, engine FROM system.tables WHERE database = 'default' AND name LIKE 'analytics_%';
analytics-clickhouse profile.