feat: rider visibility and tracking for the express console

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>
This commit is contained in:
Suriya
2026-08-06 11:41:02 +05:30
parent 6d9232f3b7
commit d85d5571b8
5 changed files with 1164 additions and 24 deletions

View File

@@ -250,8 +250,13 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
// Milers
adminAuth.Get("/milers", controllers.GetMilers)
// Registered before /milers/:id — Fiber matches in registration order, so
// the literal path has to come first or ":id" swallows "summary".
adminAuth.Get("/milers/summary", controllers.GetMilerSummary)
adminAuth.Post("/milers", controllers.CreateMiler)
adminAuth.Get("/milers/:id", controllers.GetMilerDetails)
adminAuth.Get("/milers/:id/logs", controllers.GetMilerLogs)
adminAuth.Get("/milers/:id/activity", controllers.GetMilerActivity)
adminAuth.Put("/milers/:id", controllers.UpdateMiler)
adminAuth.Put("/milers/:id/block", controllers.BlockMiler)
adminAuth.Put("/milers/:id/assign-vehicle", controllers.AssignMilerVehicle)
@@ -262,6 +267,7 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
adminAuth.Post("/expressbooking", middlewares.CityGateMiddleware, controllers.CreateExpressBooking)
adminAuth.Post("/expressbooking/bulk", middlewares.CityGateMiddleware, controllers.AdminBulkCreateBookings)
adminAuth.Get("/bookings/:id", controllers.GetAdminBookingDetails)
adminAuth.Get("/bookings/:id/track", controllers.GetAdminBookingTrack)
adminAuth.Post("/bookings/:id/assign-miler", controllers.AdminAssignMiler)
adminAuth.Post("/bookings/:id/assign-vehicle", controllers.AdminAssignVehicle)
adminAuth.Put("/bookings/:id/status", controllers.AdminUpdateBookingStatus)
@@ -271,6 +277,7 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
// Consignments
adminAuth.Get("/consignments", controllers.GetAdminConsignments)
adminAuth.Get("/consignments/:id", controllers.GetAdminConsignmentDetails)
adminAuth.Get("/consignments/:id/logs", controllers.GetAdminConsignmentLogs)
adminAuth.Get("/consignments/track/:trackingno", controllers.GetAdminConsignmentTracking)
adminAuth.Put("/consignments/:id/status", controllers.AdminUpdateConsignmentStatus)