package main import ( "log" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) func main() { // Load configuration with environment file precedence config := LoadConfig() // Initialize structured logger if err := InitLogger(config); err != nil { log.Fatal("Failed to initialize logger:", err) } // Set Gin mode based on configuration gin.SetMode(config.GinMode) // Initialize JWT with configuration InitJWTWithConfig(config) // Initialize database with configuration if err := InitDBWithConfig(config); err != nil { Logger.WithError(err).Fatal("Failed to initialize database") } // Create tables if err := CreateTables(); err != nil { Logger.WithError(err).Fatal("Failed to create tables") } // Initialize Prometheus metrics InitMetrics() // Start metrics server on separate port StartMetricsServer(config.MetricsPort) // Create Gin router r := gin.Default() // Configure CORS corsConfig := cors.DefaultConfig() corsConfig.AllowOrigins = []string{"http://localhost:3000", "http://localhost:5173"} // React dev servers corsConfig.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"} corsConfig.AllowHeaders = []string{"Origin", "Content-Type", "Accept", "Authorization"} corsConfig.AllowCredentials = true r.Use(cors.New(corsConfig)) // Add metrics middleware r.Use(MetricsMiddleware()) // Add logging middleware r.Use(LoggingMiddleware()) // Health check endpoint r.GET("/health", func(c *gin.Context) { c.JSON(200, gin.H{"status": "ok"}) }) // API routes api := r.Group("/api/v1") { // Authentication routes auth := api.Group("/auth") { auth.POST("/register", RegisterHandler) auth.POST("/login", LoginHandler) auth.GET("/me", AuthMiddleware(), GetCurrentUserHandler) } // Counter routes (protected) counters := api.Group("/counters") counters.Use(AuthMiddleware()) { counters.POST("", CreateCounterHandler) counters.GET("", GetCountersHandler) counters.GET("/:id", GetCounterHandler) counters.PUT("/:id", UpdateCounterHandler) counters.DELETE("/:id", DeleteCounterHandler) counters.POST("/:id/increment", IncrementCounterHandler) counters.GET("/:id/entries", GetCounterEntriesHandler) counters.GET("/:id/stats", GetCounterStatsHandler) } } // Serve static files (React app) r.Static("/static", "./frontend/build/static") r.StaticFile("/", "./frontend/build/index.html") r.NoRoute(func(c *gin.Context) { c.File("./frontend/build/index.html") }) // Start server port := config.Port Logger.WithFields(logrus.Fields{ "port": port, "metrics_port": config.MetricsPort, "log_dir": config.LogDir, "log_volume": config.LogVolume, }).Info("🚀 Starting Counter Application Server") Logger.WithFields(logrus.Fields{ "health_url": "http://localhost:" + port + "/health", "api_url": "http://localhost:" + port + "/api/v1", "frontend_url": "http://localhost:" + port + "/", "metrics_url": "http://localhost:" + config.MetricsPort + "/metrics", }).Info("✅ Server is ready and accepting connections") Logger.Fatal(r.Run(":" + port)) }