package router import ( "encoding/json" "net/http" "os" "time" // Added this import "github.com/rede5/gohorsejobs/backend/internal/api/middleware" "github.com/rede5/gohorsejobs/backend/internal/database" "github.com/rede5/gohorsejobs/backend/internal/handlers" "github.com/rede5/gohorsejobs/backend/internal/infrastructure/persistence/postgres" "github.com/rede5/gohorsejobs/backend/internal/services" // Core Imports apiHandlers "github.com/rede5/gohorsejobs/backend/internal/api/handlers" authUC "github.com/rede5/gohorsejobs/backend/internal/core/usecases/auth" tenantUC "github.com/rede5/gohorsejobs/backend/internal/core/usecases/tenant" userUC "github.com/rede5/gohorsejobs/backend/internal/core/usecases/user" authInfra "github.com/rede5/gohorsejobs/backend/internal/infrastructure/auth" legacyMiddleware "github.com/rede5/gohorsejobs/backend/internal/middleware" // Admin Imports _ "github.com/rede5/gohorsejobs/backend/docs" // Import generated docs httpSwagger "github.com/swaggo/http-swagger/v2" ) func NewRouter() http.Handler { mux := http.NewServeMux() // Initialize Services // --- CORE ARCHITECTURE INITIALIZATION --- // Infrastructure userRepo := postgres.NewUserRepository(database.DB) companyRepo := postgres.NewCompanyRepository(database.DB) locationRepo := postgres.NewLocationRepository(database.DB) // Utils Services (Moved up for dependency injection) credentialsService := services.NewCredentialsService(database.DB) settingsService := services.NewSettingsService(database.DB) storageService := services.NewStorageService(credentialsService) fcmService := services.NewFCMService(credentialsService) cloudflareService := services.NewCloudflareService(credentialsService) emailService := services.NewEmailService(database.DB, credentialsService) locationService := services.NewLocationService(locationRepo) adminService := services.NewAdminService(database.DB) jobService := services.NewJobService(database.DB) applicationService := services.NewApplicationService(database.DB, emailService) jwtSecret := os.Getenv("JWT_SECRET") if jwtSecret == "" { // Fallback for dev, but really should be in env jwtSecret = "default-dev-secret-do-not-use-in-prod" } authService := authInfra.NewJWTService(jwtSecret, "todai-jobs") // Token Repository for Password Reset tokenRepo := postgres.NewPasswordResetTokenRepository(database.DB) // Frontend URL for reset link frontendURL := os.Getenv("FRONTEND_URL") if frontendURL == "" { frontendURL = "http://localhost:8963" } // UseCases loginUC := authUC.NewLoginUseCase(userRepo, authService) registerCandidateUC := authUC.NewRegisterCandidateUseCase(userRepo, companyRepo, authService, emailService) createCompanyUC := tenantUC.NewCreateCompanyUseCase(companyRepo, userRepo, authService) listCompaniesUC := tenantUC.NewListCompaniesUseCase(companyRepo) createUserUC := userUC.NewCreateUserUseCase(userRepo, authService) listUsersUC := userUC.NewListUsersUseCase(userRepo) deleteUserUC := userUC.NewDeleteUserUseCase(userRepo) updateUserUC := userUC.NewUpdateUserUseCase(userRepo) updatePasswordUC := userUC.NewUpdatePasswordUseCase(userRepo, authService) forgotPasswordUC := authUC.NewForgotPasswordUseCase(userRepo, tokenRepo, emailService, frontendURL) resetPasswordUC := authUC.NewResetPasswordUseCase(userRepo, tokenRepo, authService) // Admin Logic Services auditService := services.NewAuditService(database.DB) notificationService := services.NewNotificationService(database.DB, fcmService) ticketService := services.NewTicketService(database.DB) // Handlers & Middleware coreHandlers := apiHandlers.NewCoreHandlers( loginUC, registerCandidateUC, createCompanyUC, createUserUC, listUsersUC, deleteUserUC, updateUserUC, updatePasswordUC, listCompaniesUC, forgotPasswordUC, resetPasswordUC, auditService, notificationService, ticketService, adminService, credentialsService, ) authMiddleware := middleware.NewMiddleware(authService) // Chat Services appwriteService := services.NewAppwriteService(credentialsService) chatService := services.NewChatService(database.DB, appwriteService) chatHandlers := apiHandlers.NewChatHandlers(chatService) settingsHandler := apiHandlers.NewSettingsHandler(settingsService) credentialsHandler := apiHandlers.NewCredentialsHandler(credentialsService) // Added storageHandler := apiHandlers.NewStorageHandler(storageService) adminHandlers := apiHandlers.NewAdminHandlers(adminService, auditService, jobService, cloudflareService) locationHandlers := apiHandlers.NewLocationHandlers(locationService) seederService := services.NewSeederService(database.DB) seederHandlers := apiHandlers.NewSeederHandlers(seederService) // Initialize Legacy Handlers jobHandler := handlers.NewJobHandler(jobService) applicationHandler := handlers.NewApplicationHandler(applicationService) paymentHandler := handlers.NewPaymentHandler(credentialsService) // --- HEALTH CHECK --- mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "text/plain") w.Write([]byte("OK")) }) // --- ROOT ROUTE --- mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } response := map[string]interface{}{ "message": "GoHorseJobs API is running!", "docs": "/docs", "health": "/health", "version": "1.0.0", } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(response); err != nil { http.Error(w, "Internal Server Error", http.StatusInternalServerError) } }) // --- CORE ROUTES --- // Public mux.HandleFunc("POST /api/v1/auth/login", coreHandlers.Login) mux.HandleFunc("POST /api/v1/auth/logout", coreHandlers.Logout) mux.HandleFunc("POST /api/v1/auth/forgot-password", coreHandlers.ForgotPassword) mux.HandleFunc("POST /api/v1/auth/reset-password", coreHandlers.ResetPassword) mux.HandleFunc("POST /api/v1/auth/register", coreHandlers.RegisterCandidate) mux.HandleFunc("POST /api/v1/auth/register/candidate", coreHandlers.RegisterCandidate) mux.HandleFunc("POST /api/v1/auth/register/company", coreHandlers.CreateCompany) mux.HandleFunc("POST /api/v1/companies", coreHandlers.CreateCompany) // Public/Protected with RBAC (Smart Handler) mux.Handle("GET /api/v1/companies", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(coreHandlers.ListCompanies))) adminOnly := authMiddleware.RequireRoles("ADMIN", "SUPERADMIN", "admin", "superadmin") // Protected Core mux.Handle("POST /api/v1/users", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.CreateUser))) mux.Handle("GET /api/v1/users", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(coreHandlers.ListUsers)))) mux.Handle("PATCH /api/v1/users/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.UpdateUser))) mux.Handle("DELETE /api/v1/users/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.DeleteUser))) mux.Handle("PUT /api/v1/users/me", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.UpdateMe))) // New Profile Update // Job Routes mux.HandleFunc("GET /api/v1/jobs", jobHandler.GetJobs) mux.Handle("POST /api/v1/jobs", authMiddleware.HeaderAuthGuard(http.HandlerFunc(jobHandler.CreateJob))) mux.HandleFunc("GET /api/v1/jobs/{id}", jobHandler.GetJobByID) mux.Handle("PUT /api/v1/jobs/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(jobHandler.UpdateJob))) mux.Handle("DELETE /api/v1/jobs/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(jobHandler.DeleteJob))) // --- ADMIN ROUTES (Consolidated to Standard Paths with RBAC) --- // /api/v1/admin/access/roles -> /api/v1/users/roles mux.Handle("GET /api/v1/users/roles", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.ListAccessRoles)))) // /api/v1/admin/audit/logins -> /api/v1/audit/logins mux.Handle("GET /api/v1/audit/logins", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.ListLoginAudits)))) // Public /api/v1/users/me (Authenticated) mux.Handle("GET /api/v1/users/me", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.Me))) mux.Handle("PATCH /api/v1/users/me/profile", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.UpdateMyProfile))) mux.Handle("PATCH /api/v1/users/me/password", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.UpdateMyPassword))) // Company Management mux.Handle("PATCH /api/v1/companies/{id}/status", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.UpdateCompanyStatus)))) mux.Handle("PATCH /api/v1/companies/{id}", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.UpdateCompany)))) mux.Handle("DELETE /api/v1/companies/{id}", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.DeleteCompany)))) mux.Handle("GET /api/v1/jobs/moderation", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.ListJobs)))) // /api/v1/admin/jobs/{id}/status mux.Handle("PATCH /api/v1/jobs/{id}/status", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.UpdateJobStatus)))) // /api/v1/admin/jobs/{id}/duplicate -> /api/v1/jobs/{id}/duplicate mux.Handle("POST /api/v1/jobs/{id}/duplicate", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.DuplicateJob)))) // /api/v1/tags (GET public/auth, POST/PATCH admin) mux.Handle("GET /api/v1/tags", authMiddleware.HeaderAuthGuard(http.HandlerFunc(adminHandlers.ListTags))) mux.Handle("POST /api/v1/tags", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.CreateTag)))) mux.Handle("PATCH /api/v1/tags/{id}", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.UpdateTag)))) // /api/v1/admin/candidates -> /api/v1/candidates mux.Handle("GET /api/v1/candidates", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.ListCandidates)))) // Get Company by ID (Public) mux.HandleFunc("GET /api/v1/companies/{id}", coreHandlers.GetCompanyByID) // Location Routes (Public) mux.HandleFunc("GET /api/v1/locations/countries", locationHandlers.ListCountries) mux.HandleFunc("GET /api/v1/locations/countries/{id}/states", locationHandlers.ListStatesByCountry) mux.HandleFunc("GET /api/v1/locations/states/{id}/cities", locationHandlers.ListCitiesByState) mux.HandleFunc("GET /api/v1/locations/search", locationHandlers.SearchLocations) // Notifications Route mux.Handle("GET /api/v1/notifications", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.ListNotifications))) mux.Handle("POST /api/v1/tokens", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.SaveFCMToken))) // Support Ticket Routes mux.Handle("GET /api/v1/support/tickets", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.ListTickets))) mux.Handle("POST /api/v1/support/tickets", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.CreateTicket))) mux.Handle("GET /api/v1/support/tickets/all", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.ListAllTickets))) mux.Handle("GET /api/v1/support/tickets/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.GetTicket))) mux.Handle("POST /api/v1/support/tickets/{id}/messages", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.AddMessage))) mux.Handle("PATCH /api/v1/support/tickets/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.UpdateTicket))) mux.Handle("PATCH /api/v1/support/tickets/{id}/close", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.CloseTicket))) mux.Handle("DELETE /api/v1/support/tickets/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(coreHandlers.DeleteTicket))) // System Settings mux.Handle("GET /api/v1/system/settings/{key}", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(settingsHandler.GetSettings))) mux.Handle("POST /api/v1/system/settings/{key}", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(settingsHandler.SaveSettings)))) // System Credentials mux.Handle("GET /api/v1/system/credentials", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(credentialsHandler.ListCredentials)))) mux.Handle("POST /api/v1/system/credentials", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(credentialsHandler.SaveCredential)))) mux.Handle("DELETE /api/v1/system/credentials/{service}", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(credentialsHandler.DeleteCredential)))) mux.Handle("POST /api/v1/system/credentials/{service}/test", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(credentialsHandler.TestCredential)))) // Storage (Presigned URL) mux.Handle("GET /api/v1/storage/upload-url", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(storageHandler.GetUploadURL))) mux.Handle("POST /api/v1/storage/upload-url", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(storageHandler.GetUploadURL))) mux.Handle("POST /api/v1/storage/download-url", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(storageHandler.GetDownloadURL))) mux.Handle("DELETE /api/v1/storage/files", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(storageHandler.DeleteFile))) // Storage (Direct Proxy) mux.Handle("POST /api/v1/storage/upload", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(storageHandler.UploadFile))) mux.Handle("POST /api/v1/admin/storage/test-connection", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(storageHandler.TestConnection)))) mux.Handle("POST /api/v1/system/cloudflare/purge", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.PurgeCache)))) // Seeder Routes (Dev Only) mux.HandleFunc("GET /api/v1/seeder/seed/stream", seederHandlers.HandleSeedStream) mux.HandleFunc("POST /api/v1/seeder/reset", seederHandlers.HandleReset) // Email Templates & Settings (Admin Only) mux.Handle("GET /api/v1/admin/email-templates", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.ListEmailTemplates)))) mux.Handle("POST /api/v1/admin/email-templates", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.CreateEmailTemplate)))) mux.Handle("GET /api/v1/admin/email-templates/{slug}", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.GetEmailTemplate)))) mux.Handle("PUT /api/v1/admin/email-templates/{slug}", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.UpdateEmailTemplate)))) mux.Handle("DELETE /api/v1/admin/email-templates/{slug}", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.DeleteEmailTemplate)))) mux.Handle("GET /api/v1/admin/email-settings", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.GetEmailSettings)))) mux.Handle("PUT /api/v1/admin/email-settings", authMiddleware.HeaderAuthGuard(adminOnly(http.HandlerFunc(adminHandlers.UpdateEmailSettings)))) // Chat Routes mux.Handle("GET /api/v1/conversations", authMiddleware.HeaderAuthGuard(http.HandlerFunc(chatHandlers.ListConversations))) mux.Handle("GET /api/v1/conversations/{id}/messages", authMiddleware.HeaderAuthGuard(http.HandlerFunc(chatHandlers.ListMessages))) mux.Handle("POST /api/v1/conversations/{id}/messages", authMiddleware.HeaderAuthGuard(http.HandlerFunc(chatHandlers.SendMessage))) // Metrics Routes metricsService := services.NewMetricsService(database.DB) metricsHandler := handlers.NewMetricsHandler(metricsService) mux.HandleFunc("GET /api/v1/jobs/{id}/metrics", metricsHandler.GetJobMetrics) mux.HandleFunc("POST /api/v1/jobs/{id}/view", metricsHandler.RecordJobView) // Subscription Routes subService := services.NewSubscriptionService(database.DB) subHandler := handlers.NewSubscriptionHandler(subService) mux.HandleFunc("POST /api/v1/subscription/checkout", subHandler.CreateCheckoutSession) mux.HandleFunc("POST /api/v1/subscription/webhook", subHandler.HandleWebhook) // Application Routes (merged: both OptionalAuth for create + both /me endpoints) mux.Handle("POST /api/v1/applications", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(applicationHandler.CreateApplication))) mux.Handle("GET /api/v1/applications/me", authMiddleware.HeaderAuthGuard(http.HandlerFunc(applicationHandler.GetMyApplications))) mux.HandleFunc("GET /api/v1/applications", applicationHandler.GetApplications) mux.HandleFunc("GET /api/v1/applications/{id}", applicationHandler.GetApplicationByID) mux.HandleFunc("PUT /api/v1/applications/{id}/status", applicationHandler.UpdateApplicationStatus) mux.HandleFunc("DELETE /api/v1/applications/{id}", applicationHandler.DeleteApplication) // Job Alert Routes jobAlertService := services.NewJobAlertService(database.DB, emailService) jobAlertHandler := handlers.NewJobAlertHandler(jobAlertService) mux.Handle("POST /api/v1/alerts", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(jobAlertHandler.CreateAlert))) mux.Handle("GET /api/v1/alerts/me", authMiddleware.HeaderAuthGuard(http.HandlerFunc(jobAlertHandler.GetMyAlerts))) mux.Handle("DELETE /api/v1/alerts/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(jobAlertHandler.DeleteAlert))) mux.Handle("PATCH /api/v1/alerts/{id}/toggle", authMiddleware.HeaderAuthGuard(http.HandlerFunc(jobAlertHandler.ToggleAlert))) mux.HandleFunc("GET /api/v1/alerts/confirm", jobAlertHandler.ConfirmAlert) // Favorite Jobs Routes favoriteJobService := services.NewFavoriteJobService(database.DB) favoriteJobHandler := handlers.NewFavoriteJobHandler(favoriteJobService) mux.Handle("GET /api/v1/favorites", authMiddleware.HeaderAuthGuard(http.HandlerFunc(favoriteJobHandler.GetMyFavorites))) mux.Handle("POST /api/v1/favorites/{jobId}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(favoriteJobHandler.AddFavorite))) mux.Handle("DELETE /api/v1/favorites/{jobId}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(favoriteJobHandler.RemoveFavorite))) mux.Handle("GET /api/v1/favorites/{jobId}/check", authMiddleware.HeaderAuthGuard(http.HandlerFunc(favoriteJobHandler.CheckFavorite))) // Company Followers Routes companyFollowerService := services.NewCompanyFollowerService(database.DB) companyFollowerHandler := handlers.NewCompanyFollowerHandler(companyFollowerService) mux.Handle("GET /api/v1/companies/following", authMiddleware.HeaderAuthGuard(http.HandlerFunc(companyFollowerHandler.GetMyFollowing))) mux.Handle("POST /api/v1/companies/follow/{companyId}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(companyFollowerHandler.Follow))) mux.Handle("DELETE /api/v1/companies/follow/{companyId}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(companyFollowerHandler.Unfollow))) mux.Handle("GET /api/v1/companies/followed/check/{companyId}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(companyFollowerHandler.CheckFollowing))) mux.HandleFunc("GET /api/v1/companies/with-jobs", companyFollowerHandler.GetCompanies) // Video Interview Routes videoInterviewService := services.NewVideoInterviewService(database.DB) videoInterviewHandler := handlers.NewVideoInterviewHandler(videoInterviewService) mux.Handle("POST /api/v1/interviews", authMiddleware.HeaderAuthGuard(http.HandlerFunc(videoInterviewHandler.CreateInterview))) mux.Handle("GET /api/v1/interviews", authMiddleware.HeaderAuthGuard(http.HandlerFunc(videoInterviewHandler.GetCompanyInterviews))) mux.HandleFunc("GET /api/v1/interviews/by-application", videoInterviewHandler.GetInterviewsByApplication) mux.Handle("GET /api/v1/interviews/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(videoInterviewHandler.GetInterview))) mux.Handle("PUT /api/v1/interviews/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(videoInterviewHandler.UpdateInterview))) mux.Handle("POST /api/v1/interviews/{id}/feedback", authMiddleware.HeaderAuthGuard(http.HandlerFunc(videoInterviewHandler.SubmitFeedback))) mux.Handle("DELETE /api/v1/interviews/{id}", authMiddleware.HeaderAuthGuard(http.HandlerFunc(videoInterviewHandler.DeleteInterview))) // Payment Routes mux.Handle("POST /api/v1/payments/create-checkout", authMiddleware.HeaderAuthGuard(http.HandlerFunc(paymentHandler.CreateCheckout))) mux.Handle("POST /api/v1/payments/subscription-checkout", authMiddleware.OptionalHeaderAuthGuard(http.HandlerFunc(paymentHandler.SubscriptionCheckout))) mux.HandleFunc("POST /api/v1/payments/webhook", paymentHandler.HandleWebhook) mux.HandleFunc("GET /api/v1/payments/status/{id}", paymentHandler.GetPaymentStatus) // --- STORAGE ROUTES (Legacy Removed) --- // --- TICKET ROUTES --- ticketHandler := handlers.NewTicketHandler(ticketService) mux.HandleFunc("GET /api/v1/tickets", ticketHandler.GetTickets) mux.HandleFunc("POST /api/v1/tickets", ticketHandler.CreateTicket) mux.HandleFunc("GET /api/v1/tickets/{id}", ticketHandler.GetTicketByID) mux.HandleFunc("PUT /api/v1/tickets/{id}", ticketHandler.UpdateTicket) mux.HandleFunc("POST /api/v1/tickets/{id}/messages", ticketHandler.AddTicketMessage) // --- ACTIVITY LOG ROUTES --- activityLogService := services.NewActivityLogService(database.DB) activityLogHandler := handlers.NewActivityLogHandler(activityLogService) mux.HandleFunc("GET /api/v1/activity-logs/stats", activityLogHandler.GetActivityLogStats) mux.HandleFunc("GET /api/v1/activity-logs", activityLogHandler.GetActivityLogs) // --- NOTIFICATION ROUTES --- notificationHandler := handlers.NewNotificationHandler(notificationService) mux.Handle("PUT /api/v1/notifications/read-all", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.MarkAllAsRead))) mux.Handle("PUT /api/v1/notifications/{id}/read", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.MarkAsRead))) mux.Handle("PATCH /api/v1/notifications/read-all", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.MarkAllAsRead))) mux.Handle("PATCH /api/v1/notifications/{id}/read", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.MarkAsRead))) mux.Handle("POST /api/v1/notifications/fcm-token", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.RegisterFCMToken))) // Swagger Route - available at /docs mux.HandleFunc("/docs/", httpSwagger.WrapHandler) // Apply middleware chain: Security Headers -> Rate Limiting -> CORS -> Router // Order matters: outer middleware var handler http.Handler = mux handler = middleware.CORSMiddleware(handler) handler = legacyMiddleware.SanitizeMiddleware(handler) // Sanitize XSS from JSON bodies handler = legacyMiddleware.RateLimitMiddleware(100, time.Minute)(handler) // 100 req/min per IP handler = legacyMiddleware.SecurityHeadersMiddleware(handler) return handler }