Files
doormile_milderapp/MILER_ROUTE_ORDER_REQUEST.md
2026-08-28 11:13:15 +05:30

6.4 KiB
Raw Blame History

P0 — The hub's route order never reaches the rider

From: Miler rider-app engineering · 24 Aug 2026 To: Doormile backend Endpoints: GET /miler/bookings, GET /miler/assignments Related: API requirements §11b (request 13), open questions 6 and 7


The rule we are building to

The console decides the order. The rider follows it.

If operations has solved a route, the app must work the stops in that exact order — both legs, pickup and delivery — and must never re-sort by what is closest to the rider. Re-optimising a planned route is not a small difference: it changes the arrival windows customers were promised, and it makes the hub's own screen a fiction.

This is already how the app behaves. lib/data/route_order.dart is the single place that answers it, and its rule is:

The payload says The app does The rider is told
any stop carries a sequence works them in that order, exactly Hub route
no sequence, but booked times orders by booked time No route assigned — ordered by booked time
no sequence, no times keeps the backend's own array order No route assigned — shown in the order they came through
nothing at all, rider has GPS nearest-first No route assigned — ordered by what is closest to you

Nearest-first is the last of four, it is labelled as a guess wherever it appears, and one sequenced stop is enough to switch the whole set into hub order.


What is happening instead

Every live row comes back step: 0. Verified in production, rider Rajan A (userid 38), 21–24 Aug:

GET /miler/bookings     → 29 rows · step = 0 on all 29
GET /miler/assignments  → 12 rows · step = 0 on all 12, sequencedat = null

step is on the contract and is present in the payload. It is simply never written. So the first branch of the table above has never once been taken on a real device, and every rider in production is working a route the app ordered, while the console believes he is working the route it planned.

Neither side is currently able to notice. That is the part we would most like to close.

Why it bites hardest on the delivery leg

GET /miler/assignments is — correctly, and you have confirmed this — the active queue: Assigned / Accepted only. A booking leaves that queue the moment it is collected.

The delivery leg begins the moment it is collected.

So even if step were populated on assignments tomorrow, the sequence would vanish at exactly the point the rider starts delivering, and the delivery half of his day would still be ordered by the app. The sequence has to be on GET /miler/bookings, which is the only list that covers all of a rider's work.


What we need

1. Populate step on every routed stop

On both GET /miler/bookings and GET /miler/assignments:

{
  "bookingid": 59,
  "stoptype": "delivery",
  "step": 4,                          // 1-based position in the solved route
  "sequencedat": "2026-08-24 07:12:00", // when the route was solved, IST
  "tripid": 2                         // see §3
}
  • step is 1-based. 0 keeps its current meaning — this stop is not in a solved route — and the app already sends those to the end of the list.
  • Stable for the day. A stop's step must not change between two polls unless the route was genuinely re-solved. The app re-sorts on every fetch; a step that drifts makes the list reshuffle under the rider's thumb.
  • Unique within a rider's route, so two stops cannot claim position 4.
  • Survives the leg change. The step a booking had as a pickup, or the step its delivery has, must still be on the row after pickup-complete — that is the case that is broken today.

2. sequencedat, preserved

Null means never solved. A timestamp means solved then. The app uses it for one thing only: telling a rider "no route assigned" honestly instead of implying the hub planned an order it did not. It is currently null on every row even where a step exists.

3. Confirm who owns Trip 1 / Trip 2 / Trip 3

A rider's day is split into up to three runs. Today the app derives that split client-side, from the day part — morning / afternoon / evening — because nothing in the payload names a run.

That is a guess, and it is the wrong kind: a rider's "Trip 2" and the hub's "Trip 2" are not necessarily the same set of stops, and neither screen can tell.

Two workable answers, and we need to know which:

  • The console owns runs → return tripid (and slotid if they differ) on every row of GET /miler/bookings, stable for the day. We follow it and delete the day-part split entirely.
  • Nobody owns runs → say so, and the day-part split stays as documented client behaviour rather than an unlabelled invention.

Two questions we cannot answer from this side

  1. Is sequencing automatic or manual? Is a route solved when assignments are created, or does an operator have to trigger a route/optimizer action? If it is manual, then step: 0 is often the correct answer, and the app should say "no route assigned" plainly rather than quietly ordering the stops itself — which is a different piece of work from populating the field.

  2. What happens on a mid-day re-solve? If operations re-sequences a route while a rider is part-way through it, do completed stops keep their old steps? We will follow whatever you send; we need to know whether to expect the numbers to move.


How to tell it is fixed

No app release is needed for any of this — the app reads these fields today.

  1. GET /miler/bookings for a rider with a solved route returns step ≥ 1 on the routed stops and a non-null sequencedat.
  2. The same booking still carries its step after pickup-complete.
  3. Two consecutive polls return the same steps.
  4. On the rider's phone, the queue heading reads Hub route rather than Nearest first — that string is driven directly by which branch of the table above was taken, so it is a one-glance check that the sequence actually arrived.

What we are not asking for

  • Not a routing engine. If the console already stores an order, exposing it is enough; we are not asking anyone to solve TSP.
  • Not a new endpoint. Two fields on two existing list responses.
  • Not a change to /miler/assignments' scoping. Active-queue-only is right — it is precisely why /miler/bookings has to carry the sequence.