A client login could list its own bookings but had no way to see what its
riders were actually doing. jupiter's console gave them getridersummary and
the rider/delivery logs; Doormile records all of it and exposed none of it.
New console endpoints, all tenant-scoped:
GET /admin/milers/summary roster with live state + range totals
GET /admin/milers/:id/logs GPS trail from the Redis telemetry index
GET /admin/milers/:id/activity one rider's assignments, duty and breaks
GET /admin/consignments/:id/logs event history + telemetry + proof
GET /admin/bookings/:id/track booking -> assignments -> parcel -> proof
Also closes a rider IDOR: GetMilers scoped the roster to the caller's own
fleet, but reading, editing, blocking, notifying or assigning a vehicle to a
single rider by id did not, so a client login could walk the whole network's
riders by incrementing the id. All five now go through assertMilerAccess.
And the client dashboard no longer reports milers/customers/exceptions as
zero — those have no tenant column, so they are counted through appusers,
bookings and consignments respectively.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Captures the working request bodies for the customer login/booking and the
admin/hub assign-miler endpoints, plus the constraints that are easy to hit
and hard to diagnose:
- CityGate only accepts pickup pincodes in 641/600/560/500
- hub assign-miler 403s unless milerprofiles.hubid matches the calling hub,
and most milers have hubid NULL
- CreateCustomerBooking auto-assigns in the background, so a booking is often
already on a miler before you assign one
- the routing watchdog sweeps unaccepted assignments within ~a minute and may
re-assign under a new bookingassignmentid, so accept IDs must be re-read
- reject takes its reason in the body, not the query string
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>