Case 01 · Logistics · Northern Europe

The file that doesn’t fit.

Product design and design engineering·route-planning platform for last-mile delivery·under NDA, data anonymised
Three delivery trucks parked nose-out at the dock doors of a warehouse, seen from the front
Minutesper client file, down from hours
3approaches built and tested with clients
0cells re-keyed by hand

Why one spreadsheet was the whole problem

A route-planning platform runs on exact optimisation models: give it clean stops, time windows, capacities and a depot, and it returns routes a dispatcher can trust. The catch is the word “clean”.

Every new client arrives with the order file from their old system.

An Excel that follows nobody’s pattern: column names in their language, merged address cells, time windows written as “8–12”, vehicles named after drivers. Getting that file in meant an afternoon of re-keying per client, repeated every week until they migrated. It was also the step where deals died: a prospect who likes the routing still has to get data in, and if that step looks like work, the trial never starts.

I owned the import end to end and built it three times: a template people filled in by hand, then automatic column mapping, and finally an AI-assisted parser that splits merged cells into stops, windows, vehicles and routes and lists everything it assumed.

Order selection: three sources, the file upload selected, drop zone with XLSX/XLS/CSV and the template row
Upload your order file
XLSX
orders-aug-2026.xlsx1.2 MB · uploading…
×
Upload your order file
XLSX
orders-aug-2026.xlsx1.2 MB · 4,256 rows · 20 delivery dates✓ Read and checked · column mapping confirmed
Orders table after import: delivery date, postcode, region, pickup location, time window, tags, weight

The import, step by step

Four steps that stayed the same across all three approaches: read, map, review, plan. The approaches differ only in who does the mapping: the client, a rule set, or a model. The review step never goes away, because a wrong time window silently produces a wrong plan.

Clients arrive with a file, so the file is the default source, and the drop zone says up front that nothing needs reformatting. The template stays for people who prefer it, as a small row below. After reading, the orders land in the same table and filters the planner uses for planning, so checking an import happens where they already work.

Import pipeline · four steps, the same for all three approaches

Three approaches, kept as working prototypes

Each one shipped or was tested with real files. The prototypes below run on their own, with invented data.

Approach 1 · Our template

We send the client an import template; their team copies every order into our columns. The system trusts the result completely.

Works
  • Nothing to guess: every field lands where the optimiser expects it
  • No engineering on our side
Breaks
  • Hours of manual work per client, every week, until they migrate
  • Clients refuse to do it; trial-to-active conversion was the lowest of the three
  • Typos go straight into routes
Prototype · copying into the template, cell by cell

Approach 2 · Automatic mapping

Upload the file as it is. The system matches columns by name, type and sample values, asks the planner only about the leftovers, and refuses politely when a required field doesn’t exist anywhere.

Works
  • Minutes instead of hours; most columns match on the first try
  • A clear contract: what we could not map, you map; what nobody can, goes back to the client with one sentence
Breaks
  • Rules only look at column names and types: a merged “address, window, van” cell is one column to them
  • Every new client file adds a rule, and the rule set is the thing that drifts
Prototype · matching, asking, returning

Approach 3 · AI-assisted parsing

The client’s sheet has one “Delivery” column with everything in it: street, city, window, van, parcels, a note. A model reads it the way a dispatcher would and writes each row out into our seven fields, marking what it had to assume. The planner confirms or corrects before anything touches the optimiser.

Works
  • Handles merged cells, free text and the client’s own naming without new rules
  • Assumptions are visible, so a wrong guess costs one click to fix before it reaches a route
  • Onboarding a file takes minutes of review
Breaks
  • Tokens cost money per file; cheap next to a dispatcher’s hour, but still a cost
  • Confidence is not correctness: the review step cannot be skipped
  • Needs a fallback to approach 2 when the model is unavailable
Prototype · the sheet as received → the same rows in our fields
Clientdoes all the work in approach 1, and most of it never gets done.
Rulestake most of it in approach 2, and hand the leftovers to the planner.
Modeltakes the leftovers too in approach 3, and leaves the planner a check.
Client
Rules
Model
Planner
1 · Templateevery cell, by hand
×
×
2 · Auto mappingname and type rules
×
3 · AI-assistedreads cells like a dispatcher
a personsoftwarefallback onlybubble size = share of the mapping step
Who does the work

Columns and review

Our fields on the left, the client’s columns as dropdowns with a sample value, so a planner can check them without opening the file. A time window written as “8–12” becomes two fields. What is not in the file is filled from defaults and marked as assumed, never silently.

Review lists every assumption as one line with its evidence: how many rows, which pattern. Keep or change. Rows that nobody can map become a list the planner sends back to the client in one click, and the rest of the import goes on.

02 · Columns
03 · Review

Side by side

Why the third one became the default: it is the one clients actually finish.

Criterion1 · Template2 · Auto mapping3 · AI-assisted
Client effortRe-type every orderUpload, answer a few questionsUpload, confirm
Time per fileHoursMinutes, if columns are cleanMinutes, messy files included
ReliabilityExact by constructionBlind to merged contentHigh, assumptions reviewed
Running costNoneNoneTokens per file
Trial → activeLowestBetterHighest

What I did

Design engineering here meant I owned how the import behaves, failures included.

Flows and statesUpload → map → confirm, with every failure state designed: unmatched, missing, returned.
Mapping rulesName, type and sample-value matching for approach 2; the “ask only about leftovers” contract.
Prompt and schemaThe parsing instructions, the field schema the model fills, the assumption format the UI shows.
Prototypes, testedClickable prototypes in code, tested with a focus group of existing and prospective clients.

Outcome

The work ran as a loop: prototype in code, test with the focus group, change, test again. The AI-assisted import shipped as the default path for new clients.

Several × fasteronboarding a client’s order file: minutes of review instead of hours of re-keying.
Shippedthe AI-assisted import is the default path for every new client.