DBRaven
Architecture Decision RecordProposed

Use E-Commerce Order Platform as the Foundational Architecture Pattern

Deterministic ADR derived from topology, simulation, and advisor intelligence for E-Commerce Order Platform. Traceable to YAML knowledge entities.

Context

E-commerce platforms concentrate two fundamentally different operational problems in a single system: the read-heavy product discovery path (millions of product page views with low write rate) and the write-contention checkout path (flash sale events driving thousands of concurrent buyers at the same inventory rows simultaneously). A payment provider timeout during checkout must not leave inventory reserved and payment charged: the compensation path must be as reliable as the forward path. Order status updates must fan out to the customer app, warehouse system, and shipping provider without coupling checkout latency to downstream notification delivery. Return and refund flows invert the entire saga, requiring the same compensating transaction reliability in the reverse direction. Primary operational risks include: Saga compensation cascade from payment provider timeout: when the payment provider returns a timeout (not a clear success or failure), the saga must decide whether to treat the ambiguous response as a success or failure. Treating it as failure and releasing inventory after a charge that silently succeeded produces a double-debit when the customer retries. The idempotency key sent to the payment provider is the only defense against this, and it must be persisted before the payment call, not after.; Flash sale inventory row hot lock contention: a flash sale with 10,000 concurrent buyers purchasing the same SKU concentrates all write traffic on a single inventory row. PostgreSQL row-level locks serialize all concurrent UPDATE inventory_items SET reserved = reserved + 1 WHERE sku_id = X operations. At this concurrency level, effective checkout throughput for the hot SKU drops to single-digit transactions per second regardless of hardware scaling.; RabbitMQ fulfillment queue backlog on warehouse system outage: when the warehouse fulfillment system goes offline, RabbitMQ accumulates fulfillment_created messages without a consumer draining them. When the system recovers, it processes the full backlog simultaneously, potentially overwhelming the warehouse API with a burst of orders that should have been metered. Without per-consumer rate limiting and dead-letter configuration, the recovery makes the incident worse..

Decision

We will adopt the **E-Commerce Order Platform** architecture pattern. This is a high-complexity architecture appropriate for teams at experienced backend team level or above. The advisor rates this pattern as 'advanced' operational maturity.

Rationale

An e-commerce order lifecycle platform handling cart, checkout, payment, fulfillment, and returns across a mixed read/write workload where product discovery is read-heavy, checkout is write-transactional, and fulfillment is event-driven. The saga pattern orchestrates multi-step checkout: reserve inventory → charge payment → confirm order → notify fulfillment. PostgreSQL owns order records and inventory with row-level locking; Redis holds session state and cart contents with sub-millisecond access; RabbitMQ delivers fulfillment notifications with dead-letter handling; Elasticsearch serves product search and order history with faceted navigation. CQRS separates the write command path from the read model: the order read model is denormalized for fast order history queries without joining across domain tables. Core technology stack: postgresql, redis, rabbitmq, elasticsearch, kafka.

Accepted Tradeoffs

  • Saga pattern provides checkout resilience without distributed two-phase commit, but every compensation path must be designed, implemented, and tested to the same quality bar as the forward path: in practice, compensation logic is under-tested and fails exactly when needed most
  • Elasticsearch product search serves faceted navigation with p99 < 100ms across millions of products, but is eventually consistent with PostgreSQL catalog data via CDC: price changes and inventory availability updates have a propagation window that must be handled in the search UX
  • Redis cart state provides sub-millisecond cart reads and writes with no database round-trips, but cart data is lost if Redis is not persisted with AOF or RDB snapshots: a Redis node failure without durability configuration causes cart abandonment for all active sessions
  • CQRS separates write throughput from read query complexity, but the order read model must be kept synchronized with the command model: a projection bug causes order history to diverge silently, which is only detected by a customer reporting a wrong order status
  • Kafka outbox pattern guarantees no event loss for fulfillment and notification downstream consumers, but adds a write per order state transition to the outbox table: under high order volume this doubles the effective write amplification on the orders table region

Risks

highLock Contention

Concurrent writers to the same rows serialize behind each other's row locks, so latency is set not by the work a transaction does but by how long it waits for the writers ahead of it. On a hot row the queue depth, and therefore the tail latency, grows with concurrency while throughput flattens. Blocked writers hold connections open, so a single contended row can drain the connection pool as a secondary failure.

highCascading Failure

A failure or degradation in one service causes increased load, held resources, or error propagation in its callers, which in turn degrade their callers, until the failure front propagates through the entire dependency graph and brings down services with no direct dependency on the original failure point.

highThundering Herd (Cache Stampede)

When a popular cached key expires or a service recovers from downtime, all requests that were waiting or arrive simultaneously miss the cache and hit the origin database concurrently, producing a request spike that can overwhelm the database within seconds.

highQueue Backlog Accumulation

Message queue or event stream consumer processing rate falls below producer write rate, causing consumer lag to grow unboundedly: eventually leading to increased end-to-end latency, producer backpressure, data expiry, or queue resource exhaustion.

highDeadlock

Two or more transactions each hold a lock the other needs, forming a cycle in the lock wait-for graph that no participant can escape on its own. The database breaks the cycle by aborting one transaction, surfacing a serialization-class error the application must catch and retry. Under sustained contention, naive immediate retries re-enter the same cycle and amplify it into a retry storm.

Alternatives Considered

AI Retrieval-Augmented Generation Platform shares core technology (kafka, postgresql) with the chosen architecture but applies different structural patterns; E-Commerce Order Platform is a better fit for the identified workload profile.

Analytics Data Platform shares core technology (kafka, postgresql) with the chosen architecture but applies different structural patterns; E-Commerce Order Platform is a better fit for the identified workload profile.

API Gateway Platform shares core technology (kafka, postgresql) with the chosen architecture but applies different structural patterns; E-Commerce Order Platform is a better fit for the identified workload profile.

Audit and Compliance Platform shares core technology (kafka, postgresql) with the chosen architecture but applies different structural patterns; E-Commerce Order Platform is a better fit for the identified workload profile.

Scaling Thresholds

Signals indicating the architecture is approaching its scaling limits:

Tier 1: Flash Sale Inventory Contention

Signal: PostgreSQL pg_locks showing high RowExclusiveLock contention on inventory_items for specific sku_ids; checkout p99 > 2s for contended SKUs; deadlock errors appearing in application logs during sale events; effective checkout throughput for hot SKUs well below per-request checkout latency would predict

Evolution: Introduce a per-SKU checkout serialization queue at the application layer : all concurrent checkout requests for the same SKU are queued and processed serially, converting lock contention into queue latency. Alternatively, use PostgreSQL advisory locks with non-blocking trylock: requests that cannot acquire the lock immediately return a "sold out" response rather than queuing. For very high flash sale volumes, pre-allocate inventory slots (reserve N slots per sale event, each slot is a row with one reservation) to spread lock contention across N rows instead of one.

Tier 2: Payment Provider Latency Amplifying Checkout Latency

Signal: Checkout p99 tracking payment provider p99 almost linearly; connection pool utilization on the payment service rising during payment provider slowdowns; circuit breaker trip events appearing in payment service metrics; saga timeout events correlated with payment provider latency spikes

Evolution: Decouple the payment step from the synchronous checkout saga: reserve inventory and create the order record synchronously, then process payment asynchronously. The customer receives an "order confirmed, payment processing" state immediately; the payment step runs as a separate saga step triggered by an event. This reduces the synchronous checkout latency to the inventory reservation time, not the payment provider round-trip time.

Tier 3: Elasticsearch Index Staleness During High Catalog Update Rate

Signal: CDC consumer lag on the Elasticsearch indexing consumer > 30s during catalog bulk updates; customer complaints about price changes not visible in search; search result prices diverging from checkout prices by more than the acceptable window; Kibana showing indexing throughput below the catalog update rate

Evolution: Tune Elasticsearch bulk indexing batch size and flush interval to increase indexing throughput; add indexing consumer replicas with partition-based assignment to parallelize indexing across catalog segment partitions. Introduce a "price_as_of" timestamp in search results displayed to customers : this converts an invisible consistency gap into an explicit, auditable staleness signal that satisfies most checkout price dispute scenarios.

Tier 4: Domain Decomposition Pressure from Shared PostgreSQL

Signal: PostgreSQL primary CPU > 75% sustained under combined checkout + catalog write + order history read workloads; domain team schema migrations blocking each other; connection pool exhausted by combined connection demand from checkout, catalog, and order history services sharing the same pool

Evolution: Decompose into catalog database (product data, inventory), orders database (orders, payments, returns), and user database (sessions, preferences) using database-per-service pattern. Each domain gets its own connection pool and its own schema migration lifecycle. Cross-domain data access moves to events or API calls: direct cross-database JOINs are eliminated.

Migration Path

1

Synchronous checkout with direct database payment insert and synchronous payment API callSaga-orchestrated checkout with outbox-based fulfillment events

Payment provider timeout causing full checkout rollback and user-facing error; fulfillment system outage causing checkout to fail synchronously rather than queue the fulfillment work; inability to replay failed fulfillment notifications after downstream system recovery

2

PostgreSQL full-text search for product discoveryElasticsearch for product search with CDC-based catalog indexing

Product search p99 > 1s; faceted navigation (category + price range + brand + availability) requiring full-table scans in PostgreSQL; ranking by popularity or relevance score not achievable in PostgreSQL without full-table aggregation

3

Monolithic order processing with inline notification deliveryRabbitMQ-based notification fanout with dead-letter handling

Email/push notification provider timeouts causing checkout latency to increase proportionally; notification delivery failures causing order confirmation to appear failed even when the order was created successfully; inability to replay failed notification deliveries after provider recovery

Operational Requirements

  • Minimum team maturity: Experienced Backend Team: This scenario has high operational complexity. It is recommended for Experienced Backend Team teams or higher.
  • Runbooks and alerting for high-severity risks: 5 high-severity risks identified. Each requires a documented runbook, alerting threshold, and on-call response procedure before running in production.
  • Event stream operations expertise: This architecture includes event stream infrastructure (Kafka, Kinesis, or similar). Operations requires consumer group management, partition assignment, dead-letter handling, and lag monitoring.
  • Cache sizing and eviction policy configuration: Redis or equivalent cache requires correct maxmemory configuration, eviction policy selection (allkeys-lru is common), and cold-start warming strategy after restarts.
DBRaven knowledge base: deterministic, YAML-backed, traceable

Export