Skip to content

Design prompt: product page and checkout

Cache by freshness, price at the server, and keep one payment attempt and its key on the order, where every resend finds it.

Predict first

Before you read: predict

ExamHall's registration page disables Pay on the first click and sends POST /registrations/R-17/pay with no idempotency key. Its fetch wrapper re-sends a request once if no reply arrives within 15 s. When the bank's 3-D Secure page sends the candidate back to /registrations/R-17/return, that page sends the same pay request to learn the result. One candidate's log on a slow train: a double click on Pay; no reply within 15 s, so the wrapper re-sends; the bank's page; back on the return page; a reload of it. Every request reached the server, and the provider charges the card for each pay request it accepts.

How many charges does the provider record for this candidate?

Pick one

The 30-second version

Split the product page by freshness: a cached shell, a stock island with its own short edge lifetime, the price confirmed by the server at pay time. The checkout is one attempt per order, its key kept on the order. A disabled button stops a click, not a retry, a reload or the bank's return.

Cache by freshness, price at the server, and keep one payment attempt and its key on the order, where every resend finds it.

How it works

Step 1 of 11

Numbers first. Peak views a second, products, edges, how fast stock moves, how stale a number may be, payments a minute.

Analogy: A bowling alley's front desk

At the desk In the design
the price board above the desk, repainted when a price changes the shell, cached until edited (step 3)
a screen of lanes free tonight, updated every few minutes, read by the whole queue a shared stock island (steps 4–5)
the till rings tonight's price, and the clerk reads it out before the card goes in the server's total on the Pay screen (step 6)
a numbered booking sheet on the desk's clipboard; the customer keeps the receipt the attempt's key on the order (step 7)
holding back a hand does not stop a friend coming in later to pay with the receipt a disabled button (step 8)
the customer steps out to phone the bank and comes back; the clerk looks up the sheet the 3-D Secure return (steps 9–10)

In real terms: a shop serves many readers cheap, slightly old numbers, and charges each order once.

Breaks down when: a clerk recognises a face; a server knows a returning buyer only by the order id it is sent.

Contrasting case: a free newsletter sign-up: a repeat is harmless, so no key.

Examples, run for real

4.1 ExamHall EXH-3470 → MR !3770: registration opening

The pilot disabled Pay and sent no key; its return page re-sent the pay request (EXH-3470). MR !3770 creates the attempt key with the order and makes the return page read the order (steps 7–10). The same logged buyers replay against the fixture endpoint over real HTTP.

4.1 logged buyers: 60 (20 plain, 10 double clicks, 8 lost replies re-sent, 14 3-D Secure returns in the same tab, 4 in a new tab, 4 reloaded), each meaning to pay once
4.1 EXH-3470 pilot: 94 pay requests over HTTP · 94 charges · buyers charged more than once 30
4.1 MR !3770: 68 pay requests over HTTP · 60 charges · buyers charged more than once 0

Every buyer meant to pay once. Under the pilot, every return page charged again, and so did each retry and reload; the disabled button stopped only the double clicks (step 8).

4.2 Proof domain, chat: a sticker store's launch

A chat app's sticker store launches 30 packs; each page shows how many launch editions are left (steps 2–5).

4.2 model: 30 sticker packs · 1500 views/s over 20 edges · 20 sales/s
4.2 a render per visit: origin 1500 requests/s · oldest count at open 0 s
4.2 shell + island, s-maxage=10: origin 60 requests/s · oldest count at open 10 s

A render per visit sends every view to the origin; the island with s-maxage=10 sends one request per pack per edge every 10 s.

4.3 The board for "Design the product page and checkout for a mid-size shop" (worked, not executed)

Typical question Steps that answer it Mechanism owner
"The Pay button is clicked twice on a slow network. What happens?" 7, 8 this lesson; the key's contract: api-idempotency-keys
"How do you keep LCP under 2.5 s while showing live stock?" 3–5 this lesson; the shell and holes: fsd-rendering-strategy-choice; edge copies: sd-cdn-edge-caching
"The bank asks for 3-D Secure. What changes?" 9, 10 this lesson
"The price changed while the page was open." 6 this lesson

Try it

Answer first, then check. Nothing is saved.

Question 1 of 7

ExamHall's design so far: the registration page creates an idempotency key and sends it with POST /registrations/{id}/pay. The bank's 3-D Secure page then replaces the page and sends the candidate back to /registrations/{id}/return, which sends the pay request again with the key to learn the result.

The interviewer's next follow-up: "In last week's logs, 40 candidates paid with 3-D Secure; 9 of them came back from their banking app in a new tab, and every candidate reloaded the return page once." Where should the key live so that every candidate is charged exactly once?

Pick one

Question 2 of 7

A concert promoter's show pages: 40 shows on sale and 12,000 page views a second at the on-sale peak, spread over 25 CDN edge locations, so every edge serves every show's page several times a second. Seats sell at 50 a second across the shows. The origin can answer at most 300 seat-count requests a second, and no visitor may see a seat count more than 10 s old when the page opens. Each page's shell is prerendered and cached at the edge until it is edited.

Which design for the seat count meets both limits?

Pick one

Question 3 of 7

A chat app's sticker shop caches each pack's page at the edge for a day; the page takes its price from an island cached at the edge with s-maxage=60, fetched once, when the page opens. The Pay screen shows the price the pack's page showed, and the server charges the price in force when Pay is pressed. A pack's price rose at 12:00:00. The island's copy at the buyers' edge was stored at 11:59:40, and the edge gets a request for it every second. Five buyers opened the page and paid at: 11:58:00 and 11:59:00; 11:59:30 and 12:00:30; 12:00:20 and 12:01:00; 12:00:50 and 12:01:30; 11:50:00 and 12:05:00.

How many were charged a price their Pay screen did not show?

Pick one

Question 4 of 7

A streaming service sells gift cards. One evening's logs hold three kinds of buyer: one who double-clicks Buy; one who, unsure, pastes the checkout's address into a new tab and clicks Buy there too; and parents who buy two €25 cards for two children on the same card, a minute apart, on purpose.

Which guard charges every card a buyer meant to buy, and no card twice?

Pick one

Question 5 of 7

The interviewer says: "Design the session page and checkout for ExamHall's paid exam registration." The numbers you get when you ask: 20,000 session-page views a second when registration opens, 120 sessions, 30 CDN edge locations, every edge serving every session's page several times a second; the origin answers at most 600 seat-count requests a second; no candidate may see a seat count more than 15 s old; a session's fee changes a few times a year; 3-D Secure on most payments, some candidates returning from a banking app in a new tab; double clicks, timeouts and reloads in every log. In 20 minutes, write your board: the numbers, what is cached where, the seat count's edge lifetime and refresh, where the Pay screen's price comes from, where the payment attempt's key lives, what the return page does.

Then write your choices in the shape of design.template.mjs as my-design.mjs, and run the check.

Question 6 of 7

A payments ledger's wallet top-up page creates an idempotency key in its script when it loads and sends it with POST /wallet/top-ups. Its fetch wrapper re-sends a request once if no reply arrives within 15 s. One customer's log: one click on Top up; no reply within 15 s, so the wrapper re-sends; the bank's page; back on the return page; a reload of it. Every request reached the server, which replays the saved response for a key it has seen.

How many charges does the provider record?

Pick one

Question 7 of 7

A streaming service's pay-per-view page for a boxing night shows how many tickets are left. The page's shell is cached at the edge for an hour (s-maxage=3600). The count is its own URL, cached at the edge with s-maxage=20, and an open page fetches it again every 30 s. The edge gets a request for the count every second, and tickets sell all the time.

To the nearest second, how old can the count on a viewer's screen be at most?

Pick one

Go deeper

Pro tip
  1. Split the page by freshness out loud, a static shell with live islands for price and stock, and say which region changes how often. When: the interviewer asks how the page stays fast while stock moves. Status: RAN on the CDN model (a model, not a real CDN).
Source

No item is keyed on a source; every key is executed. Vendor advice is valid as of 2026-10-12.

  • Stripe, Idempotent requests (the curriculum row's URL): https://docs.stripe.com/api/idempotent_requests (stripe-idempotent-requests.txt). "Retries with the same key return the saved response, including 500 errors." (the endpoint model's replay; the mechanism is api-idempotency-keys').
  • Stripe, The Payment Intents API: https://docs.stripe.com/payments/payment-intents (stripe-payment-intents.txt). "Each PaymentIntent typically correlates with a single shopping cart or customer session in your application."; "This key is typically based on the ID that you associate with the cart or customer session in your application." (step 7).
  • Stripe, 3D Secure authentication flow: https://docs.stripe.com/payments/3d-secure/authentication-flow (stripe-3ds-flow.txt). "When the customer finishes the authentication process, the redirect sends them back to the return_url you specified when you created or confirmed the PaymentIntent." (step 9); "The redirect also adds payment_intent and payment_intent_client_secret URL query parameters that your application can use to identify the PaymentIntent associated with the purchase." (step 10).
  • web.dev, Largest Contentful Paint (the curriculum row's URL): https://web.dev/articles/lcp (webdev-lcp.txt). "sites should strive to have Largest Contentful Paint of 2.5 seconds or less" (step 3).
  • Baymard Institute, Checkout usability (the curriculum row's URL): https://baymard.com/research/checkout-usability (baymard-checkout.txt). "70% of all e-commerce visitors abandon their shopping cart." (why the checkout is a round's deep dive; no step rests on it).
  • MDN, Window: sessionStorage property: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage (mdn-sessionstorage.txt). "Opening a page in a new tab or window creates a new session with the value of the top-level browsing context"; "If the page has an opener, the sessionStorage is initially a copy of the opener's sessionStorage object.".
  • MDN, Cache-Control: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control (mdn-cache-control.txt). "The s-maxage response directive indicates how long the response remains fresh in a shared cache." (steps 4–5).

Checked against the tools and docs as of 2026-10-12.