•CASE STUDY

E-commerce Shopping Website (and Fixing Cart Latency)

6 min read·1,002 words·Intermediate

Asked at

2 candidate reports between Feb 2026 and Jun 2026

How to use this case study

SDE-2 / Mid

Explain the main services (catalog, search, cart, checkout, orders, payments, inventory) and the checkout flow

SDE-3 / Senior

  • Go deeper on caching the cart and product data
  • Reserving inventory at checkout
  • "notify me when back in stock"

Staff / Principal

  • Discuss profiling an existing slow system before changing it
  • Peak events (sales)
  • Consistency between inventory
  • Orders and payments

Problem RestatementProblem

JPMorgan asked two versions:

  1. Design a scalable e-commerce website: browse products, search, cart, checkout, orders and payment.
  2. Improve an existing system: the shopping cart (web and mobile) already works, but it's slow, and product wants "notify me when this item is back in stock". You should improve the current design, not rewrite it.

RequirementsRequirements

  • Browse and search products, product pages.
  • Add to cart, view the cart, update quantities.
  • Checkout: address, payment, order creation, inventory update.
  • Order history and status.
  • Back-in-stock alerts.
  • Handle big sale days (5–10x traffic).

Architecture (greenfield)Architecture

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
    U["Web / Mobile"] --> CDN["CDN - static, product pages"]
    U --> GW["API Gateway"]
    GW --> CAT["Catalog"]
    GW --> SRCH["Search"]
    GW --> CART["Cart Service"]
    GW --> CHK["Checkout / Orders"]
    CART --> RC[("Redis - carts")]
    CART --> CDB[("Cart DB - durable")]
    CHK --> INV[("Inventory")]
    CHK --> PAY["Payments"]
    CHK --> ODB[("Orders DB")]
    CHK --> K[("Events")]
    K --> NOTIF["Notifications"]
    INV --> K
  • Catalog + Search: read-heavy. Product pages are cached at the CDN, and search uses a search index.
  • Cart: fast reads and writes in Redis, persisted to a durable DB (so carts survive restarts and work across devices).
  • Checkout/Orders: validates price and stock, reserves inventory, takes payment, creates the order (idempotently).
  • Events: order placed, stock changed, feeding notifications and analytics.

2.1 Checkout in short

  1. Re-validate the cart (prices, availability).
  2. Reserve inventory atomically (available >= qty → decrement and hold for 10 minutes).
  3. Authorize payment → create the order → confirm the reservation. If payment fails, release the hold.
  4. An idempotency key on "Place order" prevents double orders.

Version 2: Improving an Existing Slow Cart

Step 1: Measure first. Don't guess. Add tracing to the cart endpoints and find where time goes. Typical findings:
  • The cart page calls many services one by one (product details, price, stock, promotions) for each item → N sequential calls. Fix: batch calls (getProducts(ids)), make them in parallel, and cache product data.
  • Every read hits the DB with joins. Fix: keep the cart as one document in Redis (write-through to the DB), and invalidate or update it on each change.
  • Price and stock computed live on every view. Fix: cache prices briefly, and show stock as "In stock / Few left" from a cached value, with exact checks only at checkout.
  • Chatty mobile clients re-fetching the whole cart after every tap. Fix: return the updated cart in the mutation response, use ETags, and avoid extra round trips.
  • Large payloads: send only what the cart UI needs.

Step 2: Roll out safely: behind a feature flag, compare latency (p50/p99) before and after, and keep the old path for rollback.

Deep Dive — "Notify me when it's back in stock"Deep dive

Fifty thousand people subscribe to a sold-out console. Twenty units arrive. What the system does in the next ten seconds decides whether this feature helps customers or just creates a riot.

Weak

Poll inventory for every subscriber

A job walks the subscription list and checks stock for each one.

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
  SUB["500,000 subscriptions"] --> LOOP["Check stock for each, every few minutes"]
  LOOP --> DB[("Inventory service")]
  DB --> LOAD["Hundreds of thousands of reads for almost always the same answer"]
  LOOP --> LAG["Restock at 10:00:02, noticed at 10:04 - already sold out"]

Nearly every check confirms nothing changed, and the one time something does change, the answer is minutes stale. The customer gets an email for an item that sold out before they opened it — worse than no email at all.

Good

Publish a restock event

Inventory emits stock_available(sku) when the count crosses zero, and a consumer notifies everyone subscribed to that SKU.

No polling and no lag; notifications go out within a second of the restock. And now the real problem is visible: fifty thousand notifications land simultaneously, fifty thousand people tap at once, and twenty of them get a console. The other 49,980 experience a checkout that fails under load — and the site gets a traffic spike shaped exactly like a DDoS, aimed at the hottest product page.

Best

Notify in waves, sized to the stock

Treat the notification as an invitation, and hand out only as many as there is stock to justify:

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
  RS["Restock - 20 units"] --> W1["Wave 1: notify the first 200 subscribers, FIFO"]
  W1 --> HOLD["Each gets a short reservation window"]
  HOLD --> BUY{"Units left after the window?"}
  BUY -->|"yes"| W2["Wave 2: next 200"]
  BUY -->|"no"| STOP["Stop - remaining subscribers keep their subscription"]
  W2 --> BUY
  • Wave size follows the stock, not the subscriber count. Twenty units justify inviting a few hundred people, not fifty thousand.
  • Order is the subscription order. People who subscribed first get invited first, which is both fairer and easier to explain than a race.
  • A short reservation window per invited customer turns the race into a queue. Unclaimed reservations expire and free the unit for the next wave.
  • Un-notified subscribers stay subscribed. Nobody loses their place because the batch ran out.

Two smaller details that matter: deduplicate per user per SKU with a cool-down, so a flapping stock count does not send six emails; and make the notification link carry the reservation, so tapping it goes straight to a checkout that will actually succeed.

Handling Sale Days

  • Pre-scale stateless services, warm the caches, and serve static and product pages from the CDN.
  • Put a queue or waiting room in front of checkout for extreme spikes.
  • Protect inventory with atomic decrements, and use a separate hot-item stock counter (e.g., Redis) for flash-sale items, reconciled with the DB.

Trade-offs & AlternativesTrade-offs

DecisionChoiceWhyAlternative
Cart storageRedis + durable DBFast and safeDB only: slow; cache only: carts lost
Stock on cart pageCached approximate statusFastExact live stock: slow, not needed until checkout
CheckoutReserve → pay → confirm, idempotentNo oversell, no double ordersDecrement after payment: oversell risk
Back in stockEvent on 0→positive, batched sendsEfficient, no spamPoll stock for every subscriber: wasteful

Wrap-UpWrap-up

Split the site into catalog and search (CDN and cache heavy), cart (Redis + durable DB), and checkout (re-validate, reserve stock atomically, pay, create the order idempotently), connected by events. To fix a slow existing cart, measure with tracing, then batch and parallelize service calls, cache the cart and product data, and trim payloads, rolling out behind a flag. Implement back-in-stock alerts as subscriptions triggered by a stock 0→positive event, sent in batches.

More Case Studies

Frequently Asked Questions

What is the E-commerce Shopping Website (and Fixing Cart Latency) system design question?

E-commerce Shopping Website (and Fixing Cart Latency) is a system design interview question asked at FAANG companies. It covers e-commerce, caching, databases, distributed systems and tests your ability to design scalable, production-ready systems. InterviewSkool's breakdown walks you through requirements, API design, architecture, and trade-offs.

Which companies ask the E-commerce Shopping Website (and Fixing Cart Latency) question?

JPMorgan have reportedly asked variations of this question in system design interviews. The exact wording may differ, but the core design challenges remain the same.

How should I prepare for the E-commerce Shopping Website (and Fixing Cart Latency) interview question?

Start with the problem statement and scale estimates, then design the high-level architecture. Focus on the core components, data model, and API design. InterviewSkool's breakdown covers the full solution with mermaid diagrams and trade-off analysis to help you prep efficiently.

What level is the E-commerce Shopping Website (and Fixing Cart Latency) question?

This question is suitable for SDE-2, SDE-3, and Staff engineer interviews. The level guidance on this page provides specific tips for each level — SDE-2 candidates should focus on core architecture, while Staff engineers should discuss trade-offs, monitoring, and incremental rollouts.

Practice with a Mock Interview

Apply what you learned in a live system design mock interview with InterviewSkool's AI interviewer.

Start System Design Interview →