E-commerce Checkout & Order Service
Problem statement
Handle cart, inventory reservation, payment, tax/shipping, order creation, and failure compensation under concurrency (flash sales).
How it works
- User checks out → validate cart + price snapshot.
- Reserve inventory (soft hold) with TTL.
- Charge payment; on success confirm inventory and create order; on failure release hold.
- Emit OrderPlaced for warehouse / email / analytics.
Analogy: Theater tickets: the box office holds your seats for 10 minutes while you pay; if payment fails, seats return to the pool.
High-level design
Rendering diagram…
Components explained — this design
| Component | What it is | Why we use it here |
|---|---|---|
| Checkout API | Orchestrates cart validation → reserve → pay → order. | Facade over multiple domains; exposes single idempotent checkout operation to clients. |
| Cart service (Redis) | Fast ephemeral cart state or session pointer. | Low latency reads while browsing; TTL aligns with session abandonment. |
| Inventory service | Authoritative or fast-reserve stock for SKUs. | Prevents oversell; may combine Redis pre-decrement with SQL truth reconciliation. |
| Payment (Stripe) | PSP handles cards, 3DS, tokens (PCI scope reduction). | PCI SAQ-A friendly when card data never touches your disks. |
| Order service | Persists immutable OrderPlaced facts. | Legal + fulfillment source of truth after money captured. |
| Kafka | Emits OrderPlaced for warehouse, search, analytics. | Downstream systems stay loosely coupled; replay rebuilds projections after bugs. |
Shared definitions: 00-glossary-common-services.md
Low-level design
Inventory reservation
- Optimistic:
UPDATE stock SET qty=qty-? WHERE sku=? AND qty>=?— may fail under race; retry UX. - Better for flash sales: Redis DECR on
stock:{sku}with Lua script atomic check-and-decrement + TTL keyhold:{order_id}for auto-release. - Authoritative stock still reconciled from PostgreSQL periodically.
Idempotency
- Stripe Idempotency-Key per checkout attempt.
- Order service:
client_order_tokenunique constraint → duplicate POST returns same order.
Saga / compensation
Rendering diagram…
- Choreography: each service listens to events (loose coupling).
- Orchestration: Temporal.io / AWS Step Functions for explicit compensation steps.
Tax & shipping
- TaxJar / Vertex APIs; cache by
(zip, cart_hash)short TTL. - Carrier APIs (UPS) for live rates; fallback table if timeout.
Fraud
- Stripe Radar + custom rules; velocity checks on IP/email/device fingerprint (Sift).
Tricky parts
| Problem | Solution |
|---|---|
| Double spend | Idempotency + single writer for order row |
| Oversell | Redis pre-decrement + async reconciliation job |
| Cart price drift | Price snapshot JSON on checkout start |
Caveats
- PCI: card data only on Stripe Elements; your servers see payment_intent_id only.
- International: currency, VAT invoices, export controls — separate compliance module.
Azure notes
- Azure Service Bus for messaging; Logic Apps for simple saga; Dynamics 365 integration for ERP.