package main import ( "context" "fmt" "log" "os" "os/signal" "syscall" "time" "go-server/internal/config" "go-server/internal/database" "go-server/internal/models" "go-server/internal/routes" "go-server/internal/server" "gorm.io/gorm" ) func main() { fmt.Println("Starting server...") // Load configuration cfg, err := config.LoadConfig() if err != nil { log.Fatalf("Failed to load config: %v", err) } // init dbs _ = database.InitDatabases(database.NewPostgresConfig(), database.RedisConfig(cfg.Redis)) // Initialize PostgreSQL db := database.GetPostgres() sqlDb, err := db.DB() if err != nil { log.Fatalf("Failed to get DB connection: %v", err) } defer sqlDb.Close() // Auto-migrate models to ensure GORM knows about table structures err = migrateModels(db) if err != nil { log.Fatalf("Failed to migrate models: %v", err) } // Initialize Redis redisClient := database.GetRedis() defer redisClient.Close() // Setup router router := routes.SetupRouter(db) // Use the server abstraction srv := server.NewServer(router) // Handle graceful shutdown quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt, syscall.SIGTERM) go func() { <-quit fmt.Println("Shutting down server...") // Create shutdown context with a timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // Shutdown services gracefully if err := srv.Shutdown(ctx); err != nil { log.Fatalf("Server shutdown failed: %v", err) } redisClient.Close() sqlDb.Close() fmt.Println("Server gracefully stopped") }() // Start server port := cfg.Server.Port if err := srv.Start(port); err != nil { log.Fatalf("Failed to start server: %v", err) } } // migrateModels auto-migrates all models to ensure GORM knows about table structures func migrateModels(db *gorm.DB) error { return db.AutoMigrate( models.User{}, models.Supplement{}, models.Nutrient{}, models.Category{}, models.NutrientCategory{}, models.SupplementNutrient{}, models.Todo{}, models.TodoCompletion{}, ) }