Skip to content

ADR-0007: CQRS for the Inventory Domain

Status: Accepted Date: 2026-01-25


Context

Inventory has a heavily asymmetric read/write ratio. Stock level queries (from product pages, search results, cart validation) run at ~5,000 RPS. Stock reservations (from order placement) run at ~200 RPS. The read path requires sub-10ms latency; the write path requires strong consistency (no oversell, INV-INV-001).

Serving both from PostgreSQL is possible at current scale but creates two problems: 1. Read queries compete with write transactions for I/O and connection pool slots. 2. The p99 read latency of 100ms (in contracts/slas/inventory-sla.yaml) is difficult to meet under write load on PostgreSQL.

Decision

CQRS for the Inventory domain. The write model is PostgreSQL — all reservations and releases go through it with row-level locking. The read model is a Redis hash maintained by a Kafka consumer. When a StockReserved or StockReleased event is published, the consumer updates the Redis projection.

Read queries are served exclusively from Redis. No read path touches PostgreSQL.

Rationale

Redis GET is sub-1ms at p99 under normal load, well within the 100ms read SLA. The Kafka consumer projection lag introduces eventual consistency (target: < 100ms lag per contracts/slas/inventory-sla.yaml). This is acceptable because stock level queries are informational — the definitive reservation decision is made against PostgreSQL.

Consequences

Positive: Read latency well within SLA; read and write paths scale independently; PostgreSQL protected from read load spikes. Negative: Eventual consistency on reads; Redis is an additional dependency; projection must be rebuilt from Kafka topic on Redis failure.