package main import ( "fmt" "net/http" "os" "time" "finance/backend/handlers" "finance/backend/internal/config" "finance/backend/internal/database" "finance/backend/internal/logger" "finance/backend/internal/middleware" "finance/backend/internal/models" "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 handlers goalHandler := handlers.NewGoalHandler() // Initialize other handlers as needed // userHandler := handlers.NewUserHandler() // accountHandler := handlers.NewAccountHandler() // transactionHandler := handlers.NewTransactionHandler() // loanHandler := handlers.NewLoanHandler() // authHandler := handlers.NewAuthHandler() // Create a new Gin router without default middleware r := gin.New() // 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"}) }) // API v1 routes v1 := r.Group("/api/v1") // Authentication routes (no JWT required) // v1.POST("/register", authHandler.Register) // v1.POST("/login", authHandler.Login) // Protected routes (JWT required) protected := v1.Group("") // protected.Use(authHandler.JWTAuth) // User routes // protected.GET("/users/me", userHandler.GetCurrentUser) // protected.PUT("/users/me", userHandler.UpdateCurrentUser) // Account routes // protected.GET("/accounts", accountHandler.GetAccounts) // protected.GET("/accounts/:id", accountHandler.GetAccountByID) // protected.POST("/accounts", accountHandler.CreateAccount) // protected.PUT("/accounts/:id", accountHandler.UpdateAccount) // protected.DELETE("/accounts/:id", accountHandler.DeleteAccount) // Transaction routes // protected.GET("/transactions", transactionHandler.GetTransactions) // protected.GET("/transactions/:id", transactionHandler.GetTransactionByID) // protected.POST("/transactions", transactionHandler.CreateTransaction) // protected.PUT("/transactions/:id", transactionHandler.UpdateTransaction) // protected.DELETE("/transactions/:id", transactionHandler.DeleteTransaction) // Goal routes protected.GET("/goals", goalHandler.GetGoals) protected.GET("/goals/:id", goalHandler.GetGoal) protected.POST("/goals", goalHandler.CreateGoal) protected.PUT("/goals/:id", goalHandler.UpdateGoal) protected.DELETE("/goals/:id", goalHandler.DeleteGoal) protected.PATCH("/goals/:id/progress", goalHandler.UpdateGoalProgress) // Loan routes // protected.GET("/loans", loanHandler.GetLoans) // protected.GET("/loans/:id", loanHandler.GetLoanByID) // protected.POST("/loans", loanHandler.CreateLoan) // protected.PUT("/loans/:id", loanHandler.UpdateLoan) // protected.DELETE("/loans/:id", loanHandler.DeleteLoan) // 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) } }