Files
doormile_backend/routes/routes.go
Suriya d7c0f35ffe fix: admin console endpoints
- Remove scratch/check_users.go
- GetAdminBookings: LIMIT/OFFSET enforced, returns pageno/pagesize/pages
- GetAdminCustomers: new B2C appcustomers list with booking count
- AdminCancelBooking: cancel + miler release + FCM + NATS event
2026-07-08 20:31:25 +05:30

340 lines
14 KiB
Go

package routes
import (
"context"
"time"
"doormile/config"
"doormile/controllers"
"doormile/db"
"doormile/internal/ws"
"doormile/middlewares"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/websocket/v2"
)
func RegisterRoutes(app *fiber.App, cfg *config.Config) {
api := app.Group("/api/v1")
// --------------------
// HEALTH & READINESS PROBES
// --------------------
api.Get("/health", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "OK", "time": time.Now()})
})
api.Get("/ready", func(c *fiber.Ctx) error {
dbStatus := "connected"
sqlDB, err := db.DB.DB()
if err != nil || sqlDB.Ping() != nil {
dbStatus = "unavailable"
}
redisStatus := "connected"
if db.Rdb == nil {
redisStatus = "unavailable"
} else {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if _, pingErr := db.Rdb.Ping(ctx).Result(); pingErr != nil {
redisStatus = "unavailable"
}
}
status := fiber.StatusOK
if dbStatus == "unavailable" || redisStatus == "unavailable" {
status = fiber.StatusServiceUnavailable
}
return c.Status(status).JSON(fiber.Map{
"status": "ready",
"checks": fiber.Map{
"postgres": dbStatus,
"redis": redisStatus,
},
})
})
// --------------------
// CUSTOMER APIS
// --------------------
customer := api.Group("/customer")
customer.Post("/register", controllers.RegisterCustomer(cfg))
customer.Post("/login", controllers.LoginCustomer)
customer.Post("/verify-pin", controllers.VerifyCustomerPin(cfg))
customer.Post("/reset-pin", controllers.ResetCustomerPin)
customer.Post("/send-email-otp", controllers.SendCustomerEmailOtp(cfg))
customer.Post("/verify-email-otp", controllers.VerifyCustomerEmailOtp())
// Authenticated Customer App routes
customerAuth := customer.Use(middlewares.AuthMiddleware(cfg), middlewares.RoleCheckMiddleware(9))
customerAuth.Get("/profile", controllers.GetCustomerProfile)
customerAuth.Put("/profile", controllers.UpdateCustomerProfile)
customerAuth.Get("/locations", controllers.GetCustomerLocations)
customerAuth.Post("/locations", controllers.CreateCustomerLocation)
customerAuth.Put("/locations/:id", controllers.UpdateCustomerLocation)
customerAuth.Delete("/locations/:id", controllers.DeleteCustomerLocation)
customerAuth.Put("/device-token", controllers.SaveCustomerDeviceToken)
customerAuth.Post("/bookings", middlewares.CityGateMiddleware, controllers.CreateCustomerBooking)
customerAuth.Get("/bookings", controllers.GetCustomerBookings)
customerAuth.Get("/bookings/:bookingid", controllers.GetCustomerBookingDetails)
customerAuth.Post("/bookings/:bookingid/cancel", controllers.CancelCustomerBooking)
customerAuth.Get("/bookings/:bookingid/price", controllers.GetCustomerBookingQuote)
customerAuth.Get("/track/:trackingno", controllers.TrackConsignment)
// --------------------
// MILER APIS
// --------------------
miler := api.Group("/miler")
miler.Post("/login", controllers.LoginMiler(cfg))
miler.Post("/verify-pin", controllers.VerifyMilerPin(cfg))
// Authenticated Miler App routes
milerAuth := miler.Use(middlewares.AuthMiddleware(cfg), middlewares.RoleCheckMiddleware(5))
milerAuth.Get("/profile", controllers.GetMilerProfile)
milerAuth.Put("/profile", controllers.UpdateMilerProfile)
milerAuth.Put("/device-token", controllers.SaveMilerDeviceToken)
milerAuth.Put("/location", controllers.UpdateMilerLocation)
milerAuth.Put("/availability", controllers.UpdateMilerAvailability)
milerAuth.Get("/assignments", controllers.GetMilerAssignments)
milerAuth.Get("/assignments/:id", controllers.GetMilerAssignmentDetails)
milerAuth.Post("/assignments/:id/accept", controllers.AcceptMilerAssignment)
milerAuth.Post("/assignments/:id/reject", controllers.RejectMilerAssignment)
milerAuth.Post("/bookings/:bookingid/reached", controllers.BookingReachedCustomer)
milerAuth.Post("/bookings/:bookingid/parcel", controllers.BookingParcelConfirm)
milerAuth.Post("/bookings/:bookingid/payment", controllers.BookingPaymentCollect)
milerAuth.Post("/bookings/:bookingid/pickup-complete", controllers.BookingPickupComplete)
milerAuth.Post("/bookings/:bookingid/vehicle-required", controllers.BookingVehicleRequiredEscalate)
// Redis periodic telemetry and status logs
milerAuth.Post("/logs", controllers.CreateMilerPeriodicLog)
milerAuth.Get("/logs", controllers.GetMilerPeriodicLogs)
milerAuth.Post("/status", controllers.CreateMilerStatus)
milerAuth.Get("/status", controllers.GetMilerStatus)
// Redis consignment tracking and telemetry logs
milerAuth.Post("/consignments/logs", controllers.PublishConsignmentLogs)
milerAuth.Get("/consignments/logs/:consignmentid", controllers.GetConsignmentLogs)
milerAuth.Get("/consignments/userlogs/:userid", controllers.GetUserConsignmentLogs)
// --------------------
// ADMIN CONSOLE APIS — all open, no token required
// --------------------
admin := api.Group("/admin")
admin.Post("/login", controllers.LoginAdmin(cfg))
// Authenticated Admin Console routes
adminAuth := admin.Use(middlewares.AuthMiddleware(cfg), middlewares.RoleCheckMiddleware(1, 3, 4))
adminAuth.Get("/dashboard", controllers.GetAdminDashboard)
adminAuth.Get("/profile", controllers.GetAdminProfile)
adminAuth.Get("/me", controllers.GetAdminProfile)
// App Users Management
adminAuth.Get("/users", controllers.GetAppUsers)
adminAuth.Post("/users", controllers.CreateAppUser)
adminAuth.Put("/users/:id", controllers.UpdateAppUser)
adminAuth.Delete("/users/:id", controllers.DeleteAppUser)
// Tenant management
adminAuth.Get("/tenants", controllers.GetTenants)
adminAuth.Post("/tenants", controllers.CreateTenant)
adminAuth.Get("/tenants/:id", controllers.GetTenantDetails)
adminAuth.Put("/tenants/:id", controllers.UpdateTenant)
adminAuth.Delete("/tenants/:id", controllers.DeleteTenant)
adminAuth.Get("/tenants/:id/locations", controllers.GetTenantLocations)
adminAuth.Post("/tenants/:id/locations", controllers.CreateTenantLocation)
adminAuth.Put("/tenantlocations/:id", controllers.UpdateTenantLocation)
// Tenant customers
adminAuth.Get("/tenantcustomers", controllers.GetTenantCustomers)
adminAuth.Post("/tenantcustomers", controllers.CreateTenantCustomer)
adminAuth.Get("/tenantcustomers/:id", controllers.GetTenantCustomerDetails)
adminAuth.Put("/tenantcustomers/:id", controllers.UpdateTenantCustomer)
adminAuth.Delete("/tenantcustomers/:id", controllers.DeleteTenantCustomer)
// B2C App customers
adminAuth.Get("/customers", controllers.GetAdminCustomers)
// Hubs
adminAuth.Get("/hubs", controllers.GetHubs)
adminAuth.Post("/hubs", controllers.CreateHub)
adminAuth.Get("/hubs/:id", controllers.GetHubDetails)
adminAuth.Put("/hubs/:id", controllers.UpdateHub)
adminAuth.Delete("/hubs/:id", controllers.DeleteHub)
// Vehicles
adminAuth.Get("/vehicles", controllers.GetVehicles)
adminAuth.Post("/vehicles", controllers.CreateVehicle)
adminAuth.Get("/vehicles/:id", controllers.GetVehicleDetails)
adminAuth.Put("/vehicles/:id", controllers.UpdateVehicle)
adminAuth.Delete("/vehicles/:id", controllers.DeleteVehicle)
// Milers
adminAuth.Get("/milers", controllers.GetMilers)
adminAuth.Post("/milers", controllers.CreateMiler)
adminAuth.Get("/milers/:id", controllers.GetMilerDetails)
adminAuth.Put("/milers/:id", controllers.UpdateMiler)
adminAuth.Put("/milers/:id/block", controllers.BlockMiler)
adminAuth.Put("/milers/:id/assign-vehicle", controllers.AssignMilerVehicle)
// Bookings
adminAuth.Get("/bookings", controllers.GetAdminBookings)
adminAuth.Post("/crmbooking", middlewares.CityGateMiddleware, controllers.CreateCRMBooking)
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)
// Consignments
adminAuth.Get("/consignments", controllers.GetAdminConsignments)
adminAuth.Get("/consignments/:id", controllers.GetAdminConsignmentDetails)
adminAuth.Get("/consignments/track/:trackingno", controllers.GetAdminConsignmentTracking)
adminAuth.Put("/consignments/:id/status", controllers.AdminUpdateConsignmentStatus)
// Tripsheets
adminAuth.Get("/tripsheets", controllers.GetTripsheets)
adminAuth.Post("/tripsheets", controllers.CreateTripsheet)
adminAuth.Get("/tripsheets/:id", controllers.GetTripsheetDetails)
adminAuth.Post("/tripsheets/:id/items", controllers.AddTripsheetItem)
adminAuth.Delete("/tripsheets/:id/items/:itemid", controllers.DeleteTripsheetItem)
adminAuth.Put("/tripsheets/:id/dispatch", controllers.DispatchTripsheet)
adminAuth.Put("/tripsheets/:id/arrive", controllers.ArriveTripsheet)
// Competitor branch survey data (from Enquiry.xlsx Sheet 1)
adminAuth.Get("/competitor-branches", controllers.GetCompetitorBranches)
adminAuth.Post("/competitor-branches", controllers.CreateCompetitorBranch)
adminAuth.Put("/competitor-branches/:id", controllers.UpdateCompetitorBranch)
adminAuth.Delete("/competitor-branches/:id", controllers.DeleteCompetitorBranch)
// Carrier pricing benchmarks (from Enquiry.xlsx Sheet 2)
adminAuth.Get("/carrier-pricing", controllers.GetCarrierPricing)
adminAuth.Post("/carrier-pricing", controllers.CreateCarrierPricing)
adminAuth.Put("/carrier-pricing/:id", controllers.UpdateCarrierPricing)
adminAuth.Delete("/carrier-pricing/:id", controllers.DeleteCarrierPricing)
// Pricing
adminAuth.Get("/pricing", controllers.GetPricing)
adminAuth.Post("/pricing", controllers.CreatePricing)
adminAuth.Put("/pricing/:id", controllers.UpdatePricing)
adminAuth.Delete("/pricing/:id", controllers.DeletePricing)
adminAuth.Post("/pricing/simulate", controllers.GetPricingQuoteSimulate)
adminAuth.Post("/pricing/quote", controllers.GetPricingQuoteSimulate)
// Doormile pricing bands
adminAuth.Get("/doormile-pricing", controllers.GetDoormilePricing)
adminAuth.Post("/doormile-pricing", controllers.CreateDoormilePricing)
adminAuth.Put("/doormile-pricing/:id", controllers.UpdateDoormilePricing)
adminAuth.Delete("/doormile-pricing/:id", controllers.DeleteDoormilePricing)
// Exceptions
adminAuth.Get("/exceptions", controllers.GetExceptions)
adminAuth.Post("/exceptions", controllers.CreateException)
adminAuth.Get("/exceptions/:id", controllers.GetExceptionDetails)
adminAuth.Put("/exceptions/:id/status", controllers.ResolveException)
// --------------------
// HUB CONSOLE APIS
// --------------------
hub := api.Group("/hub")
hub.Post("/login", controllers.HubStaffLogin(cfg))
// Authenticated Hub Console routes (role 6)
hubAuth := hub.Use(middlewares.HubStaffAuth(cfg))
hubAuth.Get("/dashboard", controllers.GetHubDashboardStats)
hubAuth.Get("/bookings/unassigned", controllers.GetHubUnassignedBookings)
hubAuth.Get("/inbound/today", controllers.GetHubInboundToday)
hubAuth.Post("/bookings/:id/inbound", controllers.CreateInboundScan)
hubAuth.Post("/bookings/:id/assign-miler", controllers.HubAssignMiler)
hubAuth.Post("/bookings/:id/auto-assign", controllers.HubAutoAssign)
hubAuth.Get("/batches", controllers.GetHubBatches)
hubAuth.Post("/batches", controllers.CreateHubBatch)
hubAuth.Patch("/batches/:id/status", controllers.UpdateBatchStatus)
hubAuth.Get("/milers", controllers.GetHubMilers)
// Hub management — enforced Doormile-staff-only inside each handler
hubAuth.Post("/staff", controllers.CreateHubStaffAccount)
hubAuth.Get("/hubs", controllers.GetHubsInCity)
hubAuth.Post("/hubs", controllers.CreateCityHub)
hubAuth.Get("/tripsheets/in-transit", controllers.GetInTransitTripsheets)
hubAuth.Get("/inbound/vehicles", controllers.GetInboundVehicles)
hubAuth.Get("/activity", controllers.GetHubActivity)
hubAuth.Get("/zones", controllers.GetHubZones)
hubAuth.Get("/notifications", controllers.GetHubNotifications)
hubAuth.Patch("/notifications/:id/read", controllers.MarkNotificationRead)
hubAuth.Get("/routing/:trackingno", controllers.GetRoutingInfo)
hubAuth.Get("/rider-routes", controllers.GetAllRiderRoutes)
hubAuth.Get("/milers/:id/route", controllers.GetMilerRoute)
hubAuth.Get("/messages", controllers.GetHubMessages)
hubAuth.Get("/messages/:id", controllers.GetHubMessageThread)
hubAuth.Post("/messages/:id", controllers.SendHubMessage)
hubAuth.Patch("/messages/:id/read", controllers.MarkHubMessagesRead)
hubAuth.Get("/report", controllers.GetHubReport)
// Redis active user caching utilities
redisUsers := api.Group("/utils/users/redis")
redisUsers.Post("/", controllers.CreateUserRedis)
redisUsers.Get("/", controllers.GetUserRedis)
redisUsers.Put("/:userid", controllers.UpdateUserRedis)
redisUsers.Delete("/:userid", controllers.DeleteUserRedis)
// --------------------
// DOORMILE PRICING — public check & meta (no auth)
// --------------------
api.Get("/pricing/meta", controllers.GetPricingMeta)
api.Post("/pricing/check", controllers.CheckPrice)
// --------------------
// BOOKING CACHE APIS — no auth required (testing)
// --------------------
bookingCache := api.Group("/bookings/cache")
bookingCache.Get("/", controllers.ListAllBookingsFromCache)
bookingCache.Get("/customer/:customer_id", controllers.GetCustomerBookingsFromCache)
bookingCache.Get("/:booking_id", controllers.GetBookingFromCache)
// --------------------
// CRM APIS — all open (field reps register from Flutter; web console reads without a separate CRM login)
// --------------------
crm := api.Group("/crm")
crm.Post("/clients", controllers.RegisterClient)
crm.Get("/clients", controllers.GetClients)
crm.Get("/clients/:id", controllers.GetClientDetails)
crm.Put("/clients/:id", controllers.UpdateClient)
crm.Delete("/clients/:id", controllers.DeleteClient)
// --------------------
// INTERNAL — machine-to-machine endpoints (API key auth, no JWT)
// --------------------
internal := api.Group("/internal", middlewares.InternalKeyAuth)
internal.Post("/notify", controllers.InternalNotify)
internal.Post("/bookings/:id/reassign", controllers.InternalReassign)
internal.Post("/agent-decisions", controllers.CreateAgentDecision)
internal.Get("/agent-decisions/similar", controllers.FindSimilarDecisions)
internal.Patch("/agent-decisions/:id/outcome", controllers.UpdateDecisionOutcome)
// --------------------
// WEBSOCKET — live miler tracking (no auth, public tracking link)
// --------------------
app.Use("/ws", func(c *fiber.Ctx) error {
if websocket.IsWebSocketUpgrade(c) {
return c.Next()
}
return fiber.ErrUpgradeRequired
})
app.Get("/ws/bookings/:bookingid/track", websocket.New(ws.TrackingHandler))
app.Get("/ws/bookings/:bookingid/chat", middlewares.WsChatAuth(cfg), websocket.New(ws.ChatHandler))
}