Streaming Data Pipeline — LIVE Scenario
A complete streaming data platform demonstrated through the simplest story everyone understands — a Mumbai cloud kitchen. Customer orders → kitchen preparation → food delivery, with every step an event flowing in real time through a production-shaped stack: SQLite with a transactional outbox, a Redpanda Connect outbox relay, Redpanda as the event log, a MinIO bronze data lake, dbt + DuckDB marts, and live auto-refreshing dashboards. Python powers the pipeline, TypeScript the dashboard, SQL (dbt) the warehouse — and there is no JVM anywhere in the stack.
This is a live, running pipeline — watch orders stream through it in real time. The demo lives exactly one business day: data is wiped every midnight and the kitchen reopens fresh.
stream.steleios.com ↗Objective
What this project sets out to do
Make streaming architecture legible — and prove it behaves like production. Every core streaming concept — topics, partitions, consumer groups, offsets, delivery semantics, idempotency, dead-letter queues, change data capture, replay, backpressure, event time vs processing time, schema drift — is not explained on a slide but demonstrated live in a running system. And the system earns the word production-shaped: no dual writes, no lost sale, effectively exactly-once processing, and 279 automated checks behind it — including hostile-input and schema-drift drills fired at the live pipeline, two of which found real bugs that are now fixed and pinned by tests.
What we're delivering
Feature Highlights
No dual writes — outbox + relay
Every state change commits the business rows and the event into a transactional outbox in one SQLite transaction; a Redpanda Connect relay tails that outbox and is the only thing that publishes. If the transaction rolls back, neither exists — the database and the stream can never diverge.
Redpanda as the system of record
Four topics, three partitions keyed by order id — per-order ordering with parallel scale-out — on infinite retention and a persistent volume. Idempotent producers (acks=all) plus ack-after-work offset commits give at-least-once delivery; idempotent processing at every layer makes it effectively exactly-once. No sale is ever lost to a crash.
The whole stack, without a JVM
Redpanda is a single C++ binary with its own Raft — no broker JVM, no ZooKeeper — and both integration hops are small Go pipelines rather than a Connect cluster running plugins. Measured on the live 2-vCPU VM under a full order feed, the entire streaming tier runs at roughly 3% CPU and 352 MB, against the ~1.7 GB of JVM heap the equivalent Kafka, Kafka Connect and MySQL tier was configured to reserve.
Bronze lake to tested marts
A second Redpanda Connect pipeline sinks every event as date-partitioned raw JSON into MinIO — the bronze layer nothing can delete — and dbt on DuckDB builds order facts, item profitability, and per-minute demand, with in-warehouse tests asserting the profit equation, the delivery physics, and the fulfillment rules on every run.
Live operations dashboards
A fully typed Bun backend reads the same stream with its own consumer group and rebuilds complete state from offset zero on every boot; the Vue 3 + Pinia frontend serves owner analytics, kitchen and delivery ops boards, per-order live customer tracking, and an append-only audit log — auto-refreshing every two seconds.
Tested by attacking it
The relay was killed mid-stream with its cursor at 1,331: twelve orders placed while it was dead kept committing to SQLite, and on restart exactly those twelve published — no loss, no duplicates. Malformed bytes, unknown event types and business-rule violations fired at the live topics are dead-lettered with reasons, never dropped and never crashing a consumer.
279 automated checks
180 Python unit tests with passing and failing cases for every business rule — the repository suite running against a real SQLite file, so schema constraints, rollback, WAL mode and concurrent writers are genuinely exercised — plus 41 TypeScript dashboard tests, 36 dbt tests in-warehouse, and 22 live end-to-end edge-case checks covering hostile input, schema drift and an API that fails closed. There is no database account to leak: the OLTP store is a file, and the relay opens it read-only.
The pipeline, live · every dot is an order event; the callouts note the complexity handled at each hop
Failure Handling
Production failure cases, handled by design
A streaming pipeline is defined by what happens when things go wrong — a crashed consumer, a duplicated message, a stalled relay, a hostile payload, a contract that moves underneath you. Every case below is handled in the running system, and most were proven by firing the failure at it rather than assumed.
- Dual-write problem — state changes commit business rows and the event into the outbox in one SQLite transaction; the Redpanda Connect relay is the only thing that publishes them. The database and the stream cannot disagree.
- Relay crash mid-batch — the cursor advances only after Redpanda acknowledges the whole batch, so a crash replays it rather than skipping it. Proven live: killed at cursor 1,331, twelve orders placed while it was dead, exactly twelve published on restart.
- Service crash mid-order — consumers commit offsets only after the work finishes, via a per-partition ack watermark. A crashed kitchen or delivery service replays its unfinished orders on restart instead of skipping them.
- Duplicate events (at-least-once) — every layer is idempotent: services skip seen order ids, the dashboard dedupes by event id, dbt staging keeps exactly one row per event id.
- Out-of-order arrival — cross-topic ordering isn't guaranteed, so the dashboard folds events monotonically: a late event can never move an order's status backwards.
- Malformed / hostile payloads — broker messages are treated as untrusted input and validated on parse. Failures go to the dead-letter topic with the reason in headers, are audit-logged, and never crash a consumer — fail closed, per message.
- Schema drift — deliberately asymmetric, because the three directions carry different risk. A new field added by a newer producer is ignored; a missing optional field reads as unset; a changed schema version is rejected to the dead-letter queue rather than half-parsed. Firing all three at the live pipeline is what caught a real bug: the Python consumers enforced the version but the dashboard did not, so an incompatible event was quarantined by one and silently accepted by the other. All three boundaries now agree.
- Poison message in the data lake — bronze is newline-delimited JSON, so one unparseable line makes an entire file unreadable and can take down a whole warehouse build. The sink groups each batch by destination and routes unparseable payloads to a quarantine prefix; the warehouse then re-validates the envelope itself and routes rejects to a dedicated table, so "the facts are clean" never quietly means "some data vanished".
- Illegal state transitions — guarded SQL verified by rowcount: a closed order cannot be re-closed, an abandoned one cannot confirm. Validation on every state change, not just at intake.
- Money correctness — all money is integer paise, no floats. dbt tests assert profit = price − ingredient cost − 5% GST − driver fee in-warehouse, on every run.
- Lost customers — ~10% of placed orders abandon, and that's a first-class event tracked in the funnel and the owner's abandonment rate — never silently missing.
- Failures & retries visibility — consumer crashes, retries, and timeouts are recorded to the audit log and persisted append-only as daily JSONL. Silence is never mistaken for success.
- Bad configuration — settings fail closed: malformed or out-of-range values raise on startup instead of falling back silently. Secrets live in gitignored env files and are injected as environment variables, never embedded in the pipeline definitions.
Beyond the failure cases, the live homepage walks through the full vocabulary of streaming — topics and partitions, consumer groups, offsets and commits, delivery semantics, DLQs, change data capture, replay, retention, backpressure, event time vs processing time, compression on the wire, fan-out, stream–table duality, the medallion architecture — each one pointing at where it is happening in the running pipeline.