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

Six order channels, one screen a branch manager runs a shift from.

Ships with the point of sale that has processed more than 30,000 transactions. The same operations layer is now public as Zentallio for food and beverage.

The problem

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.

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.

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
Six channels, one revenue picture.
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.

Scope and role

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.

System architecture

Money and permissions live in ERPNext, 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.

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 price of the split and worth naming rather than hiding.

What kept them honest was writing the contract first. Every interface, every endpoint response, and the ERPNext doctype fields behind them were settled before either half existed, which turned the port into implementation rather than reverse-engineering.

An order detail view: line items priced to the tax, customer and branch, and the actions available on the order
One order, resolved to the tax.
Hot pathGo, in frontMenu, cart pricing, order creation, status tracking: the four calls that happen while a customer is waiting.
System of recordFrappe and ERPNextSettlement, permissions and reporting, where an audit trail already exists and accounting can reach it.
The seamOne typed contractA single file naming every interface, every endpoint response, and the doctype fields behind each one.

The operations dashboard

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

The queue is the screen a branch manager lives in. Each row carries the one thing a manager acts on: an elapsed bar counting against the delivery target, turning red before a customer has to ask.

Opening a row gives the whole order 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, so it became a view of who is loaded, who is near, and who is idle.

The live orders queue: rows of orders with customer, branch and rider detail, each carrying an elapsed time bar against its delivery target
The elapsed bar is the row's argument.
A Sandy conversation thread showing the customer messages, the assistant's replies and the order it produced
An order that began as a WhatsApp thread.

Rider financials

A rider collects cash all shift, which means they are 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 the person down or implying they are not trusted.

So the ledger is built from what already happens. A trip is logged, cash is collected, a settlement is recorded against a reference, and what is left outstanding is the only number that should ever start a conversation.

The rider financials view: per rider, the trips completed, the cash collected, what has been settled and what is still outstanding
What a rider owes, without an argument.
A cash summary strip totalling collected, settled and outstanding amounts across all riders for the shift
The shift, totalled.
CollectedCash taken on the doorLogged against the trip that produced it, so the total is a consequence rather than a claim.
SettledHanded back, with a referenceSettlements recorded against a reference: JazzCash, bank transfer, or cash to the branch.
OverdueThe only number worth a callOutstanding past its settlement window: the only number that should ever prompt a conversation.

From prototype to production

The dashboard existed first as a single-file React prototype: just under four thousand lines, with every screen and a full set of realistic data. It was written to settle arguments, never to ship, and it did that job before a single production component existed.

The port was to Vue 3 and Vuetify inside Frappe, which is what ERPNext can host. What made that survivable was the contract: every interface, every 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 idea of an order.

The riders operations view: every rider with their current load, zone and status for the shift
The rider view, ported screen for screen.

Just under four thousand lines of prototype, written to be thrown away.

Shipping discipline

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 checks are built around the numbers rather than around the pixels.

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, and webhook delivery receipts.

The WhatsApp send screen: an approved template, the audience it will go to, and the rate limit that governs the send
A send is a template, an audience and a rate limit.
A rider's trip history: each delivery with its branch, time and the cash it produced
Every trip leaves a row behind it.
Tests41 across nine classesFrom phone-number normalisation through status flow and rate limiting to role checks on the restricted endpoints.
ToolingA diagnosis flowchartA diagnosis flowchart from the symptoms that actually occur (blank screen, missing component, page not found) with the cause under each.
Order timingA daily smoke testFive minutes, run before anything goes out, covering the paths a branch manager touches every shift.

What shipped

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. The same layer is now public as Zentallio for food and beverage.

What I got wrong

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

Open to product design roles and selective consulting.

binsaif2@gmail.com
© 2026 Muhammad Bin Saif Designed and built with Claude Code Client work remains the property of the respective companies and is shown here for portfolio review. Not licensed for reuse.