A food-delivery platform serving four user classes from one codebase — customers, restaurant owners, delivery partners and platform admins. A React and TypeScript front end over a Django 5 / DRF backend of sixteen domain apps, with live PhonePe payments, an explicit order state machine, WebSocket tracking, and a server-to-server integration with the DineGuru restaurant POS.
A consumer food-delivery platform — customer app, restaurant API, rider layer and operator console on one Django backend.
Server-side truth for anything that matters
Prices, taxes, the dine-in charge waiver, payment amounts, rider-assignment signals and delivery-time limits are all enforced in the domain layer rather than the interface. The rule is uniform: if getting it wrong costs money or misleads a customer, the server decides and the client is told. An interface can only ever hide an option; it cannot stop a request.
One state machine, one payment gate
Every order moves through an explicit adjacency map — placed, confirmed, preparing, ready, picked up, out for delivery, delivered — and an illegal move raises a typed conflict carrying the attempted transition rather than silently doing nothing. A prepaid order cannot enter the fulfilment pipeline until its payment is settled, and because that check lives at the single transition point it holds for every actor alike: the partner portal, the POS integration and the payment webhook.
Money discipline in the payment path
Amounts are never accepted from the client — the create-payment endpoint takes an order id and computes the figure from the order’s own immutable total. The webhook logs the raw body before parsing it, verifies authentication, independently re-reads the gateway’s status API outside any transaction, then locks the row and re-checks under the lock; an amount mismatch flags for manual review instead of quietly succeeding. No database lock is ever held across a network call, and a refund commits its pending state before the call goes out.
A transactional outbox, not fire-and-forget
Cross-boundary events are written to an outbox table inside the same transaction as the state change that caused them, then drained by a scheduled worker with attempt counts, backoff and dead-lettering. That is what makes “the order was confirmed” and “the restaurant was told” either both true or both false, instead of a notification that fires just before a rollback.
The POS integration is an API-key boundary
DineGuru drives day-to-day restaurant operation over a separate versioned surface authenticated by an API key and scoped entirely to that key’s restaurant. Identity fields are read-only across it, so a restaurant cannot rename itself or clear a platform suspension; and the key lives encrypted on DineGuru’s server and never reaches a browser, which is also why no cross-origin surface had to be opened here.
A kill switch that cannot lock you out
Platform maintenance is a single config flag read by middleware mounted ahead of every view, returning a structured 503 with a Retry-After. The exempt paths are deliberately narrow — the admin control API, health checks, schema docs — so the switch that turns maintenance off is never behind the maintenance it turned on.
Live order tracking
A real state machine, an ETA, and a rider icon that appears only when the server reports an assignment — never a time-based guess.
Handover OTP
A hashed six-digit code verified at the door, with lockout after repeated wrong entries. One OTP system shared with the POS, not two.
Doorstep collection
A cash order can be collected on a platform payment QR, reusing the entire prepaid money path through a new entry point.
Offers and surge
A coupon rule engine with per-user and total caps, restaurant scoping, date windows, referral codes and surge windows.
Support with context
Tickets routed server-side to ops, finance or rider queues, with the payment reference auto-attached so finance never has to look it up.
Operator console
One read ledger over every order across all restaurants, two kinds of restaurant hold with different blast radius, and the platform switch.
Status: Live in production
Domain apps: Sixteen
Payments: PhonePe V2
Divyakush Punjabi