Guide

Here is the full design of an e-commerce order system built on an event log. The requirements are demanding. The site handles 2,000 orders a minute at peak. When an order is placed, it must appear in the customer's history straight away. Support agents must be able to search it within seconds. Hourly sales dashboards must include it. And it must trigger a confirmation email.

Write side

The Orders service owns an orders table in Postgres. PlaceOrder validates the cart, then writes the order and an OrderPlaced row to the outbox table, in one transaction. It returns the new order to the client, which shows it immediately. That is read-your-writes from the write model.

Event log

Debezium reads the outbox through the WAL and publishes to a Kafka topic, orders.events. It has 12 partitions, keyed by order ID. The volume is modest:

2,000 orders/min ÷ 60 ≈ 33 OrderPlaced/s
plus status changes (paid, shipped, delivered) ≈ 4 events per order → ~130 events/s
at ~2 KB per event (state transfer) ≈ 260 KB/s ≈ 23 GB/day
retain 7 days on Kafka ≈ 160 GB before replication; × 3 replicas ≈ 480 GB

That is a small Kafka cluster's workload. Long-term history goes to object storage for replay.

Consumers

Each consumer has its own group, so it progresses independently.

  • Search projection. Upserts each order's latest state into Elasticsearch, keyed by order ID. It is guarded by the event's version, so an older event that arrives late can't overwrite a newer one. Lag is typically under a second.
  • Analytics. Lands events in the warehouse every few minutes. Dashboards aggregate from there.
  • Email service. Consumes OrderPlaced, deduplicates on event ID in its own table, and passes email:{eventId} as an idempotency key to the email provider.

Failure scenarios

  • Search is down for 20 minutes. The search consumer stops, and its lag grows to about 40,000 orders. Checkout is unaffected. The consumer catches up when search returns.
  • A bug corrupts the search index. Delete the index and replay from the earliest retained offset. That is a rebuild, not a restore.
  • A new team wants a "frequently bought together" feature next year. It starts a new consumer group from the beginning of the archived history.

These three properties are what the event log buys you: isolation, replayability and extensibility. They are the reason to pay for its complexity.

Common mistakes

  • Making checkout wait on consumers. Checkout should finish on the write side, and consumers should catch up.
  • Writing the search index without a version guard. A late, older event can then overwrite newer data.
  • No retention plan. Replay is only possible for the history you kept.

Check yourself

1. Search is down for 20 minutes. What happens to checkout? Nothing. Checkout doesn't wait for the search consumer, which catches up when search returns.

2. Why guard the search upsert with the event version? Without a guard, an older event that arrives late can overwrite the newer order state.

Key takeaways

  • The write side commits the order and its event together, through the outbox.
  • A single durable log feeds search, analytics and email, each through its own consumer group.
  • Each consumer can fall behind or be rebuilt without touching checkout.
  • Guard projections with versions, and keep enough retention for the replays you plan to do.

Further learning

Next, see how partition counts and throughput are sized in event streaming and Kafka.