feat: 14 new endpoints closing jupiter->Doormile API gaps, plus two tenant-scoping bug fixes

New endpoints:
- Admin: partner CRUD (GET/POST /admin/partners, GET/PUT/DELETE
  /admin/partners/:id), bulk express booking create
  (POST /admin/expressbooking/bulk), bulk cancel
  (POST /admin/bookings/bulk-cancel), reports (GET /admin/reports),
  password change (PUT /admin/profile/password), miler notify
  (POST /admin/milers/:id/notify)
- Miler: PIN reset (POST /miler/reset-pin), cancel assignment
  (POST /miler/bookings/:bookingid/cancel), skip delivery
  (POST /miler/consignments/:id/skip)
- Hub: batch assign (POST /hub/bookings/batch-assign) - greedy
  nearest-rider queue clearing, capped per rider

Bug fixes:
- BookingPickupComplete now sets Consignment.Tenantid from the
  booking's tenant instead of the completing miler's own tenant
  (fixes cross-tenant shipment mis-attribution)
- GetHubUnassignedBookings/GetHubBookingsRange now scoped via
  scopeBookingsToOwnTenant (fixes partner hub staff seeing other
  tenants' bookings)

Also: CRM booking routes renamed to expressbooking to end the naming
collision with the separate CRM clients feature; PickupBooking gains
nullable Tenantid; adds CLAUDE.md project memory.

Verified: go build ./... and go vet ./... both clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-05 12:22:39 +05:30
parent 77a723e047
commit c272a33fa6
10 changed files with 1404 additions and 43 deletions

View File

@@ -113,6 +113,7 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
miler := api.Group("/miler")
miler.Post("/login", authThrottle, controllers.LoginMiler(cfg))
miler.Post("/verify-pin", authThrottle, controllers.VerifyMilerPin(cfg))
miler.Post("/reset-pin", authThrottle, controllers.ResetMilerPin)
// Authenticated Miler App routes
milerAuth := miler.Use(middlewares.AuthMiddleware(cfg), middlewares.RoleCheckMiddleware(5))
@@ -134,6 +135,7 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
milerAuth.Post("/bookings/:bookingid/payment", controllers.BookingPaymentCollect)
milerAuth.Post("/bookings/:bookingid/pickup-complete", controllers.BookingPickupComplete)
milerAuth.Post("/bookings/:bookingid/vehicle-required", controllers.BookingVehicleRequiredEscalate)
milerAuth.Post("/bookings/:bookingid/cancel", controllers.MilerCancelAssignment)
// Redis periodic telemetry and status logs
milerAuth.Post("/logs", controllers.CreateMilerPeriodicLog)
@@ -160,6 +162,7 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
// Delivery confirmation
milerAuth.Post("/consignments/:id/deliver", controllers.MilerDeliverConsignment)
milerAuth.Post("/consignments/:id/skip", controllers.MilerSkipDelivery)
// Earnings
milerAuth.Get("/earnings", controllers.MilerGetEarnings)
@@ -183,8 +186,10 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
adminAuth := admin.Use(middlewares.AuthMiddleware(cfg), middlewares.RoleCheckMiddleware(1, 3, 4))
adminAuth.Get("/dashboard", controllers.GetAdminDashboard)
adminAuth.Get("/reports", controllers.GetAdminReports)
adminAuth.Get("/profile", controllers.GetAdminProfile)
adminAuth.Get("/me", controllers.GetAdminProfile)
adminAuth.Put("/profile/password", controllers.AdminChangePassword)
// App Users Management
adminAuth.Get("/users", controllers.GetAppUsers)
@@ -192,6 +197,14 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
adminAuth.Put("/users/:id", controllers.UpdateAppUser)
adminAuth.Delete("/users/:id", controllers.DeleteAppUser)
// Partner management (fleet/rider suppliers — distinct from tenants,
// which are the client companies Doormile delivers for)
adminAuth.Get("/partners", controllers.GetPartners)
adminAuth.Post("/partners", controllers.CreatePartner)
adminAuth.Get("/partners/:id", controllers.GetPartnerDetails)
adminAuth.Put("/partners/:id", controllers.UpdatePartner)
adminAuth.Delete("/partners/:id", controllers.DeletePartner)
// Tenant management
adminAuth.Get("/tenants", controllers.GetTenants)
adminAuth.Post("/tenants", controllers.CreateTenant)
@@ -234,15 +247,18 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
adminAuth.Put("/milers/:id", controllers.UpdateMiler)
adminAuth.Put("/milers/:id/block", controllers.BlockMiler)
adminAuth.Put("/milers/:id/assign-vehicle", controllers.AssignMilerVehicle)
adminAuth.Post("/milers/:id/notify", controllers.AdminNotifyMiler)
// Bookings
adminAuth.Get("/bookings", controllers.GetAdminBookings)
adminAuth.Post("/crmbooking", middlewares.CityGateMiddleware, controllers.CreateCRMBooking)
adminAuth.Post("/expressbooking", middlewares.CityGateMiddleware, controllers.CreateExpressBooking)
adminAuth.Post("/expressbooking/bulk", middlewares.CityGateMiddleware, controllers.AdminBulkCreateBookings)
adminAuth.Get("/bookings/:id", controllers.GetAdminBookingDetails)
adminAuth.Post("/bookings/:id/assign-miler", controllers.AdminAssignMiler)
adminAuth.Post("/bookings/:id/assign-vehicle", controllers.AdminAssignVehicle)
adminAuth.Put("/bookings/:id/status", controllers.AdminUpdateBookingStatus)
adminAuth.Post("/bookings/:id/cancel", controllers.AdminCancelBooking)
adminAuth.Post("/bookings/bulk-cancel", controllers.AdminBulkCancelBookings)
// Consignments
adminAuth.Get("/consignments", controllers.GetAdminConsignments)
@@ -307,6 +323,7 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
hubAuth.Post("/bookings/:id/inbound", controllers.CreateInboundScan)
hubAuth.Post("/bookings/:id/assign-miler", controllers.HubAssignMiler)
hubAuth.Post("/bookings/:id/auto-assign", controllers.HubAutoAssign)
hubAuth.Post("/bookings/batch-assign", controllers.HubBatchAssign)
hubAuth.Get("/batches", controllers.GetHubBatches)
hubAuth.Post("/batches", controllers.CreateHubBatch)
hubAuth.Patch("/batches/:id/status", controllers.UpdateBatchStatus)