View
CASE STUDY 02 / OPERATIONS, LOGISTICS

Order Management System

One console for orders from six channels, the riders carrying them, and the cash coming back, shipping with Lucrum POS.

ROLE Product design, UI system, front-end
YEAR 2026
SCOPE Five operational modules, data contract, dashboard build
STACK Vue 3, Vuetify, Frappe/ERPNext, Go, Copilot
The orders analytics tab: revenue, order count, average order value and completion rate for the week, above a breakdown of orders by channel and a revenue comparison across four branches

The problem

01 / 09

A multi-branch food business does not receive orders in one place. They arrive by WhatsApp, from the Android and iOS apps, off the website, through Instagram and Facebook, over the phone, and from someone standing at the counter.

Each one still has to reach the right kitchen, get made, get picked up by a rider who is already carrying two other bags, and come back at the end of the shift as cash that has to be counted and settled.

01Six front doorsEvery channel had its own queue and its own idea of what an order looked like.
02Blind dispatchNo shared view of which rider was loaded, near, or idle at the moment an order was ready.
03Cash on trustRiders collect cash all shift. Without a ledger, settlement is a conversation, not a record.

The dashboard exists to collapse those three into one screen a branch manager can run a shift from, and to make the money side auditable rather than remembered.

Scope and role

02 / 09

Sole designer on this, and the person who built the front end. The brief was five operational modules behind one rail. What it actually required was settling what the product was before anyone wrote a component, then moving that into the framework ERPNext could host without losing the detail in transit.

ROLE Design and front-end, both Product design across all five modules, the UI system, and the Vue build of the dashboard layer.
METHOD Prototype first, then port A single-file React prototype (every screen, realistic data) written to settle arguments, never to ship. Built alongside GitHub Copilot in VS Code.
DELIVERED Five modules and a contract Orders, riders, the AI agent, WhatsApp and the social channels, plus the typed file both halves were built against.

The contract is the part worth keeping. Field names, enum values and nullability were decided once, in writing, before either half existed, which turned the port into implementation rather than reverse-engineering, and is why the two sides never drifted apart.

System architecture

03 / 09

The system is deliberately split in two, because the two halves have opposite requirements. Records and money belong in the ERP, where they are auditable and where accounting already lives. Taking an order does not: a customer waiting in a WhatsApp thread cannot wait on a document write.

ERPNEXT · PYTHON

The system of record.

Orders, riders, payment entries, WhatsApp templates and campaigns, social data. Everything that has to reconcile, and everything the finance team already understands. MariaDB underneath.
GO · FIBER

The ordering hot path.

Menu, cart pricing, order creation, status tracking: the four calls that happen while a customer is waiting. Menu served from Redis, order state in PostgreSQL.
WHY SPLIT · AND WHAT IT COST Latency and auditability pull in opposite directions An ERP write is the right home for a settlement and the wrong home for a menu lookup during a dinner rush. Splitting them let each side be judged on its own terms, and cost us a single source of truth. Two systems can drift, which is the whole reason the contract below had to be written before either half existed.
THE SEAM One contract, written before either side A single typed file defined every interface, every endpoint response, and the ERPNext doctype fields behind them, so the two halves could be built against the same idea of an order.

The operations dashboard

04 / 09

Five modules behind one persistent rail: orders, riders, the AI chat agent, WhatsApp, and the social channels. Each has an Operations view for the person running the shift and an Intelligence view for the person reading the week.

The screens below run on seeded demo data: real customer records are not shown.

Orders & riders

Orders operations view: a filterable queue showing order number and type, verified state, customer name, phone and address, originating channel, branch, an elapsed-time bar against a 45 minute target, and rider with ETA
Every channel in one queue, with the clock running
Riders operations view: a roster filtered by all, active, idle and offline, with a selected rider's trips beside an OpenStreetMap view of Lahore showing the rider's last known position and the numbered delivery stops still on their round
Roster, load, and the round in progress

Acting on one order

The order details panel over the queue: a five-stage tracker from verification through branch, preparation and rider to delivered; three item lines with codes, descriptions and prices; a money summary of subtotal, sixteen per cent GST, discount and total; and panels for order, branch, customer and rider with transfer and cancel actions
Every decision about one order, one panel

A rider's round, and their cash

A selected rider's detail pane: status Busy, today's trip count, and a delivery trips list showing one in-transit trip of three stops above a collapsed group of completed trips
One rider, three drops still to make
Rider financials view: totals for collected, remitted, outstanding and overdue, above a per-rider ledger listing collections and settlements by date with reference, linked order and notes
Cash in, cash settled, per rider

Conversational orders

The AI chat agent view: a list of conversations filtered by channel, status and sentiment, with an open thread showing a customer asking about a menu item in mixed Urdu and English and the agent answering with prices and an order link
The agent answers in the language the customer used
The WhatsApp send tab: a message template picker, a single-or-bulk recipient toggle, a phone number field and a send button, beside a phone preview panel waiting for a template to be chosen
Templates go out singly or in bulk

The queue is the piece that earns its place. Each row carries the one thing a manager acts on: an elapsed bar counting against the delivery target, turning red before anyone has to ask. Assignment happens inline, in the row, without opening anything.

Opening a row is for everything the queue deliberately leaves out: the item lines, the money broken down to the tax, and the two actions that warrant a second thought: transferring the order to another branch, or cancelling it outright.

The assignment control changed most. It started as a picker (choose a rider, done) because the first version of this queue assumed one order per rider. Riders carry three. Once that was clear the control had to show load rather than names, and every screen that named a rider had to admit how much they were already holding.

Rider financials

05 / 09

This was the least glamorous part of the system and the one that mattered most. A rider on a cash-on-delivery round is holding the company's money for the length of a shift. The design problem is not a screen: it is making an informal, trust-based process leave a record without slowing anyone down.

01CollectedEvery cash-on-delivery order becomes a line, tied to the order that produced it.
02RemittedSettlements recorded against a reference: JazzCash, bank transfer, or cash to the branch.
03OutstandingThe running difference. What the rider is still holding, visible before the shift ends.
04OverdueOutstanding past its settlement window: the only number that should ever prompt a conversation.

Collections are green and additive, settlements red and subtractive, so the ledger reads like a bank statement rather than a report. The four totals sit above it because the question a manager actually asks is "who owes me money right now", not "show me all transactions".

The four cash totals across the top of the rider financials tab: total collected, total remitted, outstanding and overdue, each in its own colour, above an empty ledger prompting the user to select a rider
Four numbers, before any rider is chosen

Overdue is the only one coloured as an alarm. The other three are facts; that one is a task.

From prototype to production

06 / 09

The dashboard existed first as a single-file React prototype: just under four thousand lines, with every screen and a full set of realistic sample data. It was never meant to ship. It was meant to settle what the thing was before anyone wrote a component.

The production build is Vue 3 and Vuetify, because that is what the ERPNext front end could host. Porting between two frameworks is where detail normally gets quietly lost, so the port was done against a written contract rather than by reading the prototype.

THE CONTRACT

One typed file as the source of truth.

Every data model, every API endpoint's response shape, and the ERPNext doctype fields behind each one, written down before the port so both the Python and the Vue side had the same definition of an order, a rider and a conversation.
WHAT IT BOUGHT Port by reading the old code Port by implementing the contract Field names, enum values and nullability were decided once. The prototype became a visual reference instead of a spec to reverse-engineer.

Shipping discipline

07 / 09

An operations dashboard fails quietly. Nobody files a bug when a number is subtly wrong: they just stop trusting the screen and go back to WhatsApp. So the release process was written down alongside the code.

0141 automated testsAcross nine classes, plus a manual checklist written per tab, so each module is signed off against its own behaviour rather than a generic pass.
02A five-minute smoke testShort enough to actually run daily. The bar was that it gets used, not that it is exhaustive.
03A debugging guideA diagnosis flowchart from the symptoms that actually occur (blank screen, missing component, page not found) with the cause under each.

The WhatsApp integration got its own guide, covering Meta Business setup, webhook registration, template submission, and the WebRTC calling layer that lets an agent take a call from inside the dashboard when the AI agent escalates.

What shipped

08 / 09
DISTRIBUTION

It ships with the point of sale, not on its own.

The dashboard is not a standalone product a customer buys: it is the operations layer that arrives with Lucrum POS, in use across multiple national QSR chains. Every branch running that POS gets this screen, which is also why it never had a public URL to link to.
30,000+ Transactions through the point of sale this ships with. Lucrum's figure, not this module's.
41 Automated tests across nine classes, from phone-number normalisation to role permissions

The messaging layer is the part that went furthest. It talks to Meta's Cloud API directly: fourteen endpoints covering template submission, bulk sends with rate limiting, webhook verification, and the call handoff when the AI agent escalates to a human.

Reflection

09 / 09

I designed the queue around a rider carrying one order, and that was wrong: they carry three. Fixing it late meant the assignment control had to stop being a picker and start being a load decision, and every screen showing a rider had to admit they held more than one. The written contract saved the port; it did not save me from that.

Muhammad Bin Saif, Product Designer
NEXT PROJECT Dagwood