package v1 import ( "api-service/internal/config" "api-service/internal/database" healthcheckHandlers "api-service/internal/handlers/healthcheck" websocketHandlers "api-service/internal/handlers/websocket" "api-service/internal/middleware" services "api-service/internal/services/auth" websocketServices "api-service/internal/services/websocket" "api-service/pkg/logger" "time" "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" ) func RegisterRoutes(cfg *config.Config) *gin.Engine { router := gin.New() // Initialize auth middleware configuration middleware.AuthJWTMiddleware() // Add global middleware router.Use(middleware.CORSConfig()) router.Use(middleware.ErrorHandler()) router.Use(logger.RequestLoggerMiddleware(logger.Default())) router.Use(gin.Recovery()) // Initialize services with error handling authService := services.NewAuthService(cfg) if authService == nil { logger.Fatal("Failed to initialize auth service") } // Initialize database service dbService := database.New(cfg) // ============================================================================= // HEALTH CHECK & SYSTEM ROUTES // ============================================================================= healthCheckHandler := healthcheckHandlers.NewHealthCheckHandler(dbService) sistem := router.Group("/api/sistem") { sistem.GET("/health", healthCheckHandler.CheckHealth) sistem.GET("/databases", func(c *gin.Context) { c.JSON(200, gin.H{ "databases": dbService.ListDBs(), "health": dbService.Health(), "timestamp": time.Now().Unix(), }) }) sistem.GET("/info", func(c *gin.Context) { c.JSON(200, gin.H{ "service": "API Service v1.0.0", "websocket_active": true, "connected_clients": 0, // TODO: implement websocket handler "databases": dbService.ListDBs(), "timestamp": time.Now().Unix(), }) }) } // ============================================================================= // SWAGGER DOCUMENTATION // ============================================================================= router.GET("/swagger/*any", ginSwagger.WrapHandler( swaggerFiles.Handler, ginSwagger.DefaultModelsExpandDepth(-1), ginSwagger.DeepLinking(true), )) // ============================================================================= // WEBSOCKET TEST CLIENT // ============================================================================= // ============================================================================= // API v1 GROUP // ============================================================================= v1 := router.Group("/api/v1") // ============================================================================= // PUBLIC ROUTES (No Authentication Required) // ============================================================================= // Authentication routes // authHandler := authHandlers.NewAuthHandler(authService) // tokenHandler := authHandlers.NewTokenHandler(authService) // Basic auth routes // v1.POST("/auth/login", authHandler.Login) // v1.POST("/auth/register", authHandler.Register) // v1.POST("/auth/refresh", authHandler.RefreshToken) // Token generation routes // v1.POST("/token/generate", tokenHandler.GenerateToken) // v1.POST("/token/generate-direct", tokenHandler.GenerateTokenDirect) // ============================================================================= // WEBSOCKET ROUTES // ============================================================================= // WebSocket handler will be initialized after websocketHub is defined // ============================================================================= // PUBLISHED ROUTES // ============================================================================= // Initialize WebSocket hub with database service websocketHub := websocketServices.NewHub(cfg.WebSocket) go websocketHub.Run() // Start WebSocket hub in background // Initialize WebSocket handler websocketHandler := websocketHandlers.NewWebSocketHandler(websocketHub, cfg.WebSocket) // WebSocket routes v1.GET("/ws", websocketHandler.HandleWebSocket) v1.GET("/ws/test", websocketHandler.TestWebSocketConnection) v1.GET("/ws/stats", websocketHandler.GetWebSocketStats) v1.POST("/ws/broadcast/qris", websocketHandler.BroadcastQris) v1.POST("/ws/broadcast/check", websocketHandler.BroadcastCheck) // Retribusi endpoints with WebSocket notifications // retribusiHandler := retribusiHandlers.NewRetribusiHandler() // retribusiGroup := v1.Group("/retribusi") // { // retribusiGroup.GET("", retribusiHandler.GetRetribusi) // retribusiGroup.GET("/dynamic", retribusiHandler.GetRetribusiDynamic) // retribusiGroup.GET("/search", retribusiHandler.SearchRetribusiAdvanced) // retribusiGroup.GET("/id/:id", retribusiHandler.GetRetribusiByID) // // POST/PUT/DELETE with automatic WebSocket notifications // retribusiGroup.POST("", func(c *gin.Context) { // retribusiHandler.CreateRetribusi(c) // // Trigger WebSocket notification after successful creation // if c.Writer.Status() == 200 || c.Writer.Status() == 201 { // // Notify database change via WebSocket // // websocketHub.NotifyDatabaseChange("postgres_satudata", "retribusi_changes", // // fmt.Sprintf(`{"action": "created", "timestamp": "%s"}`, time.Now().Format(time.RFC3339))) // } // }) // retribusiGroup.PUT("/id/:id", func(c *gin.Context) { // // id := c.Param("id") // retribusiHandler.UpdateRetribusi(c) // // Trigger WebSocket notification after successful update // if c.Writer.Status() == 200 { // // Notify database change via WebSocket // // websocketHub.NotifyDatabaseChange("postgres_satudata", "retribusi_changes", // // fmt.Sprintf(`{"action": "updated", "id": "%s", "timestamp": "%s"}`, id, time.Now().Format(time.RFC3339))) // } // }) // retribusiGroup.DELETE("/id/:id", func(c *gin.Context) { // // id := c.Param("id") // retribusiHandler.DeleteRetribusi(c) // // Trigger WebSocket notification after successful deletion // if c.Writer.Status() == 200 { // // Notify database change via WebSocket // // websocketHub.NotifyDatabaseChange("postgres_satudata", "retribusi_changes", // // fmt.Sprintf(`{"action": "deleted", "id": "%s", "timestamp": "%s"}`, id, time.Now().Format(time.RFC3339))) // } // }) // } // ============================================================================= // PROTECTED ROUTES (Authentication Required) // ============================================================================= // Create protected group with configurable authentication protected := v1.Group("/") protected.Use(middleware.AuthJWTMiddleware()) // Use configurable authentication // User profile (protected) // protected.GET("/auth/me", authHandler.Me) // Retribusi endpoints (CRUD operations - should be protected) // protectedQris := protected.Group("/ws") // { // protectedQris.POST("/qris/broadcast", websocketHandler.BroadcastQris) // POST /api/v1/ws/ // protectedQris.POST("/check/broadcast", websocketHandler.BroadcastCheck) // POST /api/v1/ws/ // } return router }