azyware
Regional last-mile logistics operator ■ NOV 2025

A dispatch platform and offline-first driver app for a last-mile operator

Replaced a phone-and-WhatsApp dispatch process with a real-time order and dispatch platform, an offline-first React Native driver app and an AI agent that handles delivery exceptions with customers.

Context

The client delivers for e-commerce sellers and local retailers across several Indian cities: same-day and next-day parcels from hubs to doorsteps. When we met them, dispatch worked the way it does in most operators of that size. Hub managers assigned parcels to drivers on a spreadsheet each morning, drivers navigated with a consumer maps app and reported progress in WhatsApp groups, and customer service found out about a delayed parcel when the customer called. The operation was profitable and growing, and the founders could see that the process would not survive the next doubling of volume.

The problem to solve

Three things had to exist. A dispatch platform where orders arrive from sellers' systems, are batched and assigned with routing that respects real constraints, and where the operations room can see every parcel and driver in real time. A driver app that works when connectivity does not, because a basement loading bay or a rural stretch is exactly where updates matter most. And a way to handle the flood of delivery exceptions, address not found, customer unavailable, damaged parcel, without every one of them becoming a phone call to a hub manager.

Approach

We scoped the platform as a product with three surfaces, operations, driver and seller, on a shared backend, rather than as three separate projects. Because the business was live and growing, everything had to run beside the existing process and replace it city by city. The first two weeks with the operations team produced a map of the actual dispatch rules, which were more nuanced than anyone had written down: certain sellers' parcels never went to new drivers, certain areas were only served before a cut-off time, and cash-on-delivery parcels had their own reconciliation rules.

  • Order intake API and seller portal, with integrations to the two seller platforms that produced most volume and a CSV path for the rest.
  • Dispatch engine that batches parcels by area and time window, proposes assignments with routing that honours the rules, and lets hub managers override with a drag on the map.
  • Real-time operations view over Socket.io: every driver's position, every parcel's state, exceptions surfaced as they happen.
  • React Native driver app, offline-first: the day's route, navigation, proof of delivery with photo and signature, cash collection, all queued locally and synced when connectivity returns, with conflict handling designed rather than hoped for.
  • An exception-handling agent that reads delivery events, messages the customer on WhatsApp to resolve the common cases, reschedules within rules, and escalates the rest to the hub with a summary.
  • Reconciliation and reporting for cash-on-delivery, seller settlements and driver performance.

What we built

The backend runs as Node.js microservices on the client's cloud account, with MongoDB for operational data, Redis and BullMQ for the dispatch and notification queues, and an event bus that every surface subscribes to. The operations view is a React application built around a live map; the driver app is React Native, in the bare workflow, with a local database and a sync engine that treats the server as the source of truth but never blocks a driver from working. Sellers see their parcels and settlements in a portal with the same components.

The exception agent is a LangGraph workflow with a small set of tools: read the parcel and its events, message the customer, propose a reschedule inside the rules, update the parcel, escalate. It handles address clarification, unavailable-customer rescheduling and delivery-slot confirmation autonomously; anything involving damage, refusal or a complaint goes to a person with the conversation attached. Its permissions are scoped tightly, and it cannot touch cash or settlement records.

Delivery

The platform went live in the smallest city first, running in parallel with the spreadsheet for three weeks while the hub manager compared the engine's proposed assignments with his own. Those weeks turned several unwritten rules into configuration and caught two routing assumptions that did not survive contact with the city's one-way streets. Drivers moved to the app in groups, with the old WhatsApp groups kept open as a fallback until nobody used them. Each further city took about two weeks to onboard, mostly spent on seller integrations and local rules.

Outcomes

Dispatch in each live city now takes the hub manager minutes rather than the first hour of the morning, and the operations room works from the map rather than from calls. Drivers complete proof of delivery in the app even where there is no signal, and the sync-conflict count the team watches has stayed at zero since the second week. The exception agent resolves most customer-side delivery issues without the hub being involved, and customers are messaged about a delay before they would have called. Cash-on-delivery reconciliation, previously a two-day monthly effort, is a report.

The founders' measure of success was simpler: the operation handled a volume increase after go-live with the same operations headcount.

What we measured

  • Dispatch time per hub per morning
  • On-time delivery rate
  • Sync conflicts in the driver app
  • Crash-free sessions
  • Exceptions closed without a hub manager
  • Time from exception to customer message
  • Reconciliation effort for cash-on-delivery

Architecture in brief

Every change to a parcel is an event on the bus; the dispatch engine, the operations map, the driver app sync, the seller portal and the exception agent all consume the same stream, which is why the surfaces never disagree about the state of a delivery. The driver app keeps a local database of the day's route and writes every action there first; the sync engine replays queued actions to the server in order when connectivity returns, and the server resolves conflicts by rule, for example a parcel marked delivered offline wins over a later reassignment. Load targets were set from the client's month-end and festival peaks, not the average day, and the queues and database were sized and tested against them before the first city went live.

The exception agent is small by design. It has five tools, a budget per conversation, and a list of intents it may close on its own; everything else escalates with the conversation attached. That scope is reviewed monthly with the operations team, and intents are added only when the previous ones have a clean record.

What we learned

Offline-first is not a feature you add; it decides the data model, the sync design and the testing strategy, and we were glad to have committed to it in week one. The parallel run with the spreadsheet was slower than a cutover and was the reason the hub managers trusted the engine. And the exception agent's value came less from cleverness than from scope: a short list of cases handled reliably, with everything else escalated with context.

We continue as the client's product team on a monthly pod, currently adding a customer-facing tracking experience and seller analytics.

"We ran dispatch on phone calls and a wall of WhatsApp groups. Now the ops room watches a map, the drivers have an app that works in a basement, and the customer gets told before they call us."
Founder, Logistics client

Client details are anonymised. Figures are described qualitatively and are available under NDA on a call.