Designing a Cart Management System (Amazon / Flipkart / JioMart)
Difficulty: Intermediate Prerequisites:Caching and Message Queues
TL;DR
A cart management system lets users add, remove, and update items before checkout. The hard parts: persisting carts across devices, handling flash sales (1M users adding the same item), merging guest carts on login, and keeping prices/stock accurate without slowing down the add-to-cart path.
flowchart LR
USER["User Browser"]:::client
GW["API Gateway"]:::edge
CART["Cart Service"]:::service
REDIS[("Redis<br/>hot carts")]:::data
DDB[("DynamoDB<br/>durable carts")]:::data
INV["Inventory Service"]:::service
USER -->|"1. Add item to cart"| GW
GW -->|"2. Forward request"| CART
CART -->|"3. Write cart fast"| REDIS
CART -.->|"4. Async persist"| DDB
CART -->|"5. Check stock on read"| INV
classDef client fill:#4c3a5e,stroke:#818cf8,color:#e2e8f0
classDef edge fill:#1e3a5f,stroke:#60a5fa,color:#e2e8f0
classDef service fill:#1a3a2a,stroke:#4ade80,color:#e2e8f0
classDef data fill:#3b3520,stroke:#fbbf24,color:#e2e8f0
| Color | Layer |
|---|---|
| 🟠 Orange | Clients |
| 🔵 Blue | Edge |
| 🟢 Green | Services |
| 🟣 Purple | Async / Streaming |
| 🟡 Yellow | Data |
| 🩷 Pink | External |
In 3 sentences: User adds items to cart → stored in Redis for sub-ms reads and async-backed to DynamoDB for durability. On cart view, the service enriches items with live price and stock status from downstream services. At checkout, inventory is reserved with a distributed lock to prevent overselling.
1. Understanding the Problem
A shopping cart is the bridge between browsing and buying. Every e-commerce platform needs one, and despite looking simple (just a list of items), it has to handle: millions of concurrent carts during sales, real-time stock awareness, device switching (add on phone, checkout on laptop), guest-to-login transitions, flash sales where 100K users add the same item simultaneously, and graceful degradation when downstream services (inventory, pricing) are slow or down.
Think Amazon Cart, Flipkart Cart, Myntra Bag, or Zepto Cart.
1.5. Naive First Cut
flowchart LR
USER["User"]:::client
API["Cart API"]:::service
DB[("One Postgres DB<br/>carts table")]:::data
USER --> API
API --> DB
classDef client fill:#4c3a5e,stroke:#818cf8,color:#e2e8f0
classDef service fill:#1a3a2a,stroke:#4ade80,color:#e2e8f0
classDef data fill:#3b3520,stroke:#fbbf24,color:#e2e8f0
User adds item → write a row to Postgres → read it back on cart page. Works for 100 users.
How it breaks at scale:
- Flash sale: 500K add-to-cart/sec → Postgres row-level locks choke at ~50K writes/sec
- Cart page load queries Postgres every time → 10M concurrent users = 10M reads/sec on one DB
- Guest carts with no user_id are awkward to model in a relational schema
- No separation between hot (active session) and cold (abandoned 3 weeks ago) carts
- Price and stock checks embedded in the write path → add-to-cart latency spikes when inventory service is slow
- Single region DB → users across India see 50-200ms latency depending on geography
1.7. Prior Art We’re Drawing From
- Amazon Cart Service — Uses a session-based in-memory store backed by a durable persistence layer. Carts are eventually consistent; inventory is checked at checkout, not at add-time. Guest carts merge on login using a deterministic merge strategy. (Amazon Builder’s Library patterns)
- Flipkart Cart Architecture — Redis-first with MySQL backup. Cart operations are sub-10ms. During Big Billion Days, the cart service handles 1M+ ops/sec by sharding Redis across 100+ nodes. (Flipkart Engineering)
- Shopify Cart — Stores cart as a JSON document in a KV store. Cart is schema-flexible (different stores have different item attributes). Uses optimistic concurrency with version numbers to handle race conditions.
- Walmart Labs — Uses a write-behind cache pattern: write to cache immediately, async-persist to DB. If cache fails, fallback to DB reads. Cart merge uses “last-write-wins” per item with timestamps.
2. Functional Requirements
Core (Top 3)
- Add, remove, update items — user adds an item to cart, changes quantity, or removes it. Response in <100ms.
- Persistent cross-device cart — logged-in user’s cart survives app close, device switch, and browser restart. Guest carts persist via session cookie (7-day TTL).
- Real-time cart enrichment — when user views cart, each item shows current price, stock status (in stock / only 2 left / out of stock), and delivery estimate.
Below the Line
- Cart merge (guest → logged-in) on login
- Apply coupon / promo codes
- Save for later (wishlist-like behavior)
- Cart sharing (share a link with pre-filled cart)
- Cart-level validations (max items, max quantity per item, seller restrictions)
- Cart expiry policies (remove items after 30 days)
- Flash sale quantity limits (“max 1 per customer”)
3. Non-Functional Requirements
Core
| NFR | Target |
|---|---|
| Latency | Add-to-cart: P99 < 100ms. Cart page load: P99 < 200ms |
| Availability | 99.99% — cart must never be “down” (it’s pre-checkout, losing it = lost revenue) |
| Scale | 50M DAU, 10M concurrent active carts, 500K add-to-cart ops/sec at peak (flash sale) |
| Durability | Logged-in user’s cart must never be lost. Acceptable: guest carts can be lost on infra failure (they’re session-tied). |
| Consistency | Eventually consistent for cart reads (5s stale is fine). Strongly consistent for inventory reservation at checkout. |
Below the Line
- Multi-region support (cart accessible from any region)
- Cart size limits for DoS prevention (max 500 items)
- Graceful degradation when inventory/pricing services are down
Scale Estimation
- Users: 50M DAU, 10M concurrent carts during peak
- Write QPS: 500K add/update/remove per second at peak (flash sale)
- Read QPS: 2M cart-view reads/sec at peak (users refreshing cart page)
- Storage: Average cart = 5 items × 200 bytes = 1KB. 50M active carts × 1KB = 50GB (fits comfortably in Redis cluster)
- Bandwidth: ~500 Mbps at peak for cart API responses
Technology Choices
| Tier | Purpose | Stores | Access Pattern | Primary | Alternatives |
|---|---|---|---|---|---|
| Hot cart store | Active carts (session-like, fast) | userId → {items} | High-QPS reads + writes, sub-ms | Redis Cluster | Memcached, Aerospike |
| Durable cart store | Cart backup, survives Redis failure | userId → {items, metadata} | Write-behind from Redis, fallback reads | DynamoDB | Cassandra, ScyllaDB, MongoDB |
| Cart events | Analytics, abandoned cart triggers | cart_updated, item_added events | Append-only, consumed by analytics | Kafka | Kinesis, Pub/Sub |
| Inventory service | Stock levels per item | itemId → quantity_available | High-QPS reads, strong consistency for reservation | Postgres (with row locks for checkout) | DynamoDB conditional writes |
| Pricing service | Current price per item | itemId → price, discounts | Read-heavy, cacheable | Redis cache + Postgres source | Pricing microservice |
| Session store | Guest cart → session mapping | sessionId → guestCartId | Short-lived, TTL-based | Redis (with 7-day TTL) | Cookie-only (limited) |
Why Redis + DynamoDB (not just Postgres):
Cart is session-like data — high write rate, high read rate, no complex joins, flexible schema (items vary per seller). Postgres row locks collapse at 500K writes/sec. Redis gives sub-ms latency for the hot path. DynamoDB provides infinite-scale durability without managing shards.
4. Core Entities
- Cart — id, userId (or guestSessionId), items[], version, updatedAt, expiresAt
- CartItem — itemId, sellerId, quantity, priceAtAdd, addedAt
- InventoryReservation — reservationId, cartId, itemId, quantity, status (HELD/CONFIRMED/RELEASED), expiresAt
- CartEvent — eventType (ITEM_ADDED/REMOVED/QUANTITY_CHANGED/CART_MERGED), userId, itemId, timestamp, metadata
5. API / System Interface
POST /v1/cart/items
Body: { itemId, sellerId, quantity }
Response: { cartId, items[], totalItems, version }
Auth: JWT (logged-in) or Session cookie (guest)
Note: Idempotent via clientRequestId header. Does NOT check inventory (fire-and-forget add).
PATCH /v1/cart/items/{itemId}
Body: { quantity }
Response: { cartId, items[], version }
Note: quantity=0 is equivalent to DELETE
DELETE /v1/cart/items/{itemId}
Response: { cartId, items[], version }
GET /v1/cart
Response: { cartId, items[{ itemId, quantity, currentPrice, stockStatus, deliveryEstimate }], totalAmount, version }
Note: Enriched response — each item has LIVE price and stock from downstream services.
Auth: JWT or Session cookie
POST /v1/cart/merge
Body: { guestSessionId }
Response: { cartId, items[], mergeConflicts[] }
Note: Called on login. Merges guest cart into user cart.
POST /v1/cart/checkout
Response: { orderId, reservationId, paymentUrl }
Note: This is where inventory gets RESERVED (locked). Not before.
Security notes:
- userId comes from JWT, never from request body (prevent cart tampering)
- Rate limit add-to-cart: 50 requests/min per user (prevents bot abuse during flash sales)
- Guest carts are tied to session cookie; no cross-session access
6. High-Level Design
FR1: Add / Remove / Update Items
The most frequent operation. Must be blazing fast — users expect instant feedback when clicking “Add to Cart.”
New components:
- API Gateway — rate limiting, auth, routing
- Cart Service — core business logic for cart operations
- Redis Cluster — hot cart storage. Each user’s cart is a Redis Hash.
💡 Redis Hash: HSET cart:{userId} {itemId} “{qty, sellerId, priceAtAdd, addedAt}”. O(1) per field operation. - DynamoDB — durable backup. Async write-behind from Redis.
- Kafka — emits cart events for analytics and abandoned-cart workflows
flowchart LR
USER["User"]:::client
GW["API Gateway"]:::edge
CS["Cart Service"]:::service
REDIS[("Redis Cluster<br/>hot carts")]:::data
DDB[("DynamoDB<br/>durable backup")]:::data
KF["Kafka"]:::async
USER -->|"1. POST add item"| GW
GW -->|"2. Auth + rate limit"| CS
CS -->|"3. HSET cart:userId"| REDIS
CS -.->|"4. Async write-behind"| DDB
CS -->|"5. Emit item_added event"| KF
classDef client fill:#4c3a5e,stroke:#818cf8,color:#e2e8f0
classDef edge fill:#1e3a5f,stroke:#60a5fa,color:#e2e8f0
classDef service fill:#1a3a2a,stroke:#4ade80,color:#e2e8f0
classDef data fill:#3b3520,stroke:#fbbf24,color:#e2e8f0
classDef async fill:#3b1f5e,stroke:#c084fc,color:#e2e8f0
Step-by-step flow:
- User taps “Add to Cart” for itemId=SKU_123, quantity=1
- Request hits API Gateway → validates JWT → extracts userId → forwards to Cart Service
- Cart Service executes Redis command:
HSET cart:{userId} SKU_123 '{"qty":1,"seller":"seller_abc","price":499,"addedAt":"..."}' - Redis responds in <1ms → Cart Service returns 200 OK to user immediately
- Async: Cart Service publishes to Kafka topic
cart-events:{type: "ITEM_ADDED", userId, itemId, qty, timestamp} - Async: A write-behind consumer reads from Kafka and persists to DynamoDB (batched, every 5s or 100 events)
Why we do NOT check inventory at add-time:
- Adds latency (inventory service call = +20-50ms)
- Inventory is a moving target — checking at add-time and again at checkout is redundant
- During flash sales, inventory service is hammered; we don’t want cart to go down with it
- We check stock on cart VIEW (enrichment) and RESERVE at checkout
FR2: Persistent Cross-Device Cart + Guest Merge
User adds items on phone → closes app → opens laptop → cart is there. Guest browses without login → adds 3 items → logs in → those items appear in their saved cart.
New components:
- Session Service — maps guest session cookies to temporary cart IDs in Redis
- Cart Merge Logic — handles conflicts when guest cart and user cart have overlapping items
flowchart LR
GUEST["Guest User"]:::client
LOGGED["Logged-in User"]:::client
CS["Cart Service"]:::service
REDIS[("Redis<br/>both carts")]:::data
MERGE["Merge Logic"]:::service
GUEST -->|"1. Add items (session cookie)"| CS
CS -->|"2. Write to guest cart"| REDIS
LOGGED -->|"3. Login triggers merge"| CS
CS -->|"4. Read guest cart"| REDIS
CS -->|"5. Read user cart"| REDIS
MERGE -->|"6. Merge + write final"| REDIS
classDef client fill:#4c3a5e,stroke:#818cf8,color:#e2e8f0
classDef service fill:#1a3a2a,stroke:#4ade80,color:#e2e8f0
classDef data fill:#3b3520,stroke:#fbbf24,color:#e2e8f0
Step-by-step flow:
- Guest browses → session cookie assigned → cart stored at
cart:guest:{sessionId}in Redis with 7-day TTL - Guest adds items → same flow as FR1 but keyed by sessionId instead of userId
- Guest logs in → frontend calls
POST /v1/cart/merge { guestSessionId } - Cart Service reads both carts from Redis: guest cart + user’s existing cart
- Merge strategy (per item):
- Item only in guest cart → add to user cart
- Item only in user cart → keep as-is
- Item in both → take higher quantity (user intent: they wanted more)
- Write merged cart to
cart:{userId}, deletecart:guest:{sessionId} - Return merged cart to frontend with any conflicts highlighted
Cross-device persistence:
- Logged-in user’s cart lives at
cart:{userId}in Redis + backed to DynamoDB - Any device that authenticates with the same JWT sees the same cart
- No special sync needed — Redis is the single source, all devices read from it
FR3: Real-Time Cart Enrichment (Price + Stock)
When user opens the cart page, they don’t just see “iPhone × 1.” They see: current price (might have changed since they added it), stock status (“only 2 left”), delivery estimate, and a warning if price increased.
New components:
- Inventory Service — returns current stock level per item
- Pricing Service — returns current price (may differ from price-at-add-time)
- Catalog Service — returns item details (name, image, seller info)
flowchart LR
USER["User opens cart"]:::client
CS["Cart Service"]:::service
REDIS[("Redis<br/>cart items")]:::data
INV["Inventory Service"]:::service
PRICE["Pricing Service"]:::service
CAT["Catalog Service"]:::service
USER -->|"1. GET /cart"| CS
CS -->|"2. HGETALL cart:userId"| REDIS
CS -->|"3. Batch stock check"| INV
CS -->|"4. Batch price fetch"| PRICE
CS -->|"5. Batch item details"| CAT
CS -->|"6. Return enriched cart"| USER
classDef client fill:#4c3a5e,stroke:#818cf8,color:#e2e8f0
classDef service fill:#1a3a2a,stroke:#4ade80,color:#e2e8f0
classDef data fill:#3b3520,stroke:#fbbf24,color:#e2e8f0
Step-by-step flow:
- User opens cart page →
GET /v1/cart - Cart Service reads raw cart from Redis:
HGETALL cart:{userId}→ returns {SKU_123: qty 1, SKU_456: qty 2} - Cart Service calls downstream services IN PARALLEL (not sequential):
- Inventory:
POST /inventory/batch-check { itemIds: [SKU_123, SKU_456] }→ {SKU_123: 15 in stock, SKU_456: 0} - Pricing:
POST /pricing/batch { itemIds: [...] }→ {SKU_123: ₹499 (same), SKU_456: ₹1299 (was ₹999)} - Catalog:
POST /catalog/batch { itemIds: [...] }→ {names, images, seller info}
- Inventory:
- Cart Service assembles enriched response:
{ "items": [ { "itemId": "SKU_123", "qty": 1, "currentPrice": 499, "priceAtAdd": 499, "stock": "IN_STOCK", "stockQty": 15 }, { "itemId": "SKU_456", "qty": 2, "currentPrice": 1299, "priceAtAdd": 999, "stock": "OUT_OF_STOCK", "priceChanged": true } ] } - Frontend shows: “Price increased ₹999 → ₹1299” badge and “Out of Stock — Remove” option
Graceful degradation: If inventory service is slow/down → return cart without stock info (show “checking availability…” on frontend). Cart should NEVER fail to load because a downstream enrichment service is down.
7. Potential Deep Dives
Deep Dive 1: Flash Sale — 500K Users Add the Same Item Simultaneously
Problem: Big Billion Days. iPhone listed at ₹39,999. 500K users click “Add to Cart” in the first 10 seconds. Only 1000 units available.
Bad: Check inventory on every add-to-cart. Inventory service gets 500K reads/sec for one item → hot key → collapses. Users see “item unavailable” errors.
Good: Don’t check inventory at add-time. Let everyone add to cart freely. Check stock only on cart page view and at checkout. Show “limited stock” badge. First 1000 to checkout win.
Great: Same as Good, but add a soft limit at the cart level. After the first 2000 add-to-carts for a flash-sale item, start showing “selling fast — checkout now” urgency messaging. Use Redis INCR on a counter flash:{itemId}:carts to track how many carts contain this item. This doesn’t block anyone but creates urgency and reduces phantom demand.
At checkout: use DynamoDB conditional write (or Postgres SELECT FOR UPDATE) to atomically decrement inventory. If inventory hits 0, reject checkout for subsequent users. Their cart still has the item, but they see “sold out” when they try to pay.
Key insight: Adding to cart is NOT a commitment to buy. Don’t waste inventory-service capacity on something that has a 70% abandonment rate.
Deep Dive 2: Write-Behind Pattern — Redis + DynamoDB Consistency
Problem: We write to Redis first (fast) and async-persist to DynamoDB (durable). What if Redis crashes after the write but before the DynamoDB persist? User’s last few cart changes are lost.
Bad: Write to DynamoDB synchronously on every cart operation. Adds 5-10ms latency to every add/remove. At 500K ops/sec, DynamoDB costs explode (on-demand pricing).
Good: Write-behind with Kafka as buffer. Cart Service writes to Redis AND publishes to Kafka. A consumer drains Kafka into DynamoDB in batches. If Redis crashes, Kafka still has the events → replay into DynamoDB → hydrate back to Redis from DynamoDB.
Great: Same as Good + version vector on the cart. Each cart has a monotonically increasing version field. Redis cart has version 47. DynamoDB has version 45 (slightly behind). On Redis failure:
- Cart Service falls back to reading DynamoDB (version 45)
- When Redis recovers, hydrate from DynamoDB
- If user made changes during the fallback window, those are already in DynamoDB (the consumer was writing there via Kafka)
- No data loss. At most 2-3 seconds of stale reads during the Redis→DynamoDB switchover.
Deep Dive 3: Cart Merge Conflicts
Problem: Guest has: {iPhone: qty 2, AirPods: qty 1}. Logged-in cart has: {iPhone: qty 1, MacBook: qty 1}. User logs in. What does the merged cart look like?
Bad: Overwrite user cart with guest cart (lose MacBook). Or overwrite guest with user (lose AirPods).
Good: Union of both carts. For conflicts (same item in both), take max quantity. Result: {iPhone: 2, AirPods: 1, MacBook: 1}.
Great: Same as Good but with user transparency. Show a toast: “We added 1 item from your browsing session” or a merge summary. For quantity conflicts, default to max but let user adjust on the cart page. Log merge events to Kafka for analytics (how many users hit merge conflicts? is it causing confusion?).
Edge case: guest cart has item that’s now out of stock. Still merge it in — show “out of stock” badge. Don’t silently drop items.
Deep Dive 4: Cart Abandonment Detection + Recovery
Problem: 70% of carts are abandoned. Can we nudge users back?
Bad: Poll the DB every hour for “carts not checked out in 24h.” At 50M carts, this is expensive and wasteful.
Good: Event-driven. Kafka consumer tracks item_added events. If no checkout_initiated event arrives within 24 hours for that userId, emit an abandoned_cart event. Notification service sends push/email: “You left items in your cart.”
Great: Tiered nudges:
- 2 hours: push notification (“Your cart is waiting”)
- 24 hours: email with cart items + “prices may change” urgency
- 72 hours: email with a 5% discount code
- 7 days: remove from “active” tier, compress cart to cold storage
Implementation: Use a delayed Kafka consumer (or Redis sorted set with fire-time) to schedule nudge events at each tier. Cancel all pending nudges if user checks out.
Deep Dive 5: Inventory Reservation at Checkout
Problem: User has 2 iPhones in cart. They click “Proceed to Checkout.” Between clicking and completing payment (2-5 minutes), another user could buy the last iPhone. How do we prevent overselling?
Bad: Decrement inventory on add-to-cart. 500K carts hold 500K “reservations” but 70% abandon. Real customers can’t buy because inventory is “held” by abandoned carts.
Good: Reserve inventory only at checkout initiation (when user clicks “Pay”). Use a TTL-based hold (10 minutes). If payment isn’t completed, hold releases automatically.
Great: Conditional write with fencing:
DynamoDB:
UpdateItem(itemId=SKU_123)
SET available = available - 2
CONDITION: available >= 2
If condition fails (not enough stock), return “only X left, reduce quantity.” The conditional write is atomic — no two users can over-decrement.
TTL-based hold: write a reservation record {reservationId, itemId, qty, expiresAt: now+10min}. A sweeper restores inventory for expired reservations. Same pattern as BookMyShow seat locks.
8. Final Architecture
flowchart TD
subgraph Clients
WEB["Web Browser"]:::client
APP["Mobile App"]:::client
end
subgraph Edge
GW["API Gateway<br/>rate limit + auth"]:::edge
end
subgraph Services
CS["Cart Service"]:::service
INV["Inventory Service"]:::service
PRICE["Pricing Service"]:::service
CAT["Catalog Service"]:::service
MERGE["Merge Handler"]:::service
NOTIF["Notification Service"]:::service
end
subgraph Data
REDIS[("Redis Cluster<br/>hot carts")]:::data
DDB[("DynamoDB<br/>durable carts")]:::data
PG[("Postgres<br/>inventory")]:::data
end
subgraph Async
KF["Kafka"]:::async
end
WEB --> GW
APP --> GW
GW --> CS
CS --> REDIS
CS -.-> KF
KF -.-> DDB
KF -.-> NOTIF
CS --> INV
CS --> PRICE
CS --> CAT
CS --> MERGE
INV --> PG
MERGE --> REDIS
classDef client fill:#4c3a5e,stroke:#818cf8,color:#e2e8f0
classDef edge fill:#1e3a5f,stroke:#60a5fa,color:#e2e8f0
classDef service fill:#1a3a2a,stroke:#4ade80,color:#e2e8f0
classDef data fill:#3b3520,stroke:#fbbf24,color:#e2e8f0
classDef async fill:#3b1f5e,stroke:#c084fc,color:#e2e8f0
How it works end-to-end:
- User adds item → API Gateway authenticates and rate-limits → Cart Service writes to Redis (sub-ms)
- Cart event published to Kafka → consumed by DynamoDB writer (durability) and analytics pipeline
- User views cart → Cart Service reads from Redis + enriches in parallel from Inventory, Pricing, and Catalog services
- User logs in → Merge Handler combines guest cart with user cart, writes merged result to Redis
- User proceeds to checkout → Inventory Service reserves stock with conditional write (DynamoDB or Postgres row lock)
- If user abandons → Kafka-based timer fires nudge notifications at 2h, 24h, 72h intervals
- If Redis fails → Cart Service falls back to DynamoDB reads (slightly slower but no data loss)
Metrics to Monitor
Business Metrics
| Metric | What it tells you |
|---|---|
| Cart abandonment rate | % of carts that never reach checkout |
| Cart-to-checkout conversion | Funnel health |
| Avg items per cart | Engagement signal |
| Time: add-to-cart → checkout | Are users hesitating? |
| Price-change impact | How many users see “price increased” and remove item? |
Technical Metrics
| Metric | Alert threshold |
|---|---|
| Add-to-cart P99 latency | >100ms |
| Cart read P99 latency | >200ms |
| Redis hit rate | <95% |
| Redis → DynamoDB sync lag | >5 seconds |
| Inventory service P99 | >50ms |
| Cart merge error rate | >0.5% |
| Flash sale counter (carts holding item) | Track for demand forecasting |
What’s Expected at Each Level
Mid-level
Design a basic cart with add/remove/get operations using Redis. Recognize the need for persistence beyond Redis. Propose DynamoDB or Postgres as backup. Understand why inventory shouldn’t be checked at add-time.
Senior
Propose the write-behind pattern (Redis + Kafka + DynamoDB). Discuss cart merge strategies. Explain flash sale handling without blocking the add-to-cart path. Design the enrichment layer with parallel calls and graceful degradation. Discuss the checkout reservation with conditional writes.
Staff+
Discuss multi-region cart consistency, version vectors for conflict resolution, cart-level rate limiting for bot prevention during flash sales, and the abandoned-cart recovery pipeline with tiered nudges. Quantify costs (Redis cluster sizing, DynamoDB on-demand pricing). Propose observability: which metrics distinguish a healthy cart system from a degraded one.
Key Takeaways
- Redis for speed, DynamoDB for durability — write-behind pattern gives you both
- Don’t check inventory at add-time — it adds latency and wastes capacity. Check at view-time (soft) and reserve at checkout (hard).
- Cart merge on login — union of items, max(quantity) for conflicts, transparent to user
- Flash sale: let everyone add, gate at checkout — 70% will abandon anyway
- Enrich in parallel, degrade gracefully — if pricing service is down, show stale price with a “checking…” badge, don’t fail the cart load
Related Designs
- BookMyShow (Ticket Booking) — same reservation-with-TTL pattern at checkout
- Digital Wallet (PhonePe) — payment orchestration after cart
- Rate Limiter — protecting cart API during flash sales
Related Concepts
- Caching → — Redis as hot-path cache for cart data
- Message Queues → — Kafka for write-behind, events, and abandoned-cart triggers
- Database Replication → — Redis Cluster replication for HA
Discussion
Newest first