Skip to content
masterclassBuddyTech Buzz5 fresh blogs · 5:00 AM IST

System Design blueprint · Quick commerce

10-minute grocery delivery (dark stores)

A quick-commerce workflow that checks whether a location is serviceable, routes the order to one nearby dark store, reserves stock in that store, then runs picking, packing, rider dispatch and live tracking within a 10-minute promise. It must never sell stock the assigned store does not have, and it must never charge for items that were not delivered.

Steps
9
Subjective questions
33
Objective questions
33

The problem and the outcome

Problem: Customers want groceries in minutes, but each dark store holds limited stock and serves a small radius. Riders and pickers are scarce at peak times. Stale inventory or slow dispatch breaks the delivery promise and leads to cancellations and refunds.

Outcome: Each order is tied to one store with stock that is truly available, and it moves through pick, pack and dispatch against a time budget for every stage. Shortfalls become instant substitutions or exact refunds, and forecasts keep shelves stocked before demand arrives.

Architecture

Customer appbrowse and order01ServiceabilityH3 cell to store01Order servicecheckout + promise02Store inventoryRedis + Postgres03Order eventsKafka04Pick and packpicker handheld04Item short?swap or refund07Paymentsrefund ledger07Rider dispatchstore rider queue05Rider apppickup and drop06Live trackingWebSocket + ETA06Demand forecaststore-SKU-hour08Restock plannermother warehouse09lat-lng on app openplace orderreserve stock (TTL)in-stock catalogorder.confirmedpick taskpre-assign riderSKU not foundapprove swappartial refundorder packedassign + bag IDGPS pingslive ETAsales streamreorder quantityinbound receipt

How it works, step by step

  1. When the app opens, the device location is mapped to an H3 cell. Serviceability looks up which dark store covers that cell and whether it is open, staffed and below its load limit. It returns the store_id and a delivery promise, or shows 'not serviceable'.
  2. The catalog shows only SKUs that this store can sell right now. At checkout, the order service re-checks serviceability and the promise, then creates the order with an idempotency key so that retries never create duplicate orders.
  3. Inventory reserves each line atomically in Redis, with a TTL. The reservation becomes firm on payment success and is released on failure or timeout. Postgres stays the system of record and receives every reserve, commit and release movement.
  4. An order.confirmed event is published to Kafka. The store's pick service turns the order into a pick list sorted by bin location. Pickers scan each item as they pick it, and packing produces a bag with a label and an ID.
  5. Dispatch matches a rider while picking is still underway, not after it ends. It chooses from riders waiting at or returning to that store, based on ETA to the store and whether orders can be batched without breaking either promise.
  6. The rider scans the bag at handover, and that scan starts the last-mile leg. GPS pings go to the tracking service. Tracking smooths the location, recomputes the ETA and pushes updates to the customer over WebSocket until the rider confirms delivery with an OTP.
  7. If a scanned bin is empty, the item is marked short and inventory is corrected. The customer gets a substitute suggestion with a short approval window. If they reject it or time runs out, the line is dropped and an exact refund goes through the ledger.
  8. A forecasting job consumes the sales stream along with stockouts, weather and calendar signals. It predicts demand per store, per SKU, per hour, and treats stockout periods as censored demand rather than zero demand.
  9. The restock planner turns each forecast into reorder quantities based on shelf capacity, shelf life and the warehouse delivery schedule. Inbound stock is received at the store with scanning, which updates inventory before the stock becomes sellable.

Tech stack

  • H3 hexagonal geo-indexing for serviceability polygons
  • Redis for hot per-store stock counters and reservations
  • PostgreSQL as the inventory and order system of record
  • Apache Kafka for order, pick and dispatch events
  • WebSocket gateway for live tracking pushes
  • Mapping/routing API for ETA and road distance
  • Gradient-boosted or time-series models for store-SKU demand forecasting
  • Kubernetes services partitioned by city

Key design decisions

  • Each order is assigned to one store and is never split. Multi-store fulfilment breaks the 10-minute promise and doubles rider cost, so SKUs that the store cannot supply are hidden instead.
  • Stock is reserved at checkout with a TTL rather than decremented at payment, so two customers cannot both buy the last unit. The TTL limits how long abandoned carts lock stock.
  • The 10-minute promise is split into stage budgets (queue, pick, pack, handover, travel). Each stage is monitored separately, so a breach can be traced to one team.
  • Riders are pre-assigned during picking instead of after packing. This removes idle wait time, at the cost of an occasional rider reassignment.
  • Serviceability is dynamic. Under surge, a store can shrink its radius or pause, because declining an order is better than breaking the promise.

Common mistakes

  • Displayed stock drifts from physical stock because of damage, theft or mis-binning. Without cycle counts and short-pick feedback, the app keeps selling items that are not on the shelf.
  • Treating stockout hours as zero demand trains the forecast to under-order the very items that ran out.
  • Using straight-line distance for serviceability ignores rivers, flyovers and gated societies, so some 'nearby' cells are actually far by road.
  • Refunds issued from both the substitution flow and the customer-support flow can double-refund. All refunds need to go through one idempotent ledger keyed by order line.
  • Hot SKUs such as milk at morning peak cause contention on a single Redis key. Shard the counters or use Lua scripts, and avoid read-modify-write from app servers.

What to measure

  • Share of orders delivered within the promised time, broken down by stage
  • Order-to-packed time and rider wait-at-store time per dark store
  • Short-pick rate and fill rate (items delivered / items ordered)
  • Store-SKU stockout hours and forecast error (e.g. WAPE)
  • Refund amount per order and the substitution acceptance rate

Most-asked interview questions

Subjective questions 33

1How do you prevent overselling the last units of an item in a dark store during peak demand?Asked almost every time

I treat each store-SKU as its own counter, held in Redis for speed and backed by Postgres as the record. At checkout, I reserve the quantity with an atomic Lua script. The script checks available stock minus existing reservations and writes a reservation with a TTL. Payment success commits the reservation, and failure or expiry releases it. Every movement is written as an event, so Postgres can be rebuilt and reconciled. The catalog reads the same available-to-promise number, so out-of-stock items disappear quickly. Physical drift still happens, so a short pick during picking immediately corrects the count and triggers a substitution or refund. For very hot SKUs, I split the stock into a few sub-counters to avoid single-key contention. To sum up: reservation with TTL, atomic operations, and fast correction from the shop floor. (The Lua script runs on Redis, so the check and the write happen as one atomic step.)

2Redis holds live reservations but Postgres is the system of record. How do you keep them consistent, and what happens if Redis loses data?Asked almost every time

Every reserve, commit and release writes a movement row to Postgres, ideally through an outbox or a stream that is replayed in order with movement IDs, so replays are idempotent. Redis is a fast projection: available equals on-hand minus active reservations. A reconciliation job compares the Redis counters with the Postgres ledger per store and SKU, and it alerts on drift and repairs it. If Redis fails over and loses recent writes, I rebuild the affected store's keys from Postgres. That means on-hand stock plus unexpired reservations. While I rebuild, I briefly mark that store's catalog read-only or not serviceable. Selling during a rebuild risks overselling, and the hard rule is never to oversell, so pausing one store for a short time is the right trade.

3How would you design the idempotency key for order creation, and where is it enforced?Asked almost every time

The client generates a UUID when the user taps 'place order' and reuses it on every retry of that attempt. The order service stores the key with a hash of the request, so the customer, store, lines and amount, under a unique constraint in Postgres. On a retry with the same key and the same hash, it returns the original response. If the same key arrives with a different payload, that is a client bug, so it returns a conflict. The key is scoped to the user and expires after a window, for example a day. I pass the same key downstream as the reservation ID and as the payment gateway's idempotency or merchant reference. That way a retried request cannot double-reserve stock or double-charge the customer, even when the first attempt timed out and its real outcome is unknown.

4Payment succeeds, but the success callback arrives after the reservation TTL has expired and the stock was released. What do you do?Asked almost every time

First, I would try to re-reserve the same lines atomically. If stock is still there, the order confirms normally. If some lines are gone, I must not fulfil items the store doesn't have. I either confirm the available lines and refund the missing ones exactly through the ledger, or, if a key item is missing, I cancel and refund in full, and I tell the customer clearly. To make this rare, I set the TTL above the realistic payment window. I extend the reservation when the gateway reports the payment is pending, and I reconcile with the gateway by polling as well as through webhooks. I also track late-success counts as a metric, because a rising count means the TTL or the payment flow needs tuning.

5Why does dispatch match a rider while picking is still underway, and what are the risks?Asked almost every time

Picking and packing take a fixed part of a short budget. If the rider search only starts after packing, the bag waits on the shelf while the search and the rider's travel back to the store add their time on top. Starting the match early overlaps the two, so a rider arrives as the bag is sealed. The risks are idle riders when picking is slow or short-picked, and over-commitment when two stores compete for the same rider. I handle this by using a predicted pack-complete time from pick progress, so the match triggers when the predicted pack time is close to the rider's ETA. I also allow reassignment until the rider has accepted and is close, and I measure both rider wait time and bag wait time to tune the trigger.

6Walk me through the short-pick flow when a picker scans an empty bin.Asked almost every time

The picker scans the bin, and the app marks the line short. The pick service emits an item.short event, and inventory writes a correction movement, so stock is adjusted down and the SKU's availability updates for other shoppers. The order line moves to a pending-substitution state. The system suggests a substitute that is in stock in this store, similar in brand, size and price, and pushes it to the customer with a short approval window. The picker continues with other lines so picking doesn't stall. If the customer approves, the substitute is reserved and picked. If they reject it or time out, the line is dropped. The final bill is computed from what was actually packed, and the difference is refunded exactly through the ledger. The packing step verifies the bag against the final line list.

7Walk me through how you would decide which dark store serves an address and what ETA to promise.Very often asked

I precompute coverage. Each store has a polygon based on road-network travel time, not radius, and that polygon is converted into H3 cells. When a lookup comes in, the location is mapped to a cell, and I return candidate stores ranked by travel time. Then I apply live filters: is the store open, does it have pickers and riders on shift, and is its current queue below a threshold. The promised ETA is queue wait plus expected pick-and-pack time plus rider travel. The travel estimate comes from recent deliveries to that cell. Under surge, I shrink coverage or show a longer ETA rather than accept orders I cannot fulfil. The checkout step repeats the check, because conditions can change between browsing and paying.

8How would you design demand forecasting and restocking for thousands of SKUs across hundreds of dark stores?Very often asked

I forecast at store-SKU-hour level, because shelves are small and peaks are sharp. The features are recent sales, day of week, holidays, weather, promotions and local events. A key detail is that hours with a stockout are treated as censored: the demand was higher than what sold. For the long tail, I pool information across similar stores or SKUs, because those series are sparse. The planner then converts the forecast into orders. It works out target stock to cover demand until the next warehouse delivery plus safety stock, then caps the result by shelf space and shelf life for perishables. I measure forecast error and stockout hours together, because over-ordering also has a cost in wastage.

9How would you decide whether two orders can be batched onto one rider?Very often asked

Both orders must come from the same store and be packed at roughly the same time. For each candidate pair, I compute the route that serves both drop points in either order. I accept the batch only if each order's predicted delivery time still meets its own promise with a safety margin. I also check rider constraints: bag capacity, weight and cold-chain items. The decision runs on a short time window, so I don't hold the first order waiting for a second. If no partner appears within a few seconds of the pack-complete prediction, the order goes solo. Batching saves rider cost, but in a 10-minute model it is opportunistic. The promise always wins over utilisation.

10Estimate the load on the tracking service and describe how you would scale it.Very often asked

I would state the assumptions explicitly. Say a city has R active riders at peak, each sending a GPS ping every few seconds. Inbound load is about R divided by the interval in writes per second, and each ping is small, around a hundred bytes. Outbound load depends on how many customers are watching: one WebSocket per active order, plus ops dashboards. I partition pings by rider_id onto Kafka or a similar log. Stateless tracking workers keep the last few points per rider in memory or Redis to smooth the location and compute the ETA. WebSocket gateways scale horizontally behind sticky routing, keyed by order_id, and a pub/sub layer fans out updates. I store raw pings cheaply for a short retention period and keep only summaries long-term.

11How do you smooth noisy GPS and keep the ETA shown to the customer stable?Very often asked

Raw GPS jumps, especially between tall buildings. I drop pings with poor reported accuracy or impossible speeds, then apply a simple filter such as a Kalman filter or exponential smoothing. I also snap the point to the road network when map data allows it. The ETA comes from the remaining route distance and recent segment speeds, adjusted for the rider's observed pace. To avoid flicker, I only push an update when the ETA changes by more than a threshold, and I allow it to rise only gradually unless there's a real event such as the rider stopping. The map marker is interpolated on the client between pings so movement looks continuous, and the server stays the source of truth.

12How would you design the payment and refund ledger so the customer is never charged for undelivered items?Very often asked

I would use a double-entry ledger in Postgres. Every money movement is an immutable entry pair, for example customer payable against order revenue. Refunds are new reversing entries, never edits. Each entry references order_id, line_id and an idempotency key, so a retried refund cannot post twice. The billable amount is derived from packed and delivered lines, not from the cart. Where the payment method supports it, I authorise at checkout and capture only the final amount after packing, so drops never reach the customer's statement. Otherwise, I capture and refund the difference automatically. A daily reconciliation matches ledger totals against gateway settlement reports, and every mismatch becomes a tracked exception.

13How does serviceability protect a store that is overloaded at peak?Very often asked

Each store publishes its live capacity signals: orders in the pick queue, active pickers, riders at or near the store, and predicted pack and dispatch times. Serviceability combines these into a load state. As load rises, it first lengthens the promise for that store, then shrinks the coverage to nearer H3 cells, and finally marks the store not serviceable. This is better than accepting orders and missing the promise. The state is cached with a short TTL and has hysteresis, so a store doesn't flap between open and closed. Checkout re-checks the state, so a user who browsed a minute ago can't place an order into a store that has since hit its limit.

14How do you keep the per-store catalog availability fresh without hammering inventory?Very often asked

The catalog listing is served from a cache keyed by store_id. It holds static data such as names, images and prices, and a separate availability bitmap or set of sellable SKUs. Inventory publishes availability-change events only when a SKU crosses zero or a low-stock threshold, not on every unit, and catalog consumers update the set. A short client TTL handles anything missed. The cache can be slightly stale, and that's acceptable because the Redis reservation at checkout is the real gate. If an item shown as available fails to reserve, the user sees a clear 'just sold out' message and the cart adjusts. I'd track that failure rate as a measure of catalog freshness.

15How do you make sure order.confirmed reaches Kafka exactly when the order is confirmed in the database?Very often asked

I'd use a transactional outbox. In the same Postgres transaction that marks the order confirmed and commits the reservation movements, I insert an outbox row with the event payload. A relay process, either a polling publisher or change data capture with something like Debezium, publishes outbox rows to Kafka and marks them sent. This avoids the dual-write problem where the database commits but publishing fails, or the reverse. Delivery is at least once, so every consumer, including the pick service, deduplicates on event_id or order_id and treats repeats as no-ops. I partition by store_id or order_id so that events for one order stay in order.

16What partition key would you use for order events in Kafka, and why?Very often asked

For the pick and dispatch pipeline, I'd partition by store_id. Each store's pick service then reads a consistent, ordered stream of its own orders, and one consumer can own one store's queue. The risk is skew: a very busy store creates a hot partition. With enough partitions and a hash spread, that's usually manageable. If not, I'd key by order_id, which still keeps the lifecycle of each order in order, and have the store service filter what it needs. Order lifecycle events such as confirmed, short, packed and delivered must keep per-order ordering, so they always share the same key. Consumers are idempotent because rebalances can replay messages.

17Sketch the core data model for orders and inventory.Very often asked

For orders: orders(order_id, user_id, store_id, status, promise_at, idempotency_key, created_at), order_lines(line_id, order_id, sku_id, qty, unit_price, status such as reserved, picked, short, substituted or dropped) and order_events for the audit trail. For inventory: stock(store_id, sku_id, on_hand, version) and inventory_movements(movement_id, store_id, sku_id, delta, type such as receive, reserve, commit, release, short or adjust, ref_id, created_at), which is append-only. For reservations: reservation_id, order_id, lines and expires_at. Redis mirrors available stock per store and SKU. Fulfilment adds pick_tasks, bags(bag_id, order_id, label) and dispatch assignments. Money lives in ledger_entries. I'd partition the large tables by store or time.

18What privacy concerns exist around customer addresses and live rider locations, and how do you handle them?Very often asked

Customer addresses and phone numbers are personal data under India's DPDP Act, so I'd collect only what delivery needs and encrypt it at rest. Riders see an address only for active orders, and calls go through masked numbers via a telephony proxy. Customer location for serviceability can be reduced to the H3 cell rather than kept as exact coordinates. A rider's live location is shared with a customer only during that order's last-mile leg, and the stream stops at delivery. Raw GPS traces get a defined short retention period and are then aggregated. Access to traces by support and ops is role-based and audited. Analytics use pseudonymous IDs.

19How do you reserve a multi-line cart atomically so you never hold half an order?Very often asked

All keys for one order belong to the same store. I give them a hash tag like {store_id} so that in Redis Cluster they live in the same slot. A Lua script then checks availability for every line and, only if all lines pass, decrements each line and records the reservation hash with an expiry, all in one atomic execution. If any line fails, nothing changes, and the script returns the lines that failed so the UI can offer to drop them. Expiry is driven by a sorted set of reservation deadlines, which a sweeper releases idempotently. A per-key TTL alone can't restore counters by itself, so it isn't enough.

20What metrics and SLOs would you define to protect the 10-minute promise?Very often asked

I'd break the promise into stages and measure each one: serviceability and checkout latency, confirm-to-pick-start, pick duration, pack-to-handover, rider wait at the store, last-mile time, and finally on-time delivery rate against the promise. Correctness SLOs matter just as much: oversell incidents, which should be zero, short-pick rate, refund accuracy, and Redis-to-Postgres drift. I'd also track rider and bag idle times, substitution acceptance, and how often stores were throttled. Dashboards slice by store and hour. Alerts fire on burn rate rather than single spikes, and a missed promise links back to the stage that consumed the budget.

21The dark store loses internet for several minutes during peak. How should the system behave?Often asked

The store apps should work offline-first. Pickers already have their pick lists cached locally, they keep scanning, and the scans queue on the device with timestamps and idempotent event IDs. When the link returns, the events sync and are deduplicated. Centrally, the heartbeat from the store stops, so serviceability marks the store not serviceable for new orders. Confirmed orders keep their status, and customers get an honest delay message. Rider handover can use a locally verifiable bag barcode with sync later. The main risk is inventory drift during the outage, so after reconnection I'd reconcile movements before reopening the store. A backup cellular link per store is worth its cost.

22How do you secure delivery confirmation with an OTP, and what fraud does it prevent?Often asked

The OTP is generated server-side per order, stored hashed, and shown only in the customer's app. The rider enters what the customer tells them. The server validates it with limited attempts and a short expiry, and it also checks that the rider's last GPS point is near the drop location. This stops riders from marking orders delivered without handing them over, and it gives evidence when a customer disputes a delivery. I'd provide a fallback for customers who can't access the app, such as a support call-back flow, and log every override. Rate limiting and alerts on riders with unusual override or failure patterns catch collusion that the OTP alone misses.

23How would you approach a capacity estimate for the order and inventory services at peak?Often asked

I'd begin with assumptions instead of invented facts: the number of stores, peak orders per store per minute, average lines per order, and browse-to-order ratios. Peak order writes equal stores times per-store peak rate. Reservation operations equal orders times lines, plus releases for abandoned carts, which can be a multiple of completed orders. Each store's throughput is physically capped by pickers and riders, so per-store load is bounded and scaling is mostly horizontal across stores. Redis handles single-key atomic operations very fast, so the real bottlenecks tend to be Postgres write volume for movements, payment callbacks and catalog reads. I'd validate the numbers with load tests at a multiple of the expected peak.

24A popular SKU in one store gets hit by thousands of checkouts in seconds. Does a single Redis key become a bottleneck?Often asked

Per store, the physical order rate is limited by pickers and riders, so even a flash sale rarely exceeds what one Redis key handles. Single-key Lua operations are fast and run in a single thread, which is exactly what gives us correctness. The bigger risks are the shard holding many busy stores and retries amplifying load. I'd spread stores across shards and apply backoff with jitter on retries. At the edge, I'd rate-limit checkout attempts for the hot SKU. If needed, I'd queue checkouts for that store so they're served in order. I would avoid splitting one SKU's stock across multiple keys. It adds complexity and creates false 'out of stock' results when one bucket empties.

25A customer cancels after picking has started. How do you handle stock and money?Often asked

Cancellation is a state transition the order service validates. Before handover, the system allows it. The pick task is stopped, and the picked items go back to their bins with a scan, which writes return movements so they become sellable again. Any remaining reservation is released. Payment follows the policy: a full refund, or an exact refund through the ledger, with authorisation voided where capture hasn't happened yet. After rider handover, the policy may block cancellation or treat it as a return. Every step is idempotent and event-driven, and dispatch is told to unassign the rider or re-batch. Perishables that can't be restocked are written off through an explicit adjustment movement.

26How do you detect and correct inventory drift between system stock and physical shelves?Often asked

Drift comes from theft, damage, mis-shelving and scanning errors. Short picks are the strongest signal. I'd run cycle counts that prioritise high-velocity SKUs and SKUs with frequent shorts, and the counts are scanned on the store app. Each count writes an adjust movement with a reason code, so it appears in the ledger. Bins found empty while the system shows stock can be frozen immediately until counted, so they aren't shown as sellable. Analytics report drift per store and per category, and expiry checks write off stale perishables. A good forecast also depends on this, because drift that hides stockouts corrupts the censored-demand signal.

27How should inbound restock receiving work, and what if the delivered quantity doesn't match the purchase order?Often asked

Inbound arrives against a transfer or purchase order from the warehouse. Store staff scan each case or unit, and then scan the bin where it's shelved. Only after the putaway scan does inventory write a receive movement and increase sellable stock. This avoids selling stock that's still in a crate at the back. Over-receipts and under-receipts are recorded against the order with reason codes and sent to the warehouse for reconciliation. Batch and expiry dates are captured for perishables, so picking can follow FEFO, first expiry first out. Damaged items are received into a non-sellable state. The planner sees the actual received quantities, not the ordered ones.

28How does the restock planner balance stockouts against waste for perishables?Often asked

For each store and SKU, the planner takes the forecast distribution for the period until the next delivery. It sets an order-up-to level based on a service-level target, limited by shelf capacity and by how much can be sold before expiry. For perishables, the target service level is lower and the expiry cap is tighter, since unsold stock is pure loss. For long-life goods, a higher service level is worth it. The warehouse delivery schedule sets the review period. Then the planner subtracts on-hand and in-transit stock and rounds to case packs. I'd review waste and stockout rates per category to tune the targets.

29How would you handle a city-level outage of your primary region?Often asked

Stores, inventory and orders are naturally partitioned by city, so I'd design the cell boundaries around cities or groups of cities to limit the blast radius. Postgres replicates to a standby in another zone or region. Redis inventory can be rebuilt from Postgres. Kafka has replicated topics. During failover, I would pause new orders for affected stores rather than risk overselling with stale stock. In-flight orders continue through the offline-capable store and rider apps. After the region recovers, I'd reconcile inventory, payment and ledger state before reopening. I'd rehearse this with game days, because a failover plan that's never been tested usually breaks in some unexpected way.

30Prices can change between browsing and checkout. How do you keep the charge consistent?Often asked

The cart stores the price version shown to the user. At checkout, the order service re-prices from the current price book for that store and compares the two. If the price changed, the user sees the new total and confirms before payment. The confirmed order then snapshots unit price, discounts and taxes on each line, and all later billing, including partial refunds, uses those snapshots, never live prices. Coupons are validated and locked at the same point. This keeps refunds exact: a dropped line refunds its own snapshotted net amount, with discount allocation computed deterministically at order time.

31How would you prevent riders from spoofing GPS to game ETAs or incentives?Sometimes asked

Fake-location apps are common, so the server shouldn't trust the client blindly. The rider app checks for mock-location flags and integrity signals using platform attestation APIs. The server rejects impossible jumps and speeds and cross-checks the reported location against events with physical anchors: the bag scan at the store and the OTP at the customer. Unusual patterns, such as consistent teleporting or deliveries completed far from the address, feed a risk score. Riders with high scores get manual review. Incentives are calculated from verified events, not raw GPS distance, so spoofing gains them little.

32How would you test this workflow for correctness before a festival peak?Sometimes asked

I'd start with property-based tests on the reservation script: under concurrent reserve, commit, release and expiry, available stock never goes negative and the total stays conserved. I'd run contract tests between the order, inventory and payment services. Then I'd load-test with realistic carts at a multiple of the expected peak, including many abandoned carts that exercise expiry. For chaos, I'd kill a Redis primary, delay payment webhooks past the TTL, duplicate Kafka messages, and cut a store's network, then confirm there are no oversells, no duplicate charges, and that reconciliation is clean. A shadow ledger check verifies every refund equals the dropped line values.

33Would you use microservices for all of these steps, or merge some? Justify the boundaries.Sometimes asked

I'd separate by data ownership and scaling profile, not by step count. Serviceability and catalog are read-heavy and cache-friendly, so they can scale independently. Order and payment orchestration share transactional needs. Inventory must own stock and reservations with strict consistency. Store operations, meaning pick and pack, run close to the store and need offline support. Dispatch and tracking handle high-frequency geo data. Forecasting and planning are batch or streaming analytics in a separate stack. I'd avoid splitting order and payment orchestration too finely early on, because sagas across many services make compensation harder. The boundaries matter most where consistency or load differ sharply.

Objective questions 33

1Which mechanism best guarantees that a retried checkout request does not create a second order?Asked almost every time
  1. AUsing Kafka with acks=all
  2. BCaching the order page in a CDN
  3. CA unique constraint on a client-supplied idempotency keyCorrect answer
  4. DIncreasing the HTTP client timeout

Why: Storing the client's idempotency key under a unique constraint lets the server detect a retry and return the original order. A longer timeout or stronger broker acks do not stop a retry from creating a duplicate.

2How do you atomically check and decrement stock for several lines of one order in Redis?Asked almost every time
  1. AUse the KEYS command to find stock keys first
  2. BWrite to Redis replicas for higher throughput
  3. CRun separate DECR commands from the app and roll back on failure
  4. DUse a Lua script on keys sharing a hash tag so they live in one slotCorrect answer

Why: A Lua script runs atomically on one node, and a shared hash tag keeps all the keys in the same cluster slot. Separate DECR calls leave a window where only part of the order is reserved.

3When a picker finds an empty bin and the customer rejects the substitute, what should happen?Asked almost every time
  1. ACharge for the item and offer a coupon later
  2. BHold the whole order until restock
  3. CDrop the line, correct inventory and refund the exact line amount via the ledgerCorrect answer
  4. DCancel the entire order automatically

Why: The workflow drops the short line, writes an inventory correction and issues an exact refund. The rest of the order continues.

4Why is H3 commonly used for serviceability lookups in quick commerce?Very often asked
  1. AIt encrypts customer locations
  2. BIt turns arbitrary polygons into uniform cells, enabling fast key-value lookups from lat-lng to storeCorrect answer
  3. CIt computes road travel time directly
  4. DIt replaces the need for a mapping API

Why: H3 indexes a location into a hexagonal cell ID. Store coverage precomputed as a set of cells then becomes a constant-time lookup instead of a point-in-polygon test on every request.

5What is the main purpose of putting a TTL on a stock reservation made at checkout?Very often asked
  1. ATo release stock automatically if payment fails or the cart is abandonedCorrect answer
  2. BTo reduce rider wait time
  3. CTo improve forecast accuracy
  4. DTo speed up picking

Why: Without a TTL, abandoned or failed checkouts would lock scarce units forever. The TTL frees them for other customers with no manual cleanup.

6What problem does the transactional outbox pattern solve for publishing order.confirmed?Very often asked
  1. AIt guarantees exactly-once processing in all consumers
  2. BIt avoids the dual write where the DB commit and the Kafka publish can divergeCorrect answer
  3. CIt compresses events to reduce Kafka storage
  4. DIt removes the need for consumers to deduplicate

Why: The event is written in the same DB transaction as the state change and relayed afterwards, so the two cannot diverge. Delivery is still at least once, so consumers must deduplicate.

7Kafka guarantees message ordering at which level?Very often asked
  1. APer consumer group
  2. BWithin a single partitionCorrect answer
  3. CAcross the whole cluster
  4. DAcross all partitions of a topic

Why: Ordering holds only within a partition. Events for one order must therefore share a partition key.

8Why is rider matching started before packing is complete?Very often asked
  1. ABecause riders cannot be batched otherwise
  2. BTo overlap the rider's travel to the store with picking and packingCorrect answer
  3. CTo reduce GPS ping frequency
  4. DTo avoid generating pick lists

Why: Overlapping the two activities removes the rider-search delay from the critical path, which matters inside a 10-minute budget.

9A batch of two orders on one rider should be accepted only when…Very often asked
  1. AThe rider has the highest rating
  2. BThe second order arrives within an hour
  3. CBoth customers live in the same H3 cell at any resolution
  4. DEach order still meets its own promise along the combined routeCorrect answer

Why: Batching is opportunistic. It is acceptable only if neither order's delivery promise is broken.

10In a double-entry ledger, how is a refund recorded?Very often asked
  1. AAs new reversing entries referencing the originalCorrect answer
  2. BBy editing the original payment entry amount
  3. CBy deleting the order row
  4. DBy updating a balance column only

Why: Ledger entries are immutable. A refund is posted as new entries, which keeps the audit trail intact.

11If Redis loses recent reservation writes after a failover, what is the safest response?Very often asked
  1. AKeep selling and fix counts at night
  2. BPause sales for affected stores and rebuild counters from PostgresCorrect answer
  3. CSet all stock counts to zero permanently
  4. DTrust the client cart quantities

Why: Postgres is the system of record. Rebuilding from it while sales are paused prevents overselling against stale counters.

12What should a Kafka consumer in the pick service do when it receives the same order.confirmed event twice?Very often asked
  1. ACreate a second pick list
  2. BCrash to force a manual check
  3. CForward the duplicate to dispatch
  4. DTreat it as a no-op using the event or order IDCorrect answer

Why: Delivery is at least once, so consumers must be idempotent.

13What does the rider's bag scan at handover primarily establish?Very often asked
  1. AThe picker's shift end
  2. BA verified start of the last-mile leg and chain of custodyCorrect answer
  3. CThe customer's payment authorisation
  4. DThe store's restock quantity

Why: The scan ties the specific bag to the rider and starts the last-mile tracking.

14Delivery OTP verification mainly protects against…Very often asked
  1. APicker errors in the store
  2. BRiders marking orders delivered without handing them overCorrect answer
  3. COverselling during peak
  4. DDuplicate orders on retry

Why: The OTP comes from the customer, which proves the handover happened.

15Why sort the pick list by bin location?Very often asked
  1. ATo match the customer's cart order
  2. BTo simplify payment
  3. CTo minimise the picker's walking pathCorrect answer
  4. DTo randomise picker workload

Why: A path-ordered list shortens pick time, which is a large part of the 10-minute budget.

16Which append-only table best supports auditing and reconciling stock?Very often asked
  1. AOrder status history
  2. Binventory_movements with typed deltas and referencesCorrect answer
  3. CA single stock row overwritten on each change
  4. DRedis keys only

Why: Typed movements such as reserve, commit, release, short and receive give a full, replayable history.

17When training a demand model, how should hours where an item was out of stock be treated…Often asked
  1. AReplaced with the store's average for all SKUs
  2. BAs zero demand
  3. CAs censored demand where true demand was at least what soldCorrect answer
  4. DDeleted along with the whole day

Why: Sales during a stockout understate true demand. Treating those hours as zero biases the forecast downward and causes repeated stockouts of popular items.

18Which payment approach most directly avoids charging for items that are later dropped?Often asked
  1. ACharge on delivery for all items regardless of shorts
  2. BUse a stored-value wallet only
  3. CAuthorise at checkout and capture the final packed amount where the method supports itCorrect answer
  4. DCapture the full cart amount immediately

Why: Capturing only the final amount means dropped items never get charged. For methods without separate authorisation, an exact refund serves as the fallback.

19Why use a sorted set of expiry times instead of relying only on per-key TTL to release reservations?Often asked
  1. ATTLs are not supported in Redis Cluster
  2. BA key expiring does not restore the stock counter on its ownCorrect answer
  3. CSorted sets make reservations permanent
  4. DSorted sets use less memory than strings

Why: When a reservation key expires, the decremented availability counter is not added back. A sweeper driven by deadlines releases the stock explicitly and idempotently.

20Why does the catalog show only SKUs the specific store can sell right now?Often asked
  1. ATo reduce failed reservations and avoid promising stock the store lacksCorrect answer
  2. BBecause H3 requires it
  3. CTo avoid storing prices
  4. DTo skip checkout re-validation

Why: Showing only sellable SKUs cuts checkout failures. The reservation still acts as the final gate.

21Why does checkout re-check serviceability even though it was checked at app open?Often asked
  1. ATo recompute the forecast
  2. BBecause H3 cells expire
  3. CTo refresh the user's login token
  4. DStore load, open status or the user's location may have changed since browsingCorrect answer

Why: Serviceability is time-sensitive. An overloaded or closed store must not receive new orders.

22Which technique best reduces jitter in live rider location shown to customers?Often asked
  1. AShowing only the destination
  2. BFiltering inaccurate points and smoothing, e.g., with a Kalman filterCorrect answer
  3. CRounding coordinates to one decimal place
  4. DSending pings less often

Why: Filtering and smoothing remove GPS noise but keep real movement. Coarse rounding destroys accuracy.

23Which protocol is used in this workflow to push live tracking updates to the customer app?Often asked
  1. AFTP
  2. BBatch email digests
  3. CWebSocketCorrect answer
  4. DSMTP

Why: A persistent WebSocket connection lets the server push ETA and location updates with low latency.

24When a store becomes overloaded, which response best protects the promise?Often asked
  1. ADisable payments globally
  2. BLengthen the promise, shrink coverage, then mark the store not serviceableCorrect answer
  3. CRoute orders to stores in another city
  4. DAccept all orders and add apology messages

Why: Gradual throttling keeps accepted orders within a promise the store can actually meet.

25Why add hysteresis to a store's open or closed load state?Often asked
  1. ATo stop the store flapping between serviceable and not serviceableCorrect answer
  2. BTo speed up checkout
  3. CTo encrypt the state
  4. DTo make H3 lookups faster

Why: Separate thresholds for closing and reopening prevent rapid toggling near the limit.

26When does inbound stock become sellable in this workflow?Often asked
  1. AWhen the truck leaves the warehouse
  2. BWhen the purchase order is created
  3. CWhen the forecast predicts demand
  4. DAfter it is scanned on receipt and inventory is updatedCorrect answer

Why: Only scanned, recorded stock is sellable, which prevents selling items that are not on the shelf.

27For perishables, what is the main extra constraint the restock planner applies compared with long-life goods?Often asked
  1. AIgnoring the delivery schedule
  2. BAlways targeting a 100% service level
  3. CLarger case packs
  4. DA cap based on how much can sell before expiryCorrect answer

Why: Unsold perishables become waste, so shelf life limits the order quantity.

28Which picking rule fits perishables best?Often asked
  1. AFEFO (first expiry, first out)Correct answer
  2. BHighest price first
  3. CLIFO
  4. DRandom bin choice

Why: Picking the earliest expiry first reduces waste and prevents customers from receiving short-dated stock.

29Under India's DPDP Act, which practice best fits handling of customer delivery data?Often asked
  1. AEmail order details unencrypted
  2. BShare addresses with all riders in the city
  3. CCollect only what delivery needs, mask phone numbers and limit retentionCorrect answer
  4. DStore raw GPS traces forever for analytics

Why: Data minimisation, masking and limited retention match the purpose-limitation principles of the Act.

30A payment success webhook arrives after the reservation expired and the stock is gone. What is correct?Often asked
  1. ARe-reserve; fulfil the available lines and refund the rest exactlyCorrect answer
  2. BAsk the picker to find similar stock without telling the customer
  3. CShip the item anyway
  4. DIgnore the payment

Why: The system must never fulfil stock it lacks and must never keep money for undelivered items.

31Which partition key keeps each store's pick queue ordered and owned by one consumer?Sometimes asked
  1. Auser_id
  2. Bsku_id
  3. CRandom UUID per message
  4. Dstore_idCorrect answer

Why: Keying by store_id routes all of a store's orders to one partition in order. The trade-off is a possible hot spot.

32What is the main risk of splitting one SKU's stock across several Redis keys to spread load?Sometimes asked
  1. ARedis cannot store integers
  2. BLua scripts stop working
  3. CTTL becomes mandatory
  4. DFalse out-of-stock results when one bucket empties while others hold stockCorrect answer

Why: Split counters fragment the stock and make reservations more complex, which can produce false out-of-stock results.

33In this workflow, which signal is the strongest indicator of inventory drift at a store?Sometimes asked
  1. ARider ratings
  2. BNumber of app opens
  3. CRate of short picks from empty binsCorrect answer
  4. DAverage order value

Why: A short pick means the system believed stock existed that was not physically there.

Track your progress through every blueprint in your dashboard.

Start learning