package main import ( "os" "os/signal" "syscall" "time" "doormile/config" "doormile/controllers" "doormile/db" "doormile/internal/notify" "doormile/internal/worker" "doormile/middlewares" "doormile/migrations" "doormile/routes" "doormile/utils" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/joho/godotenv" ) func main() { // 1. Load configuration env variables _ = godotenv.Load() cfg := config.Load() utils.Info("Starting Doormile Backend...") // 2. Connect to Postgres, Redis & NATS db.Connect(cfg) db.InitRedis(cfg) db.InitNATS(cfg) notify.InitFCM() // 3. Run GORM migrations for logistics tables if db.DB != nil { err := migrations.Migrate(db.DB) if err != nil { utils.Error("⚠️ Migration failed, continuing server boot...", "error", err.Error()) } } // 4. Initialize Fiber App app := fiber.New(fiber.Config{ AppName: "Doormile Logistics Service API v1", }) // CORS policy app.Use(cors.New(cors.Config{ AllowHeaders: "Origin,Content-Type,Accept,Authorization", AllowOrigins: "http://localhost:5173,http://localhost:5174,http://localhost:3000,http://localhost:3001,http://localhost:3002,http://localhost:8080,http://localhost:8081,https://doormile.com,https://www.doormile.com,https://admin.doormile.com,https://api.doormile.com,https://crm.doormile.com,https://console.doormile.com,https://app.doormile.com", AllowCredentials: true, AllowMethods: "GET,POST,PUT,DELETE,PATCH,OPTIONS", })) // Structured Zap logger middleware app.Use(middlewares.ZapLogger()) // 5. Register routes routes.RegisterRoutes(app, cfg) // 6. Pre-warm Redis pricing cache from Postgres controllers.WarmPricingCache() // 7. Start NATS booking worker in background go worker.StartBookingWorker() // 7. Startup server in a background thread go func() { utils.Info("Server starting", "port", cfg.Port) if err := app.Listen(":" + cfg.Port); err != nil { utils.Logger.Fatalf("Server failed to bind: %v", err) } }() // Graceful shutdown listener gracefulShutdown(app) } func gracefulShutdown(app *fiber.App) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) <-c utils.Info("Shutting down Doormile Backend...") // Shutdown fiber if err := app.Shutdown(); err != nil { utils.Error("Fiber shutdown failed", "error", err) } // Close database pools db.CloseDB() time.Sleep(1 * time.Second) utils.Info("Shutdown completed cleanly.") }