package main import ( "log" "net/http" "time" "finance/backend/internal/api/auth" "finance/backend/internal/api/v1/loans" "finance/backend/internal/config" "finance/backend/internal/database" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" ) func main() { // Load Configuration cfg, err := config.LoadConfig() if err != nil { log.Fatalf("Failed to load configuration: %v", err) } // Initialize Database if err := database.InitDatabase(cfg); err != nil { log.Fatalf("Failed to initialize database: %v", err) } // Setup Gin Router r := gin.Default() // Configure CORS r.Use(cors.New(cors.Config{ AllowOrigins: []string{"http://localhost:3000"}, 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, })) // Public utility endpoints r.GET("/ping", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "pong", }) }) // Add database status endpoint r.GET("/db-status", func(c *gin.Context) { // Try to get a connection from the pool sqlDB, err := database.DB.DB() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "status": "error", "message": "Failed to get database connection", "error": err.Error(), }) return } // Check if database is reachable err = sqlDB.Ping() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "status": "error", "message": "Database is not reachable", "error": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "status": "success", "message": "Database connection is healthy", }) }) // API v1 routes v1 := r.Group("/api/v1") { // Auth routes (public) v1.POST("/auth/signup", auth.Signup(cfg)) v1.POST("/auth/login", auth.Login(cfg)) // Protected routes protected := v1.Group("") protected.Use(auth.AuthMiddleware(cfg)) { // User routes protected.GET("/users/me", func(c *gin.Context) { // Get user from context (set by auth middleware) user, exists := c.Get("user") if !exists { c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) return } c.JSON(http.StatusOK, gin.H{"user": user}) }) // Loan routes loanRoutes := protected.Group("/loans") { loanRoutes.GET("", loans.GetLoans()) loanRoutes.GET("/:id", loans.GetLoanByID()) loanRoutes.POST("", loans.CreateLoan()) loanRoutes.PUT("/:id", loans.UpdateLoan()) loanRoutes.DELETE("/:id", loans.DeleteLoan()) } } } // Run the server serverAddr := ":8080" // TODO: Make this configurable via cfg log.Printf("Starting server on %s", serverAddr) err = r.Run(serverAddr) if err != nil { // Use Fatalf to exit if server fails to start log.Fatalf("Failed to start server: %v", err) } }