Designing an E-Commerce Checkout System
The one moment in checkout where a real design decision — inventory before payment — prevents selling the same last item twice.
Advanced
| Functional | Non-functional |
|---|---|
| Browse and search the marketplace catalog | Never sell an item that's actually out of stock (no overselling) |
| Add items to a cart and check out | Checkout must stay fast even during a flash sale |
| View order history | Payment and inventory changes must be consistent with each other |
| Component | Role |
|---|---|
| Catalog Service | Backed by a document store (see SQL vs. NoSQL) since items have irregular attributes (a spice kit has heat level; a t-shirt has size). |
| Search Service | A distributed search index kept in sync with the catalog for fuzzy, ranked browsing. |
| Cart Service | Session-scoped, a natural fit for a key-value store. |
| Order Service | The relational core of checkout — needs ACID transactions for the inventory-and-payment sequence below. |
| Payment Service | Talks to an external payment gateway; every call is designed to be idempotent (see API Design). |
BEGIN TRANSACTION;
UPDATE inventory SET qty = qty - 1 WHERE item_id = 'spice_042' AND qty > 0;
-- if this UPDATE affects 0 rows, the item is already sold out — abort here,
-- before ever contacting the payment gateway
COMMIT;
-- only if the inventory decrement succeeded:
call PaymentService.charge(customer, amount)
qty > 0 guard combined with a single atomic transaction (see ACID Transactions Explained) is what prevents two concurrent checkouts from both successfully decrementing a quantity of 1 — the second transaction's UPDATE simply affects zero rows and the order is correctly rejected before payment is ever attempted.orders table accumulates far more completed orders than active ones, and a customer's occasional "view my order history" query doesn't need transactional guarantees the way an active order does.| Requirement | How it's met |
|---|---|
| No overselling | Inventory decrement is atomic and happens before payment, with a guard clause preventing negative stock. |
| Fast checkout under load | Cart and catalog reads are cache-backed; only the final inventory-and-payment step needs strong consistency. |
| Consistency between payment and inventory | A single ACID transaction for the inventory step, plus TTL-based reservation cleanup for abandoned checkouts. |
| Scalable order history | Terminal-state orders are archived out of the relational hot path into a store built for large-scale historical reads. |