package router import ( "eslogad-be/config" "eslogad-be/internal/middleware" "github.com/gin-gonic/gin" ) type Router struct { config *config.Config authHandler AuthHandler healthHandler HealthHandler authMiddleware AuthMiddleware userHandler UserHandler fileHandler FileHandler rbacHandler RBACHandler masterHandler MasterHandler letterHandler LetterHandler letterOutgoingHandler LetterOutgoingHandler adminApprovalFlowHandler AdminApprovalFlowHandler dispRouteHandler DispositionRouteHandler onlyOfficeHandler OnlyOfficeHandler analyticsHandler AnalyticsHandler notificationHandler NotificationHandler } func NewRouter( cfg *config.Config, authHandler AuthHandler, authMiddleware AuthMiddleware, healthHandler HealthHandler, userHandler UserHandler, fileHandler FileHandler, rbacHandler RBACHandler, masterHandler MasterHandler, letterHandler LetterHandler, letterOutgoingHandler LetterOutgoingHandler, adminApprovalFlowHandler AdminApprovalFlowHandler, dispRouteHandler DispositionRouteHandler, onlyOfficeHandler OnlyOfficeHandler, analyticsHandler AnalyticsHandler, notificationHandler NotificationHandler, ) *Router { return &Router{ config: cfg, authHandler: authHandler, authMiddleware: authMiddleware, healthHandler: healthHandler, userHandler: userHandler, fileHandler: fileHandler, rbacHandler: rbacHandler, masterHandler: masterHandler, letterHandler: letterHandler, letterOutgoingHandler: letterOutgoingHandler, adminApprovalFlowHandler: adminApprovalFlowHandler, dispRouteHandler: dispRouteHandler, onlyOfficeHandler: onlyOfficeHandler, analyticsHandler: analyticsHandler, notificationHandler: notificationHandler, } } func (r *Router) Init() *gin.Engine { gin.SetMode(gin.ReleaseMode) engine := gin.New() engine.Use( middleware.JsonAPI(), middleware.CorrelationID(), middleware.Recover(), middleware.HTTPStatLogger(), middleware.PopulateContext(), middleware.CORS(), ) r.addAppRoutes(engine) return engine } func (r *Router) addAppRoutes(rg *gin.Engine) { rg.GET("/health", r.healthHandler.HealthCheck) v1 := rg.Group("/api/v1") { auth := v1.Group("/auth") { auth.POST("/login", r.authHandler.Login) auth.POST("/refresh", r.authHandler.RefreshToken) auth.GET("/profile", r.authHandler.GetProfile) } users := v1.Group("/users") users.Use(r.authMiddleware.RequireAuth()) { users.POST("", r.userHandler.CreateUser) users.GET("", r.userHandler.ListUsers) users.GET("/profile", r.userHandler.GetProfile) users.GET("/:id/profile", r.userHandler.GetUserProfile) users.PUT("/profile", r.userHandler.UpdateProfile) users.PUT("/:id/password", r.userHandler.ChangePassword) users.GET("/titles", r.userHandler.ListTitles) users.GET("/mention", r.userHandler.GetActiveUsersForMention) users.POST("/profile/avatar", r.fileHandler.UploadProfileAvatar) } files := v1.Group("/files") files.Use(r.authMiddleware.RequireAuth()) { files.POST("/documents", r.fileHandler.UploadDocument) } rbac := v1.Group("/rbac") rbac.Use(r.authMiddleware.RequireAuth()) { rbac.GET("/permissions", r.rbacHandler.ListPermissions) rbac.POST("/permissions", r.rbacHandler.CreatePermission) rbac.PUT("/permissions/:id", r.rbacHandler.UpdatePermission) rbac.DELETE("/permissions/:id", r.rbacHandler.DeletePermission) rbac.GET("/roles", r.rbacHandler.ListRoles) rbac.POST("/roles", r.rbacHandler.CreateRole) rbac.PUT("/roles/:id", r.rbacHandler.UpdateRole) rbac.DELETE("/roles/:id", r.rbacHandler.DeleteRole) } roles := v1.Group("/roles") roles.Use(r.authMiddleware.RequireAuth()) { roles.POST("", r.rbacHandler.CreateOrUpdateRole) roles.GET("/permissions", r.rbacHandler.GetPermissionsGrouped) roles.GET("/:id", r.rbacHandler.GetRoleDetail) } master := v1.Group("/master") master.Use(r.authMiddleware.RequireAuth()) { master.GET("/labels", r.masterHandler.ListLabels) master.POST("/labels", r.masterHandler.CreateLabel) master.PUT("/labels/:id", r.masterHandler.UpdateLabel) master.DELETE("/labels/:id", r.masterHandler.DeleteLabel) master.GET("/priorities", r.masterHandler.ListPriorities) master.POST("/priorities", r.masterHandler.CreatePriority) master.PUT("/priorities/:id", r.masterHandler.UpdatePriority) master.DELETE("/priorities/:id", r.masterHandler.DeletePriority) master.GET("/institutions", r.masterHandler.ListInstitutions) master.POST("/institutions", r.masterHandler.CreateInstitution) master.PUT("/institutions/:id", r.masterHandler.UpdateInstitution) master.DELETE("/institutions/:id", r.masterHandler.DeleteInstitution) master.GET("/disposition-actions", r.masterHandler.ListDispositionActions) master.POST("/disposition-actions", r.masterHandler.CreateDispositionAction) master.PUT("/disposition-actions/:id", r.masterHandler.UpdateDispositionAction) master.DELETE("/disposition-actions/:id", r.masterHandler.DeleteDispositionAction) master.POST("/departments", r.masterHandler.CreateDepartment) master.GET("/departments", r.masterHandler.ListDepartments) master.GET("/departments/chart", r.masterHandler.GetOrganizationalChart) master.GET("/departments/:id", r.masterHandler.GetDepartment) master.GET("/departments/:id/chart", r.masterHandler.GetOrganizationalChartByID) master.PUT("/departments/:id", r.masterHandler.UpdateDepartment) master.DELETE("/departments/:id", r.masterHandler.DeleteDepartment) } lettersch := v1.Group("/letters") lettersch.Use(r.authMiddleware.RequireAuth()) { lettersch.GET("/unread-counts", r.letterHandler.GetLetterUnreadCounts) lettersch.GET("/incoming", r.letterHandler.ListIncomingLetters) lettersch.GET("/incoming/search", r.letterHandler.SearchIncomingLetters) lettersch.POST("/incoming", r.letterHandler.CreateIncomingLetter) lettersch.GET("/incoming/cta/:letter_id", r.letterHandler.GetLetterCTA) lettersch.GET("/incoming/:id", r.letterHandler.GetIncomingLetter) lettersch.PUT("/incoming/:id", r.letterHandler.UpdateIncomingLetter) lettersch.PUT("/incoming/:id/read", r.letterHandler.MarkIncomingLetterAsRead) lettersch.DELETE("/incoming/:id", r.letterHandler.DeleteIncomingLetter) lettersch.POST("/incoming/archive", r.letterHandler.BulkArchiveIncomingLetters) lettersch.POST("/outgoing", r.letterOutgoingHandler.CreateOutgoingLetter) lettersch.GET("/outgoing/search", r.letterOutgoingHandler.SearchOutgoingLetters) lettersch.GET("/outgoing/:id", r.letterOutgoingHandler.GetOutgoingLetter) lettersch.GET("/outgoing", r.letterOutgoingHandler.ListOutgoingLetters) lettersch.PUT("/outgoing/:id", r.letterOutgoingHandler.UpdateOutgoingLetter) lettersch.PUT("/outgoing/:id/read", r.letterHandler.MarkOutgoingLetterAsRead) lettersch.DELETE("/outgoing/:id", r.letterOutgoingHandler.DeleteOutgoingLetter) lettersch.POST("/outgoing/:id/submit", r.letterOutgoingHandler.SubmitForApproval) lettersch.POST("/outgoing/:id/approve", r.letterOutgoingHandler.ApproveOutgoingLetter) lettersch.POST("/outgoing/:id/reject", r.letterOutgoingHandler.RejectOutgoingLetter) lettersch.POST("/outgoing/:id/send", r.letterOutgoingHandler.SendOutgoingLetter) lettersch.POST("/outgoing/:id/archive", r.letterOutgoingHandler.ArchiveOutgoingLetter) lettersch.POST("/outgoing/archive", r.letterOutgoingHandler.BulkArchiveOutgoingLetters) lettersch.GET("/outgoing/:id/cta", r.letterOutgoingHandler.GetLetterApprovalInfo) lettersch.GET("/outgoing/:id/approvals", r.letterOutgoingHandler.GetLetterApprovals) lettersch.POST("/outgoing/:id/recipients", r.letterOutgoingHandler.AddRecipients) lettersch.PUT("/outgoing/:id/recipients/:recipient_id", r.letterOutgoingHandler.UpdateRecipient) lettersch.DELETE("/outgoing/:id/recipients/:recipient_id", r.letterOutgoingHandler.RemoveRecipient) lettersch.POST("/outgoing/:id/attachments", r.letterOutgoingHandler.AddAttachments) lettersch.DELETE("/outgoing/:id/attachments/:attachment_id", r.letterOutgoingHandler.RemoveAttachment) lettersch.POST("/outgoing/:id/discussions", r.letterOutgoingHandler.CreateDiscussion) lettersch.PUT("/outgoing/discussions/:discussion_id", r.letterOutgoingHandler.UpdateDiscussion) lettersch.DELETE("/outgoing/discussions/:discussion_id", r.letterOutgoingHandler.DeleteDiscussion) lettersch.GET("/outgoing/:id/approval-discussions", r.letterOutgoingHandler.GetApprovalDiscussions) lettersch.GET("/outgoing/:id/timeline", r.letterOutgoingHandler.GetApprovalTimeline) lettersch.POST("/dispositions/:letter_id", r.letterHandler.CreateDispositions) lettersch.GET("/dispositions/:letter_id", r.letterHandler.GetEnhancedDispositionsByLetter) lettersch.GET("/dispositions/:letter_id/department/status", r.letterHandler.GetDepartmentDispositionStatus) lettersch.PUT("/dispositions/:letter_id/status", r.letterHandler.UpdateDispositionStatus) lettersch.POST("/discussions/:letter_id", r.letterHandler.CreateDiscussion) lettersch.PUT("/discussions/:letter_id/:discussion_id", r.letterHandler.UpdateDiscussion) } droutes := v1.Group("/disposition-routes") droutes.Use(r.authMiddleware.RequireAuth()) { droutes.POST("", r.dispRouteHandler.Create) // Create with upsert logic droutes.PUT("/bulk", r.dispRouteHandler.BulkCreateOrUpdate) // Explicit bulk create/update droutes.GET("", r.dispRouteHandler.ListAll) // List all routes with details droutes.GET("/grouped", r.dispRouteHandler.ListGrouped) // List grouped by from_department_id droutes.GET("/department", r.dispRouteHandler.ListByFromDept) droutes.GET("/:id", r.dispRouteHandler.Get) droutes.PUT("/:id", r.dispRouteHandler.Update) droutes.PUT("/:id/active", r.dispRouteHandler.SetActive) } admin := v1.Group("/setting") admin.Use(r.authMiddleware.RequireAuth()) { approvalFlows := admin.Group("/approval-flows") { approvalFlows.POST("", r.adminApprovalFlowHandler.CreateApprovalFlow) approvalFlows.GET("", r.adminApprovalFlowHandler.ListApprovalFlows) approvalFlows.GET("/:id", r.adminApprovalFlowHandler.GetApprovalFlow) approvalFlows.GET("/department/:department_id", r.adminApprovalFlowHandler.GetApprovalFlowByDepartment) approvalFlows.PUT("/:id", r.adminApprovalFlowHandler.UpdateApprovalFlow) approvalFlows.DELETE("/:id", r.adminApprovalFlowHandler.DeleteApprovalFlow) approvalFlows.POST("/:id/activate", r.adminApprovalFlowHandler.ActivateApprovalFlow) approvalFlows.POST("/:id/deactivate", r.adminApprovalFlowHandler.DeactivateApprovalFlow) approvalFlows.POST("/:id/clone", r.adminApprovalFlowHandler.CloneApprovalFlow) } } onlyoffice := v1.Group("/onlyoffice") { onlyoffice.POST("/callback/:key", r.onlyOfficeHandler.ProcessCallback) onlyofficeAuth := onlyoffice.Group("") onlyofficeAuth.Use(r.authMiddleware.RequireAuth()) { onlyofficeAuth.POST("/config", r.onlyOfficeHandler.GetEditorConfig) onlyofficeAuth.GET("/settings", r.onlyOfficeHandler.GetOnlyOfficeConfig) onlyofficeAuth.POST("/lock/:id", r.onlyOfficeHandler.LockDocument) onlyofficeAuth.POST("/unlock/:id", r.onlyOfficeHandler.UnlockDocument) onlyofficeAuth.GET("/session/:key", r.onlyOfficeHandler.GetDocumentSession) } } analytics := v1.Group("/analytics") analytics.Use(r.authMiddleware.RequireAuth()) { analytics.GET("/dashboard", r.analyticsHandler.GetDashboard) analytics.GET("/volume", r.analyticsHandler.GetLetterVolume) analytics.GET("/status-distribution", r.analyticsHandler.GetStatusDistribution) analytics.GET("/priority-distribution", r.analyticsHandler.GetPriorityDistribution) analytics.GET("/department-stats", r.analyticsHandler.GetDepartmentStats) analytics.GET("/monthly-trend", r.analyticsHandler.GetMonthlyTrend) analytics.GET("/approval-metrics", r.analyticsHandler.GetApprovalMetrics) } notifications := v1.Group("/notifications") notifications.Use(r.authMiddleware.RequireAuth()) { notifications.POST("/me/trigger", r.notificationHandler.TriggerNotificationForCurrentUser) notifications.GET("/me/subscriber", r.notificationHandler.GetCurrentUserSubscriber) notifications.PUT("/me/channel", r.notificationHandler.UpdateCurrentUserSubscriberChannel) notifAdmin := notifications.Group("") notifAdmin.Use(r.authMiddleware.RequirePermissions("notification.admin")) { notifAdmin.POST("/trigger", r.notificationHandler.TriggerNotification) notifAdmin.POST("/bulk-trigger", r.notificationHandler.BulkTriggerNotification) notifAdmin.GET("/subscribers/:userId", r.notificationHandler.GetSubscriber) notifAdmin.PUT("/subscribers/channel", r.notificationHandler.UpdateSubscriberChannel) } } } }