aboutsummaryrefslogtreecommitdiffstats
path: root/backend/cmd/api/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'backend/cmd/api/main.go')
-rw-r--r--backend/cmd/api/main.go215
1 files changed, 107 insertions, 108 deletions
diff --git a/backend/cmd/api/main.go b/backend/cmd/api/main.go
index e1d0824..f882175 100644
--- a/backend/cmd/api/main.go
+++ b/backend/cmd/api/main.go
@@ -1,40 +1,77 @@
package main
import (
- "log"
+ "fmt"
"net/http"
+ "os"
"time"
- "finance/backend/internal/api/auth"
- "finance/backend/internal/api/v1/accounts"
- "finance/backend/internal/api/v1/goals"
- "finance/backend/internal/api/v1/loans"
- "finance/backend/internal/api/v1/transactions"
+ "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() {
- // Load Configuration
+ // Initialize logger
+ log := logger.NewLogger(os.Stdout, logger.INFO)
+ log.Info("Starting API server...")
+
+ // Load configuration
cfg, err := config.LoadConfig()
if err != nil {
- log.Fatalf("Failed to load configuration: %v", err)
+ 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)
}
- // Initialize Database
- if err := database.InitDatabase(cfg); err != nil {
- log.Fatalf("Failed to initialize database: %v", 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)
}
- // Setup Gin Router
- r := gin.Default()
+ // 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{"http://localhost:3000"},
+ AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization"},
ExposeHeaders: []string{"Content-Length"},
@@ -42,115 +79,77 @@ func main() {
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("/ping", func(c *gin.Context) {
- c.JSON(http.StatusOK, gin.H{
- "message": "pong",
- })
+ r.GET("/health", func(c *gin.Context) {
+ c.JSON(http.StatusOK, gin.H{"status": "ok", "timestamp": time.Now().Unix()})
})
- // Add database status endpoint
- r.GET("/db-status", func(c *gin.Context) {
- // Try to get a connection from the pool
+ r.GET("/dbstatus", func(c *gin.Context) {
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(),
- })
+ c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Database connection 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(),
- })
+ c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Database ping failed"})
return
}
-
- c.JSON(http.StatusOK, gin.H{
- "status": "success",
- "message": "Database connection is healthy",
- })
+ c.JSON(http.StatusOK, gin.H{"status": "ok", "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})
- })
-
- // Account routes
- accountRoutes := protected.Group("/accounts")
- {
- accountRoutes.GET("", accounts.GetAccounts())
- accountRoutes.GET("/:id", accounts.GetAccountByID())
- accountRoutes.POST("", accounts.CreateAccount())
- accountRoutes.PUT("/:id", accounts.UpdateAccount())
- accountRoutes.DELETE("/:id", accounts.DeleteAccount())
- }
-
- // Transaction routes
- transactionRoutes := protected.Group("/transactions")
- {
- transactionRoutes.GET("", transactions.GetTransactions())
- transactionRoutes.GET("/:id", transactions.GetTransactionByID())
- transactionRoutes.POST("", transactions.CreateTransaction())
- transactionRoutes.PUT("/:id", transactions.UpdateTransaction())
- transactionRoutes.DELETE("/:id", transactions.DeleteTransaction())
- }
-
- // Goal routes
- goalRoutes := protected.Group("/goals")
- {
- goalRoutes.GET("", goals.GetGoals())
- goalRoutes.GET("/:id", goals.GetGoalByID())
- goalRoutes.POST("", goals.CreateGoal())
- goalRoutes.PUT("/:id", goals.UpdateGoal())
- goalRoutes.DELETE("/:id", goals.DeleteGoal())
- goalRoutes.PATCH("/:id/progress", goals.UpdateGoalProgress()) // Specific endpoint for updating progress
- }
-
- // 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)
+ // 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)
}
}