Skip to main content
The repository includes a self-contained direct-mode commerce project. It is designed to make the important behavior visible without external services or hidden setup:
  • Redpanda creates source.order_events.live with exactly three partitions and seven-day retention.
  • A stateful local producer emits a fixed-key JSON contract with integer quantities and prices.
  • ClickHouse retains the source and serves four coherent SQL models.
  • Four SQL tests exercise region labels, additive facts, replay deduplication, and expression macros.
  • A scheduled warning audit and local console sensor demonstrate failure and natural recovery.
The checked-in project uses direct mode. stb build replaces its model relations immediately; it does not create a staged deployment or require promotion.

Prerequisites

Start the demo

From a StreamBuild source checkout:
make start builds the producer image, waits for healthy services, creates the topic, and applies the StreamBuild project. Every published service binds to loopback: The shared redpanda.localhost broker name resolves to loopback for the host-side UI and to the Redpanda service inside Compose. This lets ClickHouse ingest while StreamBuild reads real broker metadata for Topics and Kafka lag.

Event contract

Every message carries the same keys and stable types:
Quantities and unit_price_cents are JSON integers. The regular producer uses monotonic IDs and a durable pending-event checkpoint, so a crash can only resend the same event body under an ID. The one-shot injector uses a separate timestamp-based ID namespace. Producer state lives in a disposable Compose volume so restarts continue active lifecycles.
Retained commerce event with fixed keys, integer quantity and integer unit price

Model graph

order_event_facts remains append-only because replay delivery is at least once. The terminal view groups by event ID and keeps the highest replay offset before deriving revenue, average order value, cancellation rate, and refund rate. Non-additive values are never stored in a summing engine, and consumers that require event-level uniqueness use the same explicit event-ID reduction. Region names come from a tested deterministic SQL macro rather than a mutable side table in the streaming path. Logical event cardinality remains one-to-one when measured by unique event ID during both live ingestion and replay; physical append-only tables can temporarily contain exact replay duplicates.

Verify the project

Compile and run the focused SQL tests:
Expected summary:
Rebuild from retained source history at any time:
The direct build reports one replay root and all authored audit invariants passing. In ClickHouse, the following query should return the same logical event count in every column:

Inspect live state

Start the UI, audit scheduler, and sensor runner:
Open http://127.0.0.1:8000. The source page reports retained history separately from Kafka lag and shows landed, committed, and broker-end offsets for all three partitions.
Commerce source health with seven-day retention and three Kafka partitions
The terminal commerce_kpis query-only view has no physical freshness measurement, so the UI marks its status as unknown rather than falsely calling it stalled. With make dev still running, execute the repeatable full-stack acceptance checks:
This compiles the project, runs all four SQL tests and every audit, verifies three-partition broker retention, checks logical event cardinality and region labels in ClickHouse, and confirms API drift, view freshness, partition lag, and the four-model graph. Run the controlled warning, natural recovery, and sensor-delivery acceptance lane separately. It takes about 30 seconds:

Demonstrate warning and recovery

Keep make dev running. In a second terminal, inject one event 30 seconds into the future:
The orders_no_future_events audit has a ten-second cadence, matching the scheduler polling loop. It records one sampled warning row, links back to order_events, and triggers the local-only ConsoleNotifier:
Expanded future-event warning with one sampled violating row
The event remains in ClickHouse. Once the clock is within two seconds of its timestamp, the next scheduled read passes naturally and the same sensor prints:
No webhook is configured or sent. Set FUTURE_EVENT_SECONDS in .env to lengthen the observation window.

Stop or reset

Stop containers while preserving local volumes:
Remove all disposable broker, producer-state, and warehouse volumes, then start a clean stack: