Learning pathsPricingChecking sign-in…
← LLD problem library

LLD-010 · DESIGN PRACTICE

Shopping Cart and Checkout

Freeze pricing and make reservation, payment, refund and release obligations explicit.

Local Java 21 reference verified: 25 checks. Learner drafts are not executed. Author self-review; independent review pending.

Existing introductory lesson · Version 1

Understand the problem

Design a versioned cart and checkout coordinator. Produce an immutable quote, accept one checkout, correlate inventory and payment outcomes, and recover when cancellation and a late charge leave compensation work. Explain why external actions cannot be represented by a single database rollback.

Before you start

  • Immutable money/price snapshots
  • Optimistic versions and retry identity
  • State machines
  • Reservation and compensation boundaries

Scope and explicit decisions

  • One in-memory cart/checkout session. It can be edited before one accepted begin; after that the cart remains sealed even if checkout fails. Opening a new cart, multiple simultaneous orders, shipment splitting, taxes, discounts and subscription billing are not implemented.
  • Item unit prices are trusted catalog-adapter inputs in integer minor units. Quote priceVersion is an immutable label, not a catalog lookup or proof of price authenticity. A production adapter must resolve authorized prices rather than trust a browser.
  • set replaces quantity/price for one SKU and increments cart version. Quantity must be positive; remove is explicit. Quotes capture sorted items, exact total, cart version, expiry and pricing label. Arithmetic overflow rejects quote creation.
  • A trusted nondecreasing elapsed clock is used for quote expiry. begin at expiresAt is rejected. Editing the cart invalidates old quotes by version, even if their timer has not expired.
  • begin uses a key fingerprint of quote ID and expected cart version. Matching repeats resolve the same Order identity/current state. A different key cannot begin another order after the session seals.
  • The coordinator performs no network I/O. reserved/paid/released/refunded are trusted adapter acknowledgements. false payment means definite no-charge; unknown means leave the current state unresolved, not call paid(false).
  • Reservation failure produces FAILED. Payment failure after successful reservation produces RELEASE_REQUIRED. A late success after cancellation/release can create REFUND_REQUIRED or REFUND_AND_RELEASE_REQUIRED. These states record obligations; external actions are not executed by changing the enum.
  • cancel while RESERVING is rejected until reservation outcome is resolved. cancel while PAYING requests release; cancellation in other states returns current state and does not implement confirmed-order refund policy.
  • Payment attempt IDs reject contradictory reuse. Additional distinct charges outside the expected states are rejected and require adapter reconciliation. Cleanup acknowledgements are state-guarded; duplicate or stale cleanup may reject rather than return a historical response. No durable storage or crash recovery is implemented.

Worked examples

Input: Cart version1 has two books at 100. Quote v1 is 200. begin succeeds, reserve succeeds, charge succeeds.

Outcome: RESERVING→PAYING→CONFIRMED; quote remains 200 and cart is sealed.

Snapshot acceptance and external outcome transitions have separate identities.

Input: Cancel while PAYING, then receive a successful charge before release completes.

Outcome: RELEASE_REQUIRED→REFUND_AND_RELEASE_REQUIRED. Both acknowledgements are needed before FAILED.

Cancellation cannot make an in-flight payment disappear.

Your design attempt

Each language has a separate draft across all three levels. Saving is device-only and does not sync to your account. Anyone using this browser profile can load it. Loading is always explicit.

Java 21 reference code is provided for local study. Use Run program in the editor to execute your code and test driver. Program runs show output; they do not grade your design.

Solution.java
Run program · Java 21

No unsaved changes · 208/20000

Self-review

Checks apply to this visit. Self-review is not a passed submission or verified mastery.

Try before revealing

Hint 1

Which facts must remain unchanged after the customer accepts a quote?

Hint 2

What prevents a second begin under a different retry key?

Hint 3

List every external obligation that cancellation can leave behind.

Requirements and invariants

R1 — Accepted checkout uses an immutable quote for the current cart version. begin protects I1.

R2 — Only one begin can seal this cart session. begin protects I2.

R3 — Every known outstanding external repair remains represented until acknowledged. paid protects I3.

I1: Order.quote and its items/amount/pricing version never change after begin.

I2: A sealed cart cannot be edited or accepted under a second begin key; a retry resolves one original order identity.

I3: Known reserved stock/payment liability is not hidden by cancellation: release and refund obligations transition independently until both are acknowledged.

Derive the design

Cart arithmetic is not the checkout transaction

A basic cart can add items and sum totals correctly, but checkout introduces a time boundary: prices, quantities and external outcomes can change independently. Start by freezing a quote tied to cart version. The reference then uses an explicit coordinator state machine rather than hiding reserve/charge/release/refund behind one synchronous success boolean.

Alternative: A transactional database can store local cart/order state but cannot roll back an already accepted external charge. A saga or durable workflow is a suitable extension only after each step’s identity, outcome ambiguity and compensation contract are specified.

Clarify which prices are authoritative

This reference accepts trusted item prices; do not expose that method directly to an untrusted browser. Real checkout resolves prices and eligibility at an authorized boundary before creating a quote.

Freeze intent before external work

A quote has identity, expiry and cart version. begin accepts it once and seals mutable editing, so asynchronous callbacks cannot drift with cart changes.

Write the failure transitions first

Enumerate reserve failure, definite payment failure, unknown payment and cancellation/late success. Give every known obligation a visible state rather than one catch-all error.

Keep external calls outside local atomicity

Methods record transitions and trusted acknowledgements. A real worker performs I/O with stable operation identities and persists results/repair intent; the local monitor is not a distributed transaction.

Responsibilities and ownership

Checkout

Owns: Cart version, immutable quotes, order lifecycle and callback identities

Methods: set, quote, begin, reserved, paid, cancel, released, refunded

Coordinates local facts but executes no provider or inventory I/O.

Item / Quote

Owns: Validated SKU quantities, unit prices, exact totals and immutable quote terms

Methods: Record constructors/accessors

Catalog authority and pricing-policy execution are adapter responsibilities.

Order

Owns: Stable checkout identity and current lifecycle snapshot

Methods: Immutable record accessors

A state change is not a completed external action.

Begin / Paid

Owns: Retry fingerprints and trusted callback identity

Methods: Structured equality

Matching retries cannot silently change quote or payment meaning.

Checkout lifecycle

One local cart session is sealed after begin. No external actions are executed inside the coordinator.

  1. Mutable versioned cart
  2. ↓ Trusted pricing and checked totals

    Immutable quote + expiry
  3. ↓ Accept current terms once

    Sealed RESERVING order
  4. ↓ Trusted reserve/payment acknowledgements

    PAYING then CONFIRMED
Compensation after late charge

Refund and release are independent obligations, and either can require retries outside this model.

  1. Cancel while PAYING
  2. ↓ Cancellation is not a provider outcome

    RELEASE_REQUIRED
  3. ↓ Preserve both liabilities

    Late charge: REFUND_AND_RELEASE_REQUIRED
  4. ↓ Only then terminal FAILED

    Acknowledge both repairs

Data model, schema and relationships

A mutable cart becomes an immutable quote, then one accepted checkout session tracks independent inventory and payment facts. Repair obligations are separate rows because refund and release can fail independently.

Implementation boundary: The reference uses Cart/Quote/session records and trusted correlated adapter facts. SQL/outbox/payment providers below describe a durable extension.

These are proposed logical schemas with field contracts, not executable database migrations. PK identifies a row, FK references an existing parent, UK is a uniqueness rule. A composite PK identifies the combination. Nullable references are marked with ?. A foreign key protects identity; cross-row limits, timing and state transitions also require the transaction rules below.

cart: relationship map

Connectors name the relationship; multiplicities state parents per child and children per parent. 0..1 means optional, 1 required, 0..* any number. Self-links show two roles of the same entity.

cart relationshipscart 1 to quote 0..*: is priced. quote.cart_id → cart.id. cart 1 to checkout 0..*: belongs to. checkout.cart_id → cart.id.is priced1 parent · 0..* childrenquoteid [PK]cart_id [FK]cart_versionbelongs to1 parent · 0..* childrencheckoutid [PK]quote_id [FK]statecartid [PK]versionowner
quote: relationship map

Connectors name the relationship; multiplicities state parents per child and children per parent. 0..1 means optional, 1 required, 0..* any number. Self-links show two roles of the same entity.

quote relationshipsquote 1 to checkout 0..*: is accepted. checkout.quote_id → quote.id.is accepted1 parent · 0..* childrencheckoutid [PK]quote_id [FK]statequoteid [PK]cart_id [FK]cart_version
checkout: relationship map

Connectors name the relationship; multiplicities state parents per child and children per parent. 0..1 means optional, 1 required, 0..* any number. Self-links show two roles of the same entity.

checkout relationshipscheckout 1 to checkout_fact 0..*: correlates evidence. checkout_fact.checkout_id → checkout.id. checkout 1 to repair_obligation 0..*: requires repair. repair_obligation.checkout_id → checkout.id.correlates evidence1 parent · 0..* childrencheckout_factid [PK]checkout_id [FK]kindrequires repair1 parent · 0..* childrenrepair_obligationid [PK]checkout_id [FK]kindcheckoutid [PK]quote_id [FK]state

Entity definitions and field contracts

cart

Editable purchase intent.

FieldType / keyMeaning and reference
iduuid · PKCart identity
versionbigint · VALUEMutation version
ownertext · VALUEAuthenticated purchaser

Code mapping: Cart.

  • Quote must correspond to expected cart version.

quote

Immutable trusted price snapshot.

FieldType / keyMeaning and reference
iduuid · PKQuote identity
cart_iduuid · FKSource cart · cart.id
cart_versionbigint · VALUEPriced version
totalbigint · VALUEExact single-currency total

Code mapping: Quote.

  • Snapshot line prices, quantities and policy/currency; reject stale/expired quote.

checkout

One sealed accepted session.

FieldType / keyMeaning and reference
iduuid · PKSession identity
quote_iduuid · FKAccepted quote · quote.id
stateenum · VALUEExplicit orchestration state
cart_iduuid · FKSource cart; unique accepted session per sealed cart · cart.id

Code mapping: Checkout state owner.

  • One accepted session per sealed cart under this reference contract.

checkout_fact

Correlated provider outcome evidence.

FieldType / keyMeaning and reference
idtext · PKProvider operation identity
checkout_iduuid · FKSession owner · checkout.id
kindenum · VALUEInventory or payment
outcomeenum · VALUEKnown success failure or unknown

Code mapping: Inventory/payment facts.

  • Duplicate terminal evidence must agree; validate session and amounts.

repair_obligation

Independent compensation work.

FieldType / keyMeaning and reference
iduuid · PKRepair identity
checkout_iduuid · FKOwner · checkout.id
kindenum · VALUERefund or release
statusenum · VALUENeeded pending complete failed
source_operationtext · VALUERemote effect being repaired; distinguishes extra side effects
next_duetimestamp? · VALUEDurable retry eligibility for unresolved repair work

Code mapping: Separate refund/release obligations.

  • Unique(checkout_id,kind,source_operation) when multiple provider effects are supported.

Relationship cardinalities and their reasons

Parent → childMultiplicityFK / why
cart → quote

is priced

1 parent per child; 0..* children per parentquote.cart_id → cart.id

A cart can have many historical quotes.

quote → checkout

is accepted

1 parent per child; 0..* children per parentcheckout.quote_id → quote.id

Single-session constraints restrict which quotes may begin checkout.

checkout → checkout_fact

correlates evidence

1 parent per child; 0..* children per parentcheckout_fact.checkout_id → checkout.id

Local orchestration state derives from trusted remote facts.

checkout → repair_obligation

requires repair

1 parent per child; 0..* children per parentrepair_obligation.checkout_id → checkout.id

Refund and release progress independently; one success cannot erase the other obligation.

cart → checkout

belongs to

1 parent per child; 0..* children per parentcheckout.cart_id → cart.id

Source cart; unique accepted session per sealed cart

Transaction boundaries

  1. begin: compare cart/quote versions, seal cart and insert accepted session with stable command identities.
  2. Outcome: record provider fact and derive session plus required repair rows atomically; dispatch repair outside transaction through an outbox.

Indexes and uniqueness

  1. Unique accepted checkout per cart through explicit cart/session ownership.
  2. Index repair_obligation(status,next_due), checkout_fact(checkout_id,kind); provider operation IDs unique.

Schema traps and failure cases

  1. A successful refund cannot mark inventory release complete.
  2. Timeout is unknown; reopening the same sealed cart can duplicate side effects.

Trace the records through one operation

  1. Quote Q pins cart v4 prices; session C accepts it once.
  2. Payment succeeds while inventory fails; refund obligation is created.
  3. Repair result closes only its own obligation; repeated provider fact cannot create a second checkout.

Method contracts

set(Item,expectedVersion); remove(sku,expectedVersion)

Edit an unsealed cart only at its current version. set replaces one SKU entry; remove is a no-op for absent SKU without increment.

quote(priceVersion,ttl,now) → Quote

Reject empty cart/invalid label/TTL. Compute every quantity×unitPrice and sum with overflow checks; capture current cart version/items and immutable expiry.

begin(quoteId,expectedVersion,key,now) → Order

Resolve key repeats, validate quote/current version/expiry, then atomically seal cart and create RESERVING order.

reserved(orderId,success); paid(orderId,attemptId,success)

Correlate trusted outcomes. Do not interpret timeout as false. Contradictory repeats reject; known late charge adds refund liability rather than confirming a cancelled flow.

cancel; released; refunded

Cancellation creates repair work only in declared states. Acknowledgements clear the corresponding obligation, preserving the other if both are pending.

What, when, why and how

Each concept is attached to the requirement it protects, its implementation, an alternative and a test.

Immutable quote snapshot

what
Freeze the exact order facts the customer accepted.
when
Catalog prices or cart quantities change between browsing and payment.
why
Recomputing from mutable cart/catalog data makes history and payment comparison inconsistent.
how
Quote copies Item records and stores cartVersion, checked amount, expiresAt and priceVersion. Order retains that Quote unchanged.

Code: Quote, quote, begin · Invariants: I1

Alternatives, cost and failure example

Alternative: Reprice at begin instead, but explicitly ask the customer to accept new terms; do not silently switch amounts.

Cost: Quote storage retains item snapshots and histories; this example has no retention cleanup.

Counterexample: Customer accepts two books at 100 each, then a later catalog update rewrites the order total.

Test: Edit cart after quoting and reject old begin; verify old quote stays 200 under its original version.

Optimistic version plus idempotent begin

what
Reject stale intent and resolve repeated accepted checkout identity.
when
Two tabs edit or begin the same cart.
why
Version guards prevent unintended contents while keys prevent duplicate effects after a response loss.
how
begin compares current cart/quote versions and seals the session under one monitor. Begin key stores quote+expectedVersion and original Order ID.

Code: set, begin, Begin · Invariants: I1, I2

Alternatives, cost and failure example

Alternative: A versioned database row and unique command key are the durable equivalent; separate uncoordinated writes lose atomicity.

Cost: One cart session stays sealed permanently here; a production product needs explicit new-cart/reset ownership.

Counterexample: Two different begin keys both charge the same cart because only a per-key cache was checked.

Test: Race two begin keys at the same version; one wins, and original key retry returns that Order.

Stateful compensation obligations

what
Represent external repair as business work that remains pending.
when
A reservation succeeds but payment fails, or payment arrives after cancellation.
why
An enum named FAILED can conceal stock still held or money still charged.
how
Use RELEASE_REQUIRED, REFUND_REQUIRED and the combined state. released/refunded remove only their own obligation; terminal FAILED follows completed local acknowledgements.

Code: paid, released, refunded · Invariants: I3

Alternatives, cost and failure example

Alternative: A durable workflow/outbox can drive these obligations, but compensation itself can fail and needs its own retry/review policy.

Cost: More states increase transition-table/test requirements but expose otherwise hidden liabilities.

Counterexample: Cancel sets FAILED immediately while a late successful charge is discarded.

Test: Cancel PAYING, accept late success, then acknowledge refund/release in either supported order and inspect remaining obligation.

Definite failure versus unknown external outcome

what
An absence of response is not evidence that no charge occurred.
when
Provider timeouts or worker crashes interrupt the request path.
why
Treating unknown as failure may trigger a second charge or clear obligations incorrectly.
how
Adapters call paid(false) only for definite no-charge. Unknown leaves PAYING or cleanup state unresolved; a later trusted success is correlated by attempt ID.

Code: paid, Paid, cancel · Invariants: I3

Alternatives, cost and failure example

Alternative: Use provider idempotency/query APIs or manual reconciliation for unknown results. No local boolean can infer an unobserved remote fact.

Cost: The teaching coordinator lacks a durable attempt journal and automatic reconciler; process loss loses evidence.

Counterexample: A timeout invokes paid(false), releases stock and retries with a fresh payment identity while the first charge succeeded.

Test: Exercise late success after release and reject contradictory success/failure under one attempt ID.

Read and run the Java reference

Reveal complete Solution.java

Java 21. Save as Solution.java; compile with javac --release 21. The repository also contains Test.java and the lld:java verification command. This reference implements the local contract above.

Solution.java Java 21
import java.util.*;
/** Local checkout state machine; external reserve/payment/refund calls are commands for adapters. */
public final class Solution {
    private Solution() {}
    public enum State { RESERVING, PAYING, CONFIRMED, FAILED, RELEASE_REQUIRED, REFUND_REQUIRED, REFUND_AND_RELEASE_REQUIRED }
    public record Item(String sku,int quantity,long unitPrice){public Item{if(sku==null||sku.isBlank()||quantity<1||unitPrice<0)throw new IllegalArgumentException("item");}}
    public record Quote(String id,long cartVersion,List<Item> items,long amount,long expiresAt,String priceVersion){public Quote{items=List.copyOf(items);}}
    public record Order(String id,Quote quote,State state){}
    private record Begin(long cartVersion,String quoteId,String orderId){}
    private record Paid(String orderId,boolean success){}
    public static final class Checkout {
        private final Map<String,Item> cart=new TreeMap<>();
        private final Map<String,Quote> quotes=new HashMap<>();
        private final Map<String,Order> orders=new HashMap<>();
        private final Map<String,Begin> keys=new HashMap<>();
        private final Map<String,Boolean> reservations=new HashMap<>();
        private final Map<String,Paid> payments=new HashMap<>();
        private long version,sequence,time;
        private boolean locked;
        private void now(long at){if(at<time)throw new IllegalArgumentException("time");time=at;}
        public synchronized long set(Item item,long expectedVersion){Objects.requireNonNull(item);if(locked||expectedVersion!=version)throw new IllegalStateException("locked or stale cart");cart.put(item.sku(),item);return ++version;}
        public synchronized long remove(String sku,long expectedVersion){if(locked||expectedVersion!=version)throw new IllegalStateException("locked or stale cart");if(cart.remove(sku)!=null)version++;return version;}
        public synchronized Quote quote(String priceVersion,long ttl,long at){
            if(cart.isEmpty()||priceVersion==null||priceVersion.isBlank()||ttl<1)throw new IllegalArgumentException("quote");
            long deadline=Math.addExact(at,ttl),amount=0;for(var item:cart.values())amount=Math.addExact(amount,Math.multiplyExact(item.unitPrice(),item.quantity()));now(at);
            var q=new Quote("Q"+(++sequence),version,new ArrayList<>(cart.values()),amount,deadline,priceVersion);quotes.put(q.id(),q);return q;
        }
        public synchronized Order begin(String quoteId,long expectedVersion,String key,long at){
            if(key==null||key.isBlank())throw new IllegalArgumentException("key");var previous=keys.get(key);
            if(previous!=null){if(previous.cartVersion()!=expectedVersion||!previous.quoteId().equals(quoteId))throw new IllegalArgumentException("key reused");return get(previous.orderId());}
            var q=quotes.get(quoteId);if(q==null)throw new IllegalArgumentException("quote");now(at);
            if(locked||expectedVersion!=version||q.cartVersion()!=version||at>=q.expiresAt())throw new IllegalStateException("stale, expired or locked");
            var order=new Order("O"+(++sequence),q,State.RESERVING);orders.put(order.id(),order);keys.put(key,new Begin(expectedVersion,quoteId,order.id()));locked=true;return order;
        }
        public synchronized Order reserved(String orderId,boolean success){
            var old=reservations.get(orderId);if(old!=null){if(old!=success)throw new IllegalStateException("contradictory reservation");return get(orderId);}
            var order=get(orderId);if(order.state()!=State.RESERVING)throw new IllegalStateException("not reserving");
            reservations.put(orderId,success);return update(order,success?State.PAYING:State.FAILED);
        }
        public synchronized Order paid(String orderId,String attemptId,boolean success){
            if(attemptId==null||attemptId.isBlank())throw new IllegalArgumentException("attempt");var prior=payments.get(attemptId);
            if(prior!=null){if(!prior.orderId().equals(orderId)||prior.success()!=success)throw new IllegalStateException("payment reused");return get(orderId);}
            var order=get(orderId);
            // A second, distinct attempt is not silently accepted; caller must reconcile it separately.
            if(order.state()!=State.PAYING&&!(order.state()==State.RELEASE_REQUIRED||order.state()==State.FAILED))throw new IllegalStateException("unexpected payment");
            payments.put(attemptId,new Paid(orderId,success));
            if(order.state()!=State.PAYING)return success?update(order,order.state()==State.RELEASE_REQUIRED?State.REFUND_AND_RELEASE_REQUIRED:State.REFUND_REQUIRED):order;
            return update(order,success?State.CONFIRMED:State.RELEASE_REQUIRED);
        }
        public synchronized Order cancel(String orderId){
            var order=get(orderId);if(order.state()==State.PAYING)return update(order,State.RELEASE_REQUIRED);
            if(order.state()==State.RESERVING)throw new IllegalStateException("resolve reservation first");return order;
        }
        public synchronized Order released(String orderId){var order=get(orderId);if(order.state()==State.RELEASE_REQUIRED)return update(order,State.FAILED);if(order.state()==State.REFUND_AND_RELEASE_REQUIRED)return update(order,State.REFUND_REQUIRED);throw new IllegalStateException("no release pending");}
        public synchronized Order refunded(String orderId){var order=get(orderId);if(order.state()==State.REFUND_REQUIRED)return update(order,State.FAILED);if(order.state()==State.REFUND_AND_RELEASE_REQUIRED)return update(order,State.RELEASE_REQUIRED);throw new IllegalStateException("no refund pending");}
        private Order update(Order order,State state){var next=new Order(order.id(),order.quote(),state);orders.put(next.id(),next);return next;}
        public synchronized Order get(String id){var order=orders.get(id);if(order==null)throw new IllegalArgumentException("order");return order;}
        public synchronized long version(){return version;}
    }
}

quote calculates before publishing

Checked multiplication and addition run before storing the new Quote. Overflow does not create a malformed accepted price.

begin resolves prior identity before checking current lock

A successful retry must still return its original Order after the cart is sealed. A fresh key is rejected by the seal.

paid handles the losing late-success path

A charge that arrives after release/cancellation does not confirm the old business flow; it creates a refund obligation and preserves any release work.

cleanup acknowledgements preserve the other obligation

From the combined state, refunded leaves RELEASE_REQUIRED and released leaves REFUND_REQUIRED. Only completion of both reaches terminal repair state.

Complexity and limits

  • Cart updates use an ordered SKU map: O(log I). quote iterates/copies I items: O(I), with checked long arithmetic.
  • begin and callback lookup are expected O(1) over retained maps; constructing order/quote snapshots retains references to immutable item records.
  • Space grows with I cart items, Q quotes, O orders and retained begin/payment identities. This session seals after one begin but quote/history retention is not bounded by a cleanup policy.
  • The coordinator has no network latency inside its monitor. That simplifies local reasoning but does not imply durability or exactly-once external side effects.

Walk through the actual reference

These walkthrough fixtures are emitted only after the Java harness verifies their operations and expected state. Concurrency tests additionally exercise competing callers.

Quote snapshot and successful checkout

Step 1 of 3: Quote 2 books at 100 each

Amount 200; cartVersion 1; price-v1

Invariant: Order terms are immutable

Read the complete trace table
ActionState after actionInvariant
Quote 2 books at 100 eachAmount 200; cartVersion 1; price-v1Order terms are immutable
Begin with current versionRESERVING; cart sealedOnly one accepted checkout
Reserve and accept paymentCONFIRMEDPayment completion follows reservation

Cancellation plus late successful charge

Step 1 of 3: Cancel while PAYING

RELEASE_REQUIRED

Invariant: Cancellation is not proof that a provider stopped

Read the complete trace table
ActionState after actionInvariant
Cancel while PAYINGRELEASE_REQUIREDCancellation is not proof that a provider stopped
Late payment succeedsREFUND_AND_RELEASE_REQUIREDBoth external obligations stay visible
Acknowledge refund, then releaseFAILED with no outstanding cleanup in this modelTerminal repair requires both acknowledgements

Mistakes and counterexamples

Calculate historic order price from current catalog

Failing case: The item price changes after quote acceptance.

Repair: Retain immutable accepted terms and version.

Use only a retry key without cart version

Failing case: A stale tab submits an old quote for edited contents.

Repair: Check both accepted identity and current version/expiry.

Set FAILED on cancellation and forget obligations

Failing case: Stock remains reserved and a late payment succeeds.

Repair: Track release/refund as explicit pending business work.

Equate timeout with no charge

Failing case: Provider processed payment but response was lost.

Repair: Preserve unknown state and reconcile a stable attempt identity.

Engineer → Senior → Staff

Choose a deep dive

Implement exact cart/quote behavior.

Executed: quantity validation, checked totals, immutable pricing snapshot, version and expiry guards.

Change exercise

Add a discount calculation with explicit ordering and rounding before snapshot creation.

Worked answer guidance

Separate policy from mechanism, define whether discounts apply per item or subtotal, test noncommutative ordering and exact minor-unit rounding. Store the resulting breakdown/version in Quote rather than re-evaluating later.

Interview follow-ups

Why is quantity zero not remove?

This API chooses explicit remove, avoiding ambiguous zero-price/zero-quantity item semantics. Other choices are valid if documented and tested.

Is priceVersion proof of a correct price?

No. It is a label on a trusted snapshot. A real catalog adapter must enforce actual policy and source authority.

Return to the lesson →

Provenance and scope of evidence

Original teaching material. The local contract is implemented by Solution.java and tested by Test.java on Java 21. Distributed persistence, real provider/device adapters and deployment are not claimed.

Reference verification is not independent editorial review, production deployment verification or a claim that distributed adapters are implemented.