package app import ( "net/http" "time" "github.com/breakpilot/ai-compliance-sdk/internal/api/handlers" "github.com/breakpilot/ai-compliance-sdk/internal/rbac" "github.com/gin-gonic/gin" ) func registerRoutes( router *gin.Engine, rbacMiddleware *rbac.Middleware, rbacHandlers *handlers.RBACHandlers, llmHandlers *handlers.LLMHandlers, auditHandlers *handlers.AuditHandlers, uccaHandlers *handlers.UCCAHandlers, escalationHandlers *handlers.EscalationHandlers, obligationsHandlers *handlers.ObligationsHandlers, ragHandlers *handlers.RAGHandlers, roadmapHandlers *handlers.RoadmapHandlers, workshopHandlers *handlers.WorkshopHandlers, portfolioHandlers *handlers.PortfolioHandlers, academyHandlers *handlers.AcademyHandlers, trainingHandlers *handlers.TrainingHandlers, whistleblowerHandlers *handlers.WhistleblowerHandlers, iaceHandler *handlers.IACEHandler, ) { v1 := router.Group("/sdk/v1") { v1.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": "ok", "timestamp": time.Now().UTC()}) }) v1.Use(rbacMiddleware.ExtractUserContext()) registerRBACRoutes(v1, rbacHandlers) registerLLMRoutes(v1, rbacMiddleware, llmHandlers) registerAuditRoutes(v1, rbacMiddleware, auditHandlers) registerUCCARoutes(v1, uccaHandlers, escalationHandlers, obligationsHandlers) registerRAGRoutes(v1, ragHandlers) registerRoadmapRoutes(v1, roadmapHandlers) registerWorkshopRoutes(v1, workshopHandlers) registerPortfolioRoutes(v1, portfolioHandlers) registerAcademyRoutes(v1, academyHandlers) registerTrainingRoutes(v1, trainingHandlers) registerWhistleblowerRoutes(v1, whistleblowerHandlers) registerIACERoutes(v1, iaceHandler) } } func registerRBACRoutes(v1 *gin.RouterGroup, h *handlers.RBACHandlers) { tenants := v1.Group("/tenants") { tenants.GET("", h.ListTenants) tenants.GET("/:id", h.GetTenant) tenants.POST("", h.CreateTenant) tenants.PUT("/:id", h.UpdateTenant) tenants.GET("/:id/namespaces", h.ListNamespaces) tenants.POST("/:id/namespaces", h.CreateNamespace) } v1.GET("/namespaces/:id", h.GetNamespace) roles := v1.Group("/roles") { roles.GET("", h.ListRoles) roles.GET("/system", h.ListSystemRoles) roles.GET("/:id", h.GetRole) roles.POST("", h.CreateRole) } userRoles := v1.Group("/user-roles") { userRoles.POST("", h.AssignRole) userRoles.DELETE("/:userId/:roleId", h.RevokeRole) userRoles.GET("/:userId", h.GetUserRoles) } permissions := v1.Group("/permissions") { permissions.GET("/effective", h.GetEffectivePermissions) permissions.GET("/context", h.GetUserContext) permissions.GET("/check", h.CheckPermission) } policies := v1.Group("/llm/policies") { policies.GET("", h.ListLLMPolicies) policies.GET("/:id", h.GetLLMPolicy) policies.POST("", h.CreateLLMPolicy) policies.PUT("/:id", h.UpdateLLMPolicy) policies.DELETE("/:id", h.DeleteLLMPolicy) } } func registerLLMRoutes(v1 *gin.RouterGroup, mw *rbac.Middleware, h *handlers.LLMHandlers) { llmRoutes := v1.Group("/llm") llmRoutes.Use(mw.RequireLLMAccess()) { llmRoutes.POST("/chat", h.Chat) llmRoutes.POST("/complete", h.Complete) llmRoutes.GET("/models", h.ListModels) llmRoutes.GET("/providers/status", h.GetProviderStatus) llmRoutes.POST("/analyze", h.AnalyzeText) llmRoutes.POST("/redact", h.RedactText) } } func registerAuditRoutes(v1 *gin.RouterGroup, mw *rbac.Middleware, h *handlers.AuditHandlers) { auditRoutes := v1.Group("/audit") auditRoutes.Use(mw.RequireAnyPermission(rbac.PermissionAuditAll, rbac.PermissionAuditRead, rbac.PermissionAuditLogRead)) { auditRoutes.GET("/llm", h.QueryLLMAudit) auditRoutes.GET("/general", h.QueryGeneralAudit) auditRoutes.GET("/llm-operations", h.QueryLLMAudit) auditRoutes.GET("/trail", h.QueryGeneralAudit) auditRoutes.GET("/usage", h.GetUsageStats) auditRoutes.GET("/compliance-report", h.GetComplianceReport) auditRoutes.GET("/export/llm", h.ExportLLMAudit) auditRoutes.GET("/export/general", h.ExportGeneralAudit) auditRoutes.GET("/export/compliance", h.ExportComplianceReport) } } func registerUCCARoutes(v1 *gin.RouterGroup, h *handlers.UCCAHandlers, eh *handlers.EscalationHandlers, oh *handlers.ObligationsHandlers) { uccaRoutes := v1.Group("/ucca") { uccaRoutes.POST("/assess", h.Assess) uccaRoutes.GET("/assessments", h.ListAssessments) uccaRoutes.GET("/assessments/:id", h.GetAssessment) uccaRoutes.PUT("/assessments/:id", h.UpdateAssessment) uccaRoutes.DELETE("/assessments/:id", h.DeleteAssessment) uccaRoutes.POST("/assessments/:id/explain", h.Explain) uccaRoutes.GET("/patterns", h.ListPatterns) uccaRoutes.GET("/examples", h.ListExamples) uccaRoutes.GET("/rules", h.ListRules) uccaRoutes.GET("/controls", h.ListControls) uccaRoutes.GET("/problem-solutions", h.ListProblemSolutions) uccaRoutes.GET("/export/:id", h.Export) uccaRoutes.GET("/escalations", eh.ListEscalations) uccaRoutes.GET("/escalations/stats", eh.GetEscalationStats) uccaRoutes.GET("/escalations/:id", eh.GetEscalation) uccaRoutes.POST("/escalations", eh.CreateEscalation) uccaRoutes.POST("/escalations/:id/assign", eh.AssignEscalation) uccaRoutes.POST("/escalations/:id/review", eh.StartReview) uccaRoutes.POST("/escalations/:id/decide", eh.DecideEscalation) oh.RegisterRoutes(uccaRoutes) } } func registerRAGRoutes(v1 *gin.RouterGroup, h *handlers.RAGHandlers) { ragRoutes := v1.Group("/rag") { ragRoutes.POST("/search", h.Search) ragRoutes.GET("/regulations", h.ListRegulations) ragRoutes.GET("/corpus-status", h.CorpusStatus) ragRoutes.GET("/corpus-versions/:collection", h.CorpusVersionHistory) ragRoutes.GET("/scroll", h.HandleScrollChunks) } } func registerRoadmapRoutes(v1 *gin.RouterGroup, h *handlers.RoadmapHandlers) { roadmapRoutes := v1.Group("/roadmaps") { roadmapRoutes.POST("", h.CreateRoadmap) roadmapRoutes.GET("", h.ListRoadmaps) roadmapRoutes.GET("/:id", h.GetRoadmap) roadmapRoutes.PUT("/:id", h.UpdateRoadmap) roadmapRoutes.DELETE("/:id", h.DeleteRoadmap) roadmapRoutes.GET("/:id/stats", h.GetRoadmapStats) roadmapRoutes.POST("/:id/items", h.CreateItem) roadmapRoutes.GET("/:id/items", h.ListItems) roadmapRoutes.POST("/import/upload", h.UploadImport) roadmapRoutes.GET("/import/:jobId", h.GetImportJob) roadmapRoutes.POST("/import/:jobId/confirm", h.ConfirmImport) } roadmapItemRoutes := v1.Group("/roadmap-items") { roadmapItemRoutes.GET("/:id", h.GetItem) roadmapItemRoutes.PUT("/:id", h.UpdateItem) roadmapItemRoutes.PATCH("/:id/status", h.UpdateItemStatus) roadmapItemRoutes.DELETE("/:id", h.DeleteItem) } } func registerWorkshopRoutes(v1 *gin.RouterGroup, h *handlers.WorkshopHandlers) { workshopRoutes := v1.Group("/workshops") { workshopRoutes.POST("", h.CreateSession) workshopRoutes.GET("", h.ListSessions) workshopRoutes.GET("/:id", h.GetSession) workshopRoutes.PUT("/:id", h.UpdateSession) workshopRoutes.DELETE("/:id", h.DeleteSession) workshopRoutes.POST("/:id/start", h.StartSession) workshopRoutes.POST("/:id/pause", h.PauseSession) workshopRoutes.POST("/:id/complete", h.CompleteSession) workshopRoutes.GET("/:id/participants", h.ListParticipants) workshopRoutes.PUT("/:id/participants/:participantId", h.UpdateParticipant) workshopRoutes.DELETE("/:id/participants/:participantId", h.RemoveParticipant) workshopRoutes.POST("/:id/responses", h.SubmitResponse) workshopRoutes.GET("/:id/responses", h.GetResponses) workshopRoutes.POST("/:id/comments", h.AddComment) workshopRoutes.GET("/:id/comments", h.GetComments) workshopRoutes.POST("/:id/advance", h.AdvanceStep) workshopRoutes.POST("/:id/goto", h.GoToStep) workshopRoutes.GET("/:id/stats", h.GetSessionStats) workshopRoutes.GET("/:id/summary", h.GetSessionSummary) workshopRoutes.GET("/:id/export", h.ExportSession) workshopRoutes.POST("/join/:code", h.JoinSession) } } func registerPortfolioRoutes(v1 *gin.RouterGroup, h *handlers.PortfolioHandlers) { portfolioRoutes := v1.Group("/portfolios") { portfolioRoutes.POST("", h.CreatePortfolio) portfolioRoutes.GET("", h.ListPortfolios) portfolioRoutes.GET("/:id", h.GetPortfolio) portfolioRoutes.PUT("/:id", h.UpdatePortfolio) portfolioRoutes.DELETE("/:id", h.DeletePortfolio) portfolioRoutes.POST("/:id/items", h.AddItem) portfolioRoutes.GET("/:id/items", h.ListItems) portfolioRoutes.POST("/:id/items/bulk", h.BulkAddItems) portfolioRoutes.DELETE("/:id/items/:itemId", h.RemoveItem) portfolioRoutes.PUT("/:id/items/order", h.ReorderItems) portfolioRoutes.GET("/:id/stats", h.GetPortfolioStats) portfolioRoutes.GET("/:id/activity", h.GetPortfolioActivity) portfolioRoutes.POST("/:id/recalculate", h.RecalculateMetrics) portfolioRoutes.POST("/:id/submit-review", h.SubmitForReview) portfolioRoutes.POST("/:id/approve", h.ApprovePortfolio) portfolioRoutes.POST("/merge", h.MergePortfolios) portfolioRoutes.POST("/compare", h.ComparePortfolios) } } func registerAcademyRoutes(v1 *gin.RouterGroup, h *handlers.AcademyHandlers) { academyRoutes := v1.Group("/academy") { academyRoutes.POST("/courses", h.CreateCourse) academyRoutes.GET("/courses", h.ListCourses) academyRoutes.GET("/courses/:id", h.GetCourse) academyRoutes.PUT("/courses/:id", h.UpdateCourse) academyRoutes.DELETE("/courses/:id", h.DeleteCourse) academyRoutes.POST("/enrollments", h.CreateEnrollment) academyRoutes.GET("/enrollments", h.ListEnrollments) academyRoutes.PUT("/enrollments/:id/progress", h.UpdateProgress) academyRoutes.POST("/enrollments/:id/complete", h.CompleteEnrollment) academyRoutes.GET("/certificates/:id", h.GetCertificate) academyRoutes.POST("/enrollments/:id/certificate", h.GenerateCertificate) academyRoutes.POST("/courses/:id/quiz", h.SubmitQuiz) academyRoutes.PUT("/lessons/:id", h.UpdateLesson) academyRoutes.POST("/lessons/:id/quiz-test", h.TestQuiz) academyRoutes.GET("/stats", h.GetStatistics) academyRoutes.POST("/courses/generate", h.GenerateCourseFromTraining) academyRoutes.POST("/courses/generate-all", h.GenerateAllCourses) academyRoutes.GET("/certificates/:id/pdf", h.DownloadCertificatePDF) } } func registerTrainingRoutes(v1 *gin.RouterGroup, h *handlers.TrainingHandlers) { trainingRoutes := v1.Group("/training") { trainingRoutes.GET("/modules", h.ListModules) trainingRoutes.GET("/modules/:id", h.GetModule) trainingRoutes.POST("/modules", h.CreateModule) trainingRoutes.PUT("/modules/:id", h.UpdateModule) trainingRoutes.DELETE("/modules/:id", h.DeleteModule) trainingRoutes.GET("/matrix", h.GetMatrix) trainingRoutes.GET("/matrix/:role", h.GetMatrixForRole) trainingRoutes.POST("/matrix", h.SetMatrixEntry) trainingRoutes.DELETE("/matrix/:role/:moduleId", h.DeleteMatrixEntry) trainingRoutes.POST("/assignments/compute", h.ComputeAssignments) trainingRoutes.GET("/assignments", h.ListAssignments) trainingRoutes.GET("/assignments/:id", h.GetAssignment) trainingRoutes.POST("/assignments/:id/start", h.StartAssignment) trainingRoutes.POST("/assignments/:id/progress", h.UpdateAssignmentProgress) trainingRoutes.POST("/assignments/:id/complete", h.CompleteAssignment) trainingRoutes.PUT("/assignments/:id", h.UpdateAssignment) trainingRoutes.GET("/quiz/:moduleId", h.GetQuiz) trainingRoutes.POST("/quiz/:moduleId/submit", h.SubmitQuiz) trainingRoutes.GET("/quiz/attempts/:assignmentId", h.GetQuizAttempts) trainingRoutes.POST("/content/generate", h.GenerateContent) trainingRoutes.POST("/content/generate-quiz", h.GenerateQuiz) trainingRoutes.POST("/content/generate-all", h.GenerateAllContent) trainingRoutes.POST("/content/generate-all-quiz", h.GenerateAllQuizzes) trainingRoutes.GET("/content/:moduleId", h.GetContent) trainingRoutes.POST("/content/:moduleId/publish", func(c *gin.Context) { c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("moduleId")}) h.PublishContent(c) }) trainingRoutes.POST("/content/:moduleId/generate-audio", h.GenerateAudio) trainingRoutes.POST("/content/:moduleId/generate-video", h.GenerateVideo) trainingRoutes.POST("/content/:moduleId/preview-script", h.PreviewVideoScript) trainingRoutes.GET("/media/module/:moduleId", h.GetModuleMedia) trainingRoutes.GET("/media/:mediaId/url", func(c *gin.Context) { c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("mediaId")}) h.GetMediaURL(c) }) trainingRoutes.POST("/media/:mediaId/publish", func(c *gin.Context) { c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("mediaId")}) h.PublishMedia(c) }) trainingRoutes.GET("/media/:mediaId/stream", func(c *gin.Context) { c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("mediaId")}) h.StreamMedia(c) }) trainingRoutes.GET("/deadlines", h.GetDeadlines) trainingRoutes.GET("/deadlines/overdue", h.GetOverdueDeadlines) trainingRoutes.POST("/escalation/check", h.CheckEscalation) trainingRoutes.GET("/audit-log", h.GetAuditLog) trainingRoutes.GET("/stats", h.GetStats) trainingRoutes.POST("/certificates/generate/:assignmentId", h.GenerateCertificate) trainingRoutes.GET("/certificates", h.ListCertificates) trainingRoutes.GET("/certificates/:id/verify", h.VerifyCertificate) trainingRoutes.GET("/certificates/:id/pdf", h.DownloadCertificatePDF) trainingRoutes.GET("/blocks", h.ListBlockConfigs) trainingRoutes.POST("/blocks", h.CreateBlockConfig) trainingRoutes.GET("/blocks/:id", h.GetBlockConfig) trainingRoutes.PUT("/blocks/:id", h.UpdateBlockConfig) trainingRoutes.DELETE("/blocks/:id", h.DeleteBlockConfig) trainingRoutes.POST("/blocks/:id/preview", h.PreviewBlock) trainingRoutes.POST("/blocks/:id/generate", h.GenerateBlock) trainingRoutes.GET("/blocks/:id/controls", h.GetBlockControls) trainingRoutes.GET("/canonical/controls", h.ListCanonicalControls) trainingRoutes.GET("/canonical/meta", h.GetCanonicalMeta) trainingRoutes.POST("/content/:moduleId/generate-interactive", h.GenerateInteractiveVideo) trainingRoutes.GET("/content/:moduleId/interactive-manifest", h.GetInteractiveManifest) trainingRoutes.POST("/checkpoints/:checkpointId/submit", h.SubmitCheckpointQuiz) trainingRoutes.GET("/checkpoints/progress/:assignmentId", h.GetCheckpointProgress) } } func registerWhistleblowerRoutes(v1 *gin.RouterGroup, h *handlers.WhistleblowerHandlers) { wbRoutes := v1.Group("/whistleblower") { wbRoutes.POST("/reports/submit", h.SubmitReport) wbRoutes.GET("/reports/access/:accessKey", h.GetReportByAccessKey) wbRoutes.POST("/reports/access/:accessKey/messages", h.SendPublicMessage) wbRoutes.GET("/reports", h.ListReports) wbRoutes.GET("/reports/:id", h.GetReport) wbRoutes.PUT("/reports/:id", h.UpdateReport) wbRoutes.DELETE("/reports/:id", h.DeleteReport) wbRoutes.POST("/reports/:id/acknowledge", h.AcknowledgeReport) wbRoutes.POST("/reports/:id/investigate", h.StartInvestigation) wbRoutes.POST("/reports/:id/measures", h.AddMeasure) wbRoutes.POST("/reports/:id/close", h.CloseReport) wbRoutes.POST("/reports/:id/messages", h.SendAdminMessage) wbRoutes.GET("/reports/:id/messages", h.ListMessages) wbRoutes.GET("/stats", h.GetStatistics) } } func registerIACERoutes(v1 *gin.RouterGroup, h *handlers.IACEHandler) { iaceRoutes := v1.Group("/iace") { iaceRoutes.GET("/hazard-library", h.ListHazardLibrary) iaceRoutes.GET("/controls-library", h.ListControlsLibrary) iaceRoutes.GET("/lifecycle-phases", h.ListLifecyclePhases) iaceRoutes.GET("/roles", h.ListRoles) iaceRoutes.GET("/evidence-types", h.ListEvidenceTypes) iaceRoutes.GET("/protective-measures-library", h.ListProtectiveMeasures) iaceRoutes.GET("/component-library", h.ListComponentLibrary) iaceRoutes.GET("/energy-sources", h.ListEnergySources) iaceRoutes.GET("/tags", h.ListTags) iaceRoutes.GET("/hazard-patterns", h.ListHazardPatterns) iaceRoutes.POST("/projects", h.CreateProject) iaceRoutes.GET("/projects", h.ListProjects) iaceRoutes.GET("/projects/:id", h.GetProject) iaceRoutes.PUT("/projects/:id", h.UpdateProject) iaceRoutes.DELETE("/projects/:id", h.ArchiveProject) iaceRoutes.POST("/projects/:id/init-from-profile", h.InitFromProfile) iaceRoutes.POST("/projects/:id/completeness-check", h.CheckCompleteness) iaceRoutes.POST("/projects/:id/components", h.CreateComponent) iaceRoutes.GET("/projects/:id/components", h.ListComponents) iaceRoutes.PUT("/projects/:id/components/:cid", h.UpdateComponent) iaceRoutes.DELETE("/projects/:id/components/:cid", h.DeleteComponent) iaceRoutes.POST("/projects/:id/classify", h.Classify) iaceRoutes.GET("/projects/:id/classifications", h.GetClassifications) iaceRoutes.POST("/projects/:id/classify/:regulation", h.ClassifySingle) iaceRoutes.POST("/projects/:id/hazards", h.CreateHazard) iaceRoutes.GET("/projects/:id/hazards", h.ListHazards) iaceRoutes.PUT("/projects/:id/hazards/:hid", h.UpdateHazard) iaceRoutes.POST("/projects/:id/hazards/suggest", h.SuggestHazards) iaceRoutes.POST("/projects/:id/match-patterns", h.MatchPatterns) iaceRoutes.POST("/projects/:id/apply-patterns", h.ApplyPatternResults) iaceRoutes.POST("/projects/:id/hazards/:hid/suggest-measures", h.SuggestMeasuresForHazard) iaceRoutes.POST("/projects/:id/mitigations/:mid/suggest-evidence", h.SuggestEvidenceForMitigation) iaceRoutes.POST("/projects/:id/hazards/:hid/assess", h.AssessRisk) iaceRoutes.GET("/projects/:id/risk-summary", h.GetRiskSummary) iaceRoutes.POST("/projects/:id/hazards/:hid/reassess", h.ReassessRisk) iaceRoutes.POST("/projects/:id/hazards/:hid/mitigations", h.CreateMitigation) iaceRoutes.PUT("/mitigations/:mid", h.UpdateMitigation) iaceRoutes.POST("/mitigations/:mid/verify", h.VerifyMitigation) iaceRoutes.POST("/projects/:id/validate-mitigation-hierarchy", h.ValidateMitigationHierarchy) iaceRoutes.POST("/projects/:id/evidence", h.UploadEvidence) iaceRoutes.GET("/projects/:id/evidence", h.ListEvidence) iaceRoutes.POST("/projects/:id/verification-plan", h.CreateVerificationPlan) iaceRoutes.PUT("/verification-plan/:vid", h.UpdateVerificationPlan) iaceRoutes.POST("/verification-plan/:vid/complete", h.CompleteVerification) iaceRoutes.POST("/projects/:id/tech-file/generate", h.GenerateTechFile) iaceRoutes.GET("/projects/:id/tech-file", h.ListTechFileSections) iaceRoutes.PUT("/projects/:id/tech-file/:section", h.UpdateTechFileSection) iaceRoutes.POST("/projects/:id/tech-file/:section/approve", h.ApproveTechFileSection) iaceRoutes.POST("/projects/:id/tech-file/:section/generate", h.GenerateSingleSection) iaceRoutes.GET("/projects/:id/tech-file/export", h.ExportTechFile) iaceRoutes.POST("/projects/:id/monitoring", h.CreateMonitoringEvent) iaceRoutes.GET("/projects/:id/monitoring", h.ListMonitoringEvents) iaceRoutes.PUT("/projects/:id/monitoring/:eid", h.UpdateMonitoringEvent) iaceRoutes.GET("/projects/:id/audit-trail", h.GetAuditTrail) iaceRoutes.POST("/library-search", h.SearchLibrary) iaceRoutes.POST("/projects/:id/tech-file/:section/enrich", h.EnrichTechFileSection) } }