← All work

Case study · Loblaw · 2026

A driver scheduling platform for Loblaw's transport network

Driver dispatch across Loblaw's transport network ran on shared Excel workbooks and memory. I built the replacement: one web platform for the company's distribution centre fleets that holds every week's schedule, checks hours of service before a run is booked, and keeps history for pay approval. Live in production and in use.

One
Schedule across the transport network
3
Roles: dispatcher, manager, admin
8
Run types, configurable in-app
14h
Daily on-duty limit enforced

The problem

At the distribution centre I scoped it with, about 15 dispatchers and supervisors edited the same Driver_Schedule.xlsm. One file, one tab that mattered, and no history: nobody could say who had moved a run or when. Two people in the same cell meant the last save won. Run types and departure times were free text, so the same run was spelled five different ways, and drivers found out about changes through one-off messages. The same pattern repeats across the network, which is why the answer had to be one platform, not one better spreadsheet.

Why it mattered

Two signals, before I wrote a line of spec. First, the business had already paid an outside firm to rebuild a neighbouring operations tool, so willingness to pay for this class of problem was proven. Second, I sat with dispatchers and watched them work the sheet rather than asking them about it. The requirements list came from what they did, not what they said.

What I built

Screens below use demo data. Driver names and load numbers are fictional.

The weekly schedule grid: drivers as rows, seven days as columns, loads to cover versus scheduled above each day
The week. Loads to cover versus loads scheduled sits above every day, so the gap is the first thing a dispatcher sees. Thursday here is four short. Each block carries its run type, departure, load number and pay status; a driver can hold more than one block in a day.
The add-block form with run type chips, departure and end times, load ID and note
One form for a run or time off. Pick the run type and the end time fills from that type's shift length. A blank load number is a valid state: planned, not yet assigned. Fixed weekly runs can repeat.
The hours-of-service check refusing a second run that would put a driver at 20 hours on duty
The guardrail. A second run that puts a driver at 20 hours on duty trips the 14-hour daily limit. The tool refuses by default and makes the override explicit and recorded, because dispatch sometimes knows something the tool doesn't.
The day view: departures grouped by hour, with the drivers who are off today listed on the right
The shift floor view. The same data cut for the people running the day: departures by hour, unplanned loads flagged, and who is off today on the right.
A previous week with approved runs marked paid and one day still pending
Weeks are kept. Last week stays exactly as it was dispatched. Approved runs flow to pay, and only managers and admins can approve; Saturday here is still pending.

Decisions I'd defend

01

Weeks are history, not a rolling sheet

Every week is its own record keyed by its Sunday. The workbook only ever knew "now", which is why nobody could answer "what changed". Keeping weeks also turned the schedule into the input for pay approval instead of a separate reconciliation.

02

Hours of service is a guardrail, not a wall

The app checks the daily limit and refuses. A manager can schedule anyway, and the override is stored on the block. A hard block would have been worked around in a text thread; a recorded override gets reviewed.

03

Roles before they were needed

Everyone who logs in can edit the schedule. Only managers and admins approve runs for pay. That split went into the data model on day one, so the pay workflow would not need a retrofit later.

04

Start where the pain is, then build the whole thing

The first release was the one tab everyone fought over: week grid, blocks per driver per day, loads to cover. The full platform was built out around it from what dispatch asked for: run and time-off types, hours-of-service checks, pay approval, driver notifications, and per-DC configuration. Every change has come from the people who run dispatch.

05

Sent means sent

A driver message only shows as sent when the telematics platform actually took it. If the driver isn't linked or the integration is off, the screen says recorded, not sent. If the send fails, nothing is recorded and the dispatcher knows to follow up another way. A tool that claims a driver was told when they weren't is worse than no tool.

06

The second writer gets told

In the workbook the last save won. Here every record carries a version, and a stale edit is rejected instead of saved over someone else's change. With about 15 people in the same week, that had to be a rule of the system, not a warning.

Where it stands

Live in production since summer 2026, after enterprise security and privacy review, and in use by the people who run dispatch. The full platform is in place: weekly scheduling, load targets, hours-of-service checks with recorded overrides, pay approval, driver notifications through the fleet telematics platform, and per-DC configuration of rosters, run types and time-off types, all set in the app rather than in code.

What I would build next is the layer the history now makes possible: coverage, override and pay analytics across the network, straight from the schedule data instead of a separate report.

Underneath, more than 100 automated checks cover the API, the hours-of-service rules, the telematics client and the payroll roster sync. They run in CI alongside static analysis, and each scan finding gets triaged and written down.

Stack: Python (FastAPI) · React · MySQL · nginx on Linux