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)) }