refactor(go): split roadmap_handlers, academy/store, extract cmd/server/main to internal/app

roadmap_handlers.go (740 LOC) → roadmap_handlers.go, roadmap_item_handlers.go, roadmap_import_handlers.go
academy/store.go (683 LOC) → store_courses.go, store_enrollments.go
cmd/server/main.go (681 LOC) → internal/app/app.go (Run+buildRouter) + internal/app/routes.go (registerXxx helpers)
main.go reduced to 7 LOC thin entrypoint calling app.Run()

All files under 410 LOC. Zero behavior changes, same package declarations.
go vet passes on all directly-split packages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-19 09:51:11 +02:00
parent 3fb5b94905
commit 3f2aff2389
8 changed files with 1482 additions and 1557 deletions

View File

@@ -0,0 +1,161 @@
package app
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/breakpilot/ai-compliance-sdk/internal/academy"
"github.com/breakpilot/ai-compliance-sdk/internal/api/handlers"
"github.com/breakpilot/ai-compliance-sdk/internal/audit"
"github.com/breakpilot/ai-compliance-sdk/internal/config"
"github.com/breakpilot/ai-compliance-sdk/internal/iace"
"github.com/breakpilot/ai-compliance-sdk/internal/llm"
"github.com/breakpilot/ai-compliance-sdk/internal/portfolio"
"github.com/breakpilot/ai-compliance-sdk/internal/rbac"
"github.com/breakpilot/ai-compliance-sdk/internal/roadmap"
"github.com/breakpilot/ai-compliance-sdk/internal/training"
"github.com/breakpilot/ai-compliance-sdk/internal/ucca"
"github.com/breakpilot/ai-compliance-sdk/internal/whistleblower"
"github.com/breakpilot/ai-compliance-sdk/internal/workshop"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5/pgxpool"
)
// Run initializes and starts the AI Compliance SDK server.
func Run() {
cfg, err := config.Load()
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
if cfg.IsProduction() {
gin.SetMode(gin.ReleaseMode)
}
ctx := context.Background()
pool, err := pgxpool.New(ctx, cfg.DatabaseURL)
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
defer pool.Close()
if err := pool.Ping(ctx); err != nil {
log.Fatalf("Failed to ping database: %v", err)
}
log.Println("Connected to database")
router := buildRouter(cfg, pool)
srv := &http.Server{
Addr: ":" + cfg.Port,
Handler: router,
ReadTimeout: 30 * time.Second,
WriteTimeout: 5 * time.Minute,
IdleTimeout: 60 * time.Second,
}
go func() {
log.Printf("AI Compliance SDK starting on port %s", cfg.Port)
log.Printf("Environment: %s", cfg.Environment)
log.Printf("Primary LLM Provider: %s", cfg.LLMProvider)
log.Printf("Fallback LLM Provider: %s", cfg.LLMFallbackProvider)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("Server failed: %v", err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("Server forced to shutdown: %v", err)
}
log.Println("Server exited")
}
// buildRouter wires all stores, services, and handlers onto a new Gin engine.
func buildRouter(cfg *config.Config, pool *pgxpool.Pool) *gin.Engine {
// Stores
rbacStore := rbac.NewStore(pool)
auditStore := audit.NewStore(pool)
uccaStore := ucca.NewStore(pool)
escalationStore := ucca.NewEscalationStore(pool)
corpusVersionStore := ucca.NewCorpusVersionStore(pool)
roadmapStore := roadmap.NewStore(pool)
workshopStore := workshop.NewStore(pool)
portfolioStore := portfolio.NewStore(pool)
academyStore := academy.NewStore(pool)
whistleblowerStore := whistleblower.NewStore(pool)
iaceStore := iace.NewStore(pool)
trainingStore := training.NewStore(pool)
obligationsStore := ucca.NewObligationsStore(pool)
// Services
rbacService := rbac.NewService(rbacStore)
policyEngine := rbac.NewPolicyEngine(rbacService, rbacStore)
// LLM providers
providerRegistry := llm.NewProviderRegistry(cfg.LLMProvider, cfg.LLMFallbackProvider)
providerRegistry.Register(llm.NewOllamaAdapter(cfg.OllamaURL, cfg.OllamaDefaultModel))
if cfg.AnthropicAPIKey != "" {
providerRegistry.Register(llm.NewAnthropicAdapter(cfg.AnthropicAPIKey, cfg.AnthropicDefaultModel))
}
piiDetector := llm.NewPIIDetectorWithPatterns(llm.AllPIIPatterns())
ttsClient := training.NewTTSClient(cfg.TTSServiceURL)
contentGenerator := training.NewContentGenerator(providerRegistry, piiDetector, trainingStore, ttsClient)
accessGate := llm.NewAccessGate(policyEngine, piiDetector, providerRegistry)
trailBuilder := audit.NewTrailBuilder(auditStore)
exporter := audit.NewExporter(auditStore)
blockGenerator := training.NewBlockGenerator(trainingStore, contentGenerator)
// Handlers
rbacHandlers := handlers.NewRBACHandlers(rbacStore, rbacService, policyEngine)
llmHandlers := handlers.NewLLMHandlers(accessGate, providerRegistry, piiDetector, auditStore, trailBuilder)
auditHandlers := handlers.NewAuditHandlers(auditStore, exporter)
uccaHandlers := handlers.NewUCCAHandlers(uccaStore, escalationStore, providerRegistry)
escalationHandlers := handlers.NewEscalationHandlers(escalationStore, uccaStore)
roadmapHandlers := handlers.NewRoadmapHandlers(roadmapStore)
workshopHandlers := handlers.NewWorkshopHandlers(workshopStore)
portfolioHandlers := handlers.NewPortfolioHandlers(portfolioStore)
academyHandlers := handlers.NewAcademyHandlers(academyStore, trainingStore)
whistleblowerHandlers := handlers.NewWhistleblowerHandlers(whistleblowerStore)
iaceHandler := handlers.NewIACEHandler(iaceStore, providerRegistry)
trainingHandlers := handlers.NewTrainingHandlers(trainingStore, contentGenerator, blockGenerator, ttsClient)
ragHandlers := handlers.NewRAGHandlers(corpusVersionStore)
obligationsHandlers := handlers.NewObligationsHandlersWithStore(obligationsStore)
rbacMiddleware := rbac.NewMiddleware(rbacService, policyEngine)
// Router
router := gin.Default()
router.Use(cors.New(cors.Config{
AllowOrigins: cfg.AllowedOrigins,
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-User-ID", "X-Tenant-ID", "X-Namespace-ID", "X-Tenant-Slug"},
ExposeHeaders: []string{"Content-Length", "Content-Disposition"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
router.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "healthy",
"timestamp": time.Now().UTC().Format(time.RFC3339),
})
})
registerRoutes(router, rbacMiddleware,
rbacHandlers, llmHandlers, auditHandlers,
uccaHandlers, escalationHandlers, obligationsHandlers, ragHandlers,
roadmapHandlers, workshopHandlers, portfolioHandlers,
academyHandlers, trainingHandlers, whistleblowerHandlers, iaceHandler)
return router
}

View File

@@ -0,0 +1,409 @@
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)
}
}