quick commerce delivery system

Quick Commerce Order & Delivery Flow

A step-by-step logic guide. Read it top to bottom and you can build the whole order-to-delivery part. No code here, only the thinking.

1. The Big Picture

Q: What are we building?
The order and delivery engine of a quick commerce app, like Zepto, Blinkit, Swiggy Instamart, Zomato or Flipkart Minutes.

Q: Why is quick commerce different from normal e-commerce?
The user wants the order immediately. The promise is delivery in about an hour or less. Every minute wasted anywhere in the flow hurts that promise.

Q: What problem are we solving?
The user should never get food, groceries or any product late. The system must find a delivery person fast, and must never leave an order stuck without anyone looking at it.

Q: Who should find the delivery person, the vendor or the system?
The system. The vendor (for example a restaurant owner) is busy cooking and serving his own customers. He cannot also call drivers. Finding a driver is our app's job, not his.

2. Who Is Involved

Role What they do in this flow
User (Customer) Places the order, receives the delivery OTP, gives it to the driver at the door
Vendor Receives the order, accepts or rejects it, prepares it, gets the pickup OTP, gives it to the driver
Driver Receives delivery requests, accepts one, picks up, delivers
Admin Sets the rules (radius, timeouts), receives alerts when the system cannot find a driver, assigns a driver manually
System (Backend) Runs the logic, filters drivers, sends notifications, tracks every status

3. Two Kinds of Status (Keep Them Separate)

An order has two different lives. Do not mix them into one column.

Order status answers: where is the order in its journey?

Order Status Meaning
PLACED User created the order
VENDOR_ACCEPTED Vendor said yes
VENDOR_REJECTED Vendor said no (end of the line)
PREPARING Vendor is making or packing it
READY Order is ready to be picked up
PICKED_UP Driver collected it (pickup OTP verified)
OUT_FOR_DELIVERY Driver is travelling to the user
DELIVERED User's OTP verified (end of the line)
CANCELLED Stopped by user, vendor or admin

Dispatch status answers: how is the search for a driver going?

Dispatch Status Meaning
NOT_STARTED Vendor has not accepted yet
SEARCHING System is looking for drivers nearby
REQUEST_SENT Nearby drivers have been notified
ASSIGNED One driver accepted
NEEDS_ADMIN No driver found in time, admin must assign
MANUALLY_ASSIGNED Admin picked a driver

Q: Why two separate statuses?
Because "searching for a driver" and "being prepared by the vendor" happen at the same time. One status column cannot say both.

Also keep a status history. Every time any status changes, save one row: which order, old status, new status, who did it (user, vendor, driver, admin, system) and when. This is your proof when there is a dispute or refund.

4. The Settings Admin Controls

Nothing below should be fixed inside the code. The admin changes them from a settings screen.

Setting Example value Why it exists
Driver search radius 3 to 5 km (quick commerce), can be raised for bigger areas Decides which drivers are "near enough"
Wait time for driver response 60 to 90 seconds per search round Keeps the 1-hour promise
Total search time before admin alert 3 to 4 minutes Order must not sit unattended
Max wrong OTP attempts 3 to 5 Stops guessing
OTP expiry time A few minutes after it is created Old OTPs become useless
Vendor response time limit 2 to 3 minutes Auto-cancels if the vendor ignores the order
Driver location freshness limit 30 to 60 seconds Ignores drivers whose location is outdated

5. The Main Flow

Step 1: User places an order

Q: What happens first?
The user places an order. The system saves it with order status PLACED and dispatch status NOT_STARTED.

Q: What does the order need to carry?
User, vendor, items, delivery address with the user's latitude and longitude, and the time it was placed.

Step 2: The order reaches the vendor

Q: Who gets the order first?
The vendor. His app shows it in his order list, and the system also sends him a push notification (FCM, Firebase Cloud Messaging).

Q: Is the push notification enough?
No. Notifications can be late or lost. Treat the notification as a wake-up call only. The order is always saved in the database first, and the vendor's app should also load pending orders from the backend whenever it opens or refreshes. The database is the truth, the notification is just a nudge.

Step 3: The vendor accepts or rejects

Q: What if the vendor is closed, out of stock or too busy?
He can reject the order. The order becomes VENDOR_REJECTED, the user is told, and nothing else happens.

Q: What if the vendor does not respond at all?
After the vendor response time limit, the system cancels the order and tells the user. A silent vendor must not block the user.

Q: When does the driver search start?
As soon as the vendor accepts. Order status becomes VENDOR_ACCEPTED, dispatch status becomes SEARCHING.

Q: Should we wait for the food to be fully ready before looking for a driver?
No, that wastes time. Start the search at acceptance. The vendor tells the app a prep time (for example 10 minutes). The idea is that the driver arrives around the time the order is ready, not 15 minutes too early and not 15 minutes too late.

Step 4: Finding the right drivers

Q: Imagine the app has 10 drivers but only 3 are near this vendor. Do we notify all 10?
No. Notifying everyone annoys drivers who are far away and floods their phones. We notify only nearby, suitable drivers.

Q: How does the system know where the vendor and drivers are?

Who Location source Changes?
Vendor The vendor's address, saved with latitude and longitude when the store is created (the frontend sends them to the backend at that moment) No, fixed
Driver The driver's app keeps sending the current latitude and longitude to the backend every few seconds while the driver is online Yes, always moving

Q: Why can't driver location be saved once, like the vendor's?
Because a driver moves. A location saved at signup is useless. Only the latest location counts.

Q: What filters decide who gets the request?
All of these must be true:

Check Question the system asks
1. Online Is the driver switched on and available for work?
2. Free Is the driver not already carrying another order?
3. Fresh location Was his location updated within the freshness limit?
4. Close enough Is he within the admin's radius from the vendor?

Q: How do we measure "close enough"?
With the Haversine formula. It takes two latitude/longitude pairs (vendor and driver) and returns the straight-line distance in km. The system does this for every online and free driver, then keeps only those at or under the radius.

Q: Example?
Radius is set to 5 km. Ten drivers are online. Haversine says: Driver A 1.2 km, B 3.8 km, C 4.6 km, the other seven are 7 to 15 km. Only A, B and C pass.

Q: Is straight-line distance always accurate?
No. Roads, flyovers and one-way streets make the real route longer. For a first version this is acceptable. Later you can use a maps routing service to improve accuracy on the short list.

Step 5: Sending the delivery request

Q: What happens with the 3 selected drivers?
They all get a "new delivery request" notification, and the request also appears in their request list in the app (same rule as before: database is truth, notification is a nudge).

Q: What does the driver see?
Pickup place, distance to the vendor, drop area, and the earning. Dispatch status becomes REQUEST_SENT.

Q: What if the first round gets no response?
Wait the configured response time (for example 60 to 90 seconds). If nobody accepts, the system can repeat once with a wider radius if the admin allowed it. Then it moves to the admin fallback.

Step 6: A driver accepts, first one wins

Q: What if two drivers tap Accept at nearly the same moment?
Only one may win. The rule: "assign this order to this driver only if the order still has no driver." The check and the assignment must happen as one single, indivisible step in the database. If the order is already taken, the second driver sees "This order was already taken."

Q: Why is this important?
Without it, two drivers could both think the order is theirs and both drive to the vendor.

Q: What happens after the winner is decided?

  • Dispatch status becomes ASSIGNED
  • The order is added to that driver's order list
  • The other drivers' requests disappear from their screens
  • The driver is now marked "busy"
  • User and vendor are told a driver is coming

Step 7: When no driver can be found

Q: What if nobody is within the radius?
The system alerts the admin right away. Dispatch status becomes NEEDS_ADMIN.

Q: What if drivers were within the radius, were notified, but nobody accepted before the time ran out?
Same result. The admin gets the alert.

Q: What does the admin do?
Chooses any driver, no matter where that driver is, and presses Assign. The order is put into that driver's order list and dispatch status becomes MANUALLY_ASSIGNED.

Q: How does the admin actually get that driver to go?
That is the admin's own business: a phone call, WhatsApp, or their own logistics. Our system does not need to handle it. Once the admin assigns, it is the app owner's responsibility that the order is delivered.

Q: Where must the timer for the "wait, then alert admin" live?
In something that survives a server restart (a saved job in a job queue or a saved "deadline time" in the database). A timer that lives only in the server's memory disappears when the server restarts, and the order would be forgotten forever.

Step 8: Pickup, the vendor OTP

Q: Why do we need an OTP at pickup?
It proves the right driver met the right vendor and took the right order. Nobody can claim "I never gave it" or "I never got it."

Q: Who sees the pickup OTP?
Only the vendor, inside the vendor's app. The driver must not see it in advance.

Q: When is the vendor's OTP created?
When a driver is assigned (either by accepting or by admin).

Q: What does the driver do?
Goes to the vendor, status can show "arrived at vendor," and asks for the product. The vendor tells the OTP. The driver types it into his app.

Q: What happens when the OTP is correct?
Order status becomes PICKED_UP, then OUT_FOR_DELIVERY.

Q: What if the OTP is wrong?
The driver may try only the allowed number of times. After that, the app blocks further tries and the admin is alerted to resolve it.

Step 9: Delivery, the user OTP

Q: When is the user's OTP created and shown?
When the order becomes OUT_FOR_DELIVERY. It is shown only in the user's app.

Q: What does the driver do?
Reaches the user, hands over the product, and asks for the OTP. The user tells it. The driver types it into his app.

Q: What happens when it is correct?
Order status becomes DELIVERED. The driver becomes free again and can receive new requests.

Q: What if the user is not reachable or refuses to share the OTP?
The driver reports "customer not available." The admin is alerted and decides (wait, retry, return, cancel). Never let the driver mark an order delivered without an OTP or an admin decision.

6. OTP Rules (Both OTPs)

Rule Why
Pickup OTP goes only to the vendor, delivery OTP only to the user The driver must not know them beforehand
Each OTP is linked to one order It cannot be reused on another order
Each OTP expires after a short time Old OTPs become useless
Limited wrong attempts Stops guessing
Store OTPs in a protected form, not as plain readable text If the database leaks, OTPs stay safe
Every successful and failed attempt is recorded Needed for disputes

7. What If Something Goes Wrong

Situation What the system does
Vendor rejects Order → VENDOR_REJECTED, tell the user
Vendor never responds Auto-cancel after the time limit, tell the user
User cancels before the driver picks up Allowed, order → CANCELLED, free the driver if one was assigned
User cancels after pickup Not allowed in the normal flow, only admin can decide
Driver cancels after accepting Remove him from the order, put the order back into driver search, alert admin if it keeps happening
Driver goes offline mid-order Alert admin, who can reassign
Vendor takes too long to prepare Alert admin and inform the driver and user of the delay
Wrong OTP too many times Block further tries, alert admin
Server restarts during a search Search continues because the deadline was saved, not kept only in memory
Notification not delivered Apps also load pending requests from the backend, so nothing is lost

8. Refunds

Covered later as a separate section. Because every status change is already recorded in the history table, refunds will be able to look at exactly what happened and when.

9. Suggested Build Order for a Beginner

Order Build this Why this order
1 Roles and login (user, vendor, driver, admin) Everything depends on knowing who is who
2 Vendor store with saved latitude and longitude Needed for distance
3 Driver online/offline toggle and live location updates Needed for the driver filter
4 Order creation and the two statuses plus history table The backbone of everything
5 Vendor accept/reject screen Starts the dispatch
6 Admin settings screen (radius, timeouts, OTP limits) Rules must be configurable before dispatch logic uses them
7 Driver filter (online, free, fresh location, Haversine within radius) The core of the dispatch
8 Delivery request list for drivers and the "first accept wins" rule The race-safe assignment
9 Timeout and admin alert, then manual assign The safety net
10 Pickup OTP First handshake
11 Delivery OTP Second handshake
12 Cancellation and failure cases from section 7 Makes it real-world ready

10. Quick Glossary

Term Plain meaning
FCM Google's push notification service. It taps the phone to say "something new is waiting"
Haversine A formula that gives the straight-line distance in km between two latitude/longitude points
Radius The maximum distance from the vendor within which drivers are considered
Dispatch The process of finding and assigning a driver
OTP A short one-time code used as proof of a handoff
Job queue A saved to-do list for the server, so scheduled tasks survive restarts
Source of truth The place (the database) that is always right when other things disagree