package main import ( "fmt" "net/http" "os" "time" "finance/backend/internal/config" "finance/backend/internal/database" "finance/backend/internal/logger" "finance/backend/internal/middleware" "finance/backend/internal/models" "finance/backend/internal/router" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" ) func main() { // Initialize logger log := logger.NewLogger(os.Stdout, logger.INFO) log.Info("Starting API server...") // Load configuration cfg, err := config.LoadConfig() if err != nil { log.Fatal("Failed to load configuration:", err) } // Set Gin mode based on environment if cfg.Environment == "production" { gin.SetMode(gin.ReleaseMode) } else { gin.SetMode(gin.DebugMode) } // Initialize database err = database.InitDatabase(cfg) if err != nil { log.Fatal("Failed to connect to database:", err) } // Auto migrate database models err = database.DB.AutoMigrate( &models.User{}, &models.Account{}, &models.Transaction{}, &models.Goal{}, &models.Loan{}, ) if err != nil { log.Fatal("Failed to migrate database:", err) } // Initialize the router from the internal/router package r := router.SetupRouter(cfg) // Add custom middleware r.Use(middleware.RequestLogger(log)) r.Use(middleware.ErrorHandler()) // Configure CORS r.Use(cors.New(cors.Config{ AllowOrigins: []string{"*"}, AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization"}, ExposeHeaders: []string{"Content-Length"}, AllowCredentials: true, MaxAge: 12 * time.Hour, })) // Set up custom handlers for 404 and 405 r.NoRoute(middleware.NotFoundHandler()) r.NoMethod(middleware.MethodNotAllowedHandler()) // Public utility endpoints r.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": "ok", "timestamp": time.Now().Unix()}) }) r.GET("/dbstatus", func(c *gin.Context) { sqlDB, err := database.DB.DB() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Database connection error"}) return } err = sqlDB.Ping() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Database ping failed"}) return } c.JSON(http.StatusOK, gin.H{"status": "ok", "message": "Database connection is healthy"}) }) // Start server serverAddr := fmt.Sprintf("%s:%d", cfg.ServerHost, cfg.ServerPort) log.Info("Server starting on", serverAddr) if err := r.Run(serverAddr); err != nil { log.Fatal("Server failed to start:", err) } }