package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "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/llm" "github.com/breakpilot/ai-compliance-sdk/internal/rbac" "github.com/breakpilot/ai-compliance-sdk/internal/academy" "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/iace" "github.com/breakpilot/ai-compliance-sdk/internal/workshop" "github.com/breakpilot/ai-compliance-sdk/internal/portfolio" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "github.com/jackc/pgx/v5/pgxpool" ) func main() { // Load configuration cfg, err := config.Load() if err != nil { log.Fatalf("Failed to load configuration: %v", err) } // Set Gin mode if cfg.IsProduction() { gin.SetMode(gin.ReleaseMode) } // Connect to database 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() // Verify connection if err := pool.Ping(ctx); err != nil { log.Fatalf("Failed to ping database: %v", err) } log.Println("Connected to database") // Initialize 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) // Initialize services rbacService := rbac.NewService(rbacStore) policyEngine := rbac.NewPolicyEngine(rbacService, rbacStore) // Initialize LLM providers providerRegistry := llm.NewProviderRegistry(cfg.LLMProvider, cfg.LLMFallbackProvider) // Register Ollama adapter ollamaAdapter := llm.NewOllamaAdapter(cfg.OllamaURL, cfg.OllamaDefaultModel) providerRegistry.Register(ollamaAdapter) // Register Anthropic adapter if API key is configured if cfg.AnthropicAPIKey != "" { anthropicAdapter := llm.NewAnthropicAdapter(cfg.AnthropicAPIKey, cfg.AnthropicDefaultModel) providerRegistry.Register(anthropicAdapter) } // Initialize PII detector piiDetector := llm.NewPIIDetectorWithPatterns(llm.AllPIIPatterns()) // Initialize TTS client and content generator for training ttsClient := training.NewTTSClient(cfg.TTSServiceURL) contentGenerator := training.NewContentGenerator(providerRegistry, piiDetector, trainingStore, ttsClient) // Initialize access gate accessGate := llm.NewAccessGate(policyEngine, piiDetector, providerRegistry) // Initialize audit components trailBuilder := audit.NewTrailBuilder(auditStore) exporter := audit.NewExporter(auditStore) // Initialize 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) blockGenerator := training.NewBlockGenerator(trainingStore, contentGenerator) trainingHandlers := handlers.NewTrainingHandlers(trainingStore, contentGenerator, blockGenerator, ttsClient) ragHandlers := handlers.NewRAGHandlers(corpusVersionStore) // Initialize obligations framework (v2 with TOM mapping) obligationsStore := ucca.NewObligationsStore(pool) obligationsHandlers := handlers.NewObligationsHandlersWithStore(obligationsStore) // Initialize middleware rbacMiddleware := rbac.NewMiddleware(rbacService, policyEngine) // Create Gin router router := gin.Default() // CORS configuration 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, })) // Health check router.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "status": "healthy", "timestamp": time.Now().UTC().Format(time.RFC3339), }) }) // API v1 routes v1 := router.Group("/sdk/v1") { // Public routes (no auth required) v1.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": "ok"}) }) // Apply user context extraction middleware v1.Use(rbacMiddleware.ExtractUserContext()) // Tenant routes tenants := v1.Group("/tenants") { tenants.GET("", rbacHandlers.ListTenants) tenants.GET("/:id", rbacHandlers.GetTenant) tenants.POST("", rbacHandlers.CreateTenant) tenants.PUT("/:id", rbacHandlers.UpdateTenant) // Tenant namespaces (use :id to avoid route conflict) tenants.GET("/:id/namespaces", rbacHandlers.ListNamespaces) tenants.POST("/:id/namespaces", rbacHandlers.CreateNamespace) } // Namespace routes namespaces := v1.Group("/namespaces") { namespaces.GET("/:id", rbacHandlers.GetNamespace) } // Role routes roles := v1.Group("/roles") { roles.GET("", rbacHandlers.ListRoles) roles.GET("/system", rbacHandlers.ListSystemRoles) roles.GET("/:id", rbacHandlers.GetRole) roles.POST("", rbacHandlers.CreateRole) } // User role routes userRoles := v1.Group("/user-roles") { userRoles.POST("", rbacHandlers.AssignRole) userRoles.DELETE("/:userId/:roleId", rbacHandlers.RevokeRole) userRoles.GET("/:userId", rbacHandlers.GetUserRoles) } // Permission routes permissions := v1.Group("/permissions") { permissions.GET("/effective", rbacHandlers.GetEffectivePermissions) permissions.GET("/context", rbacHandlers.GetUserContext) permissions.GET("/check", rbacHandlers.CheckPermission) } // LLM Policy routes policies := v1.Group("/llm/policies") { policies.GET("", rbacHandlers.ListLLMPolicies) policies.GET("/:id", rbacHandlers.GetLLMPolicy) policies.POST("", rbacHandlers.CreateLLMPolicy) policies.PUT("/:id", rbacHandlers.UpdateLLMPolicy) policies.DELETE("/:id", rbacHandlers.DeleteLLMPolicy) } // LLM routes (require LLM permission) llmRoutes := v1.Group("/llm") llmRoutes.Use(rbacMiddleware.RequireLLMAccess()) { llmRoutes.POST("/chat", llmHandlers.Chat) llmRoutes.POST("/complete", llmHandlers.Complete) llmRoutes.GET("/models", llmHandlers.ListModels) llmRoutes.GET("/providers/status", llmHandlers.GetProviderStatus) llmRoutes.POST("/analyze", llmHandlers.AnalyzeText) llmRoutes.POST("/redact", llmHandlers.RedactText) } // Audit routes (require audit permission) auditRoutes := v1.Group("/audit") auditRoutes.Use(rbacMiddleware.RequireAnyPermission(rbac.PermissionAuditAll, rbac.PermissionAuditRead, rbac.PermissionAuditLogRead)) { auditRoutes.GET("/llm", auditHandlers.QueryLLMAudit) auditRoutes.GET("/general", auditHandlers.QueryGeneralAudit) auditRoutes.GET("/llm-operations", auditHandlers.QueryLLMAudit) // Alias auditRoutes.GET("/trail", auditHandlers.QueryGeneralAudit) // Alias auditRoutes.GET("/usage", auditHandlers.GetUsageStats) auditRoutes.GET("/compliance-report", auditHandlers.GetComplianceReport) // Export routes auditRoutes.GET("/export/llm", auditHandlers.ExportLLMAudit) auditRoutes.GET("/export/general", auditHandlers.ExportGeneralAudit) auditRoutes.GET("/export/compliance", auditHandlers.ExportComplianceReport) } // UCCA routes - Use-Case Compliance & Feasibility Advisor uccaRoutes := v1.Group("/ucca") { // Main assessment endpoint uccaRoutes.POST("/assess", uccaHandlers.Assess) // Assessment management uccaRoutes.GET("/assessments", uccaHandlers.ListAssessments) uccaRoutes.GET("/assessments/:id", uccaHandlers.GetAssessment) uccaRoutes.PUT("/assessments/:id", uccaHandlers.UpdateAssessment) uccaRoutes.DELETE("/assessments/:id", uccaHandlers.DeleteAssessment) // LLM explanation uccaRoutes.POST("/assessments/:id/explain", uccaHandlers.Explain) // Catalogs (patterns, examples, rules, controls, problem-solutions) uccaRoutes.GET("/patterns", uccaHandlers.ListPatterns) uccaRoutes.GET("/examples", uccaHandlers.ListExamples) uccaRoutes.GET("/rules", uccaHandlers.ListRules) uccaRoutes.GET("/controls", uccaHandlers.ListControls) uccaRoutes.GET("/problem-solutions", uccaHandlers.ListProblemSolutions) // Export uccaRoutes.GET("/export/:id", uccaHandlers.Export) // Escalation management (assessment-review workflows) uccaRoutes.GET("/escalations", escalationHandlers.ListEscalations) uccaRoutes.GET("/escalations/stats", escalationHandlers.GetEscalationStats) uccaRoutes.GET("/escalations/:id", escalationHandlers.GetEscalation) uccaRoutes.POST("/escalations", escalationHandlers.CreateEscalation) uccaRoutes.POST("/escalations/:id/assign", escalationHandlers.AssignEscalation) uccaRoutes.POST("/escalations/:id/review", escalationHandlers.StartReview) uccaRoutes.POST("/escalations/:id/decide", escalationHandlers.DecideEscalation) // Obligations framework (v2 with TOM mapping) obligationsHandlers.RegisterRoutes(uccaRoutes) } // RAG routes - Legal Corpus Search & Versioning ragRoutes := v1.Group("/rag") { ragRoutes.POST("/search", ragHandlers.Search) ragRoutes.GET("/regulations", ragHandlers.ListRegulations) ragRoutes.GET("/corpus-status", ragHandlers.CorpusStatus) ragRoutes.GET("/corpus-versions/:collection", ragHandlers.CorpusVersionHistory) ragRoutes.GET("/scroll", ragHandlers.HandleScrollChunks) } // Roadmap routes - Compliance Implementation Roadmaps roadmapRoutes := v1.Group("/roadmaps") { // Roadmap CRUD roadmapRoutes.POST("", roadmapHandlers.CreateRoadmap) roadmapRoutes.GET("", roadmapHandlers.ListRoadmaps) roadmapRoutes.GET("/:id", roadmapHandlers.GetRoadmap) roadmapRoutes.PUT("/:id", roadmapHandlers.UpdateRoadmap) roadmapRoutes.DELETE("/:id", roadmapHandlers.DeleteRoadmap) roadmapRoutes.GET("/:id/stats", roadmapHandlers.GetRoadmapStats) // Roadmap items roadmapRoutes.POST("/:id/items", roadmapHandlers.CreateItem) roadmapRoutes.GET("/:id/items", roadmapHandlers.ListItems) // Import workflow roadmapRoutes.POST("/import/upload", roadmapHandlers.UploadImport) roadmapRoutes.GET("/import/:jobId", roadmapHandlers.GetImportJob) roadmapRoutes.POST("/import/:jobId/confirm", roadmapHandlers.ConfirmImport) } // Roadmap item routes (separate group for item-level operations) roadmapItemRoutes := v1.Group("/roadmap-items") { roadmapItemRoutes.GET("/:id", roadmapHandlers.GetItem) roadmapItemRoutes.PUT("/:id", roadmapHandlers.UpdateItem) roadmapItemRoutes.PATCH("/:id/status", roadmapHandlers.UpdateItemStatus) roadmapItemRoutes.DELETE("/:id", roadmapHandlers.DeleteItem) } // Workshop routes - Collaborative Compliance Workshops workshopRoutes := v1.Group("/workshops") { // Session CRUD workshopRoutes.POST("", workshopHandlers.CreateSession) workshopRoutes.GET("", workshopHandlers.ListSessions) workshopRoutes.GET("/:id", workshopHandlers.GetSession) workshopRoutes.PUT("/:id", workshopHandlers.UpdateSession) workshopRoutes.DELETE("/:id", workshopHandlers.DeleteSession) // Session lifecycle workshopRoutes.POST("/:id/start", workshopHandlers.StartSession) workshopRoutes.POST("/:id/pause", workshopHandlers.PauseSession) workshopRoutes.POST("/:id/complete", workshopHandlers.CompleteSession) // Participants workshopRoutes.GET("/:id/participants", workshopHandlers.ListParticipants) workshopRoutes.PUT("/:id/participants/:participantId", workshopHandlers.UpdateParticipant) workshopRoutes.DELETE("/:id/participants/:participantId", workshopHandlers.RemoveParticipant) // Responses workshopRoutes.POST("/:id/responses", workshopHandlers.SubmitResponse) workshopRoutes.GET("/:id/responses", workshopHandlers.GetResponses) // Comments workshopRoutes.POST("/:id/comments", workshopHandlers.AddComment) workshopRoutes.GET("/:id/comments", workshopHandlers.GetComments) // Wizard navigation workshopRoutes.POST("/:id/advance", workshopHandlers.AdvanceStep) workshopRoutes.POST("/:id/goto", workshopHandlers.GoToStep) // Statistics & Summary workshopRoutes.GET("/:id/stats", workshopHandlers.GetSessionStats) workshopRoutes.GET("/:id/summary", workshopHandlers.GetSessionSummary) // Export workshopRoutes.GET("/:id/export", workshopHandlers.ExportSession) // Join by code (public endpoint for joining) workshopRoutes.POST("/join/:code", workshopHandlers.JoinSession) } // Portfolio routes - AI Use Case Portfolio Management portfolioRoutes := v1.Group("/portfolios") { // Portfolio CRUD portfolioRoutes.POST("", portfolioHandlers.CreatePortfolio) portfolioRoutes.GET("", portfolioHandlers.ListPortfolios) portfolioRoutes.GET("/:id", portfolioHandlers.GetPortfolio) portfolioRoutes.PUT("/:id", portfolioHandlers.UpdatePortfolio) portfolioRoutes.DELETE("/:id", portfolioHandlers.DeletePortfolio) // Portfolio items portfolioRoutes.POST("/:id/items", portfolioHandlers.AddItem) portfolioRoutes.GET("/:id/items", portfolioHandlers.ListItems) portfolioRoutes.POST("/:id/items/bulk", portfolioHandlers.BulkAddItems) portfolioRoutes.DELETE("/:id/items/:itemId", portfolioHandlers.RemoveItem) portfolioRoutes.PUT("/:id/items/order", portfolioHandlers.ReorderItems) // Statistics & Activity portfolioRoutes.GET("/:id/stats", portfolioHandlers.GetPortfolioStats) portfolioRoutes.GET("/:id/activity", portfolioHandlers.GetPortfolioActivity) portfolioRoutes.POST("/:id/recalculate", portfolioHandlers.RecalculateMetrics) // Approval workflow portfolioRoutes.POST("/:id/submit-review", portfolioHandlers.SubmitForReview) portfolioRoutes.POST("/:id/approve", portfolioHandlers.ApprovePortfolio) // Merge & Compare portfolioRoutes.POST("/merge", portfolioHandlers.MergePortfolios) portfolioRoutes.POST("/compare", portfolioHandlers.ComparePortfolios) } // Academy routes - E-Learning / Compliance Training academyRoutes := v1.Group("/academy") { // Courses academyRoutes.POST("/courses", academyHandlers.CreateCourse) academyRoutes.GET("/courses", academyHandlers.ListCourses) academyRoutes.GET("/courses/:id", academyHandlers.GetCourse) academyRoutes.PUT("/courses/:id", academyHandlers.UpdateCourse) academyRoutes.DELETE("/courses/:id", academyHandlers.DeleteCourse) // Enrollments academyRoutes.POST("/enrollments", academyHandlers.CreateEnrollment) academyRoutes.GET("/enrollments", academyHandlers.ListEnrollments) academyRoutes.PUT("/enrollments/:id/progress", academyHandlers.UpdateProgress) academyRoutes.POST("/enrollments/:id/complete", academyHandlers.CompleteEnrollment) // Certificates academyRoutes.GET("/certificates/:id", academyHandlers.GetCertificate) academyRoutes.POST("/enrollments/:id/certificate", academyHandlers.GenerateCertificate) // Quiz academyRoutes.POST("/courses/:id/quiz", academyHandlers.SubmitQuiz) // Lessons academyRoutes.PUT("/lessons/:id", academyHandlers.UpdateLesson) academyRoutes.POST("/lessons/:id/quiz-test", academyHandlers.TestQuiz) // Statistics academyRoutes.GET("/stats", academyHandlers.GetStatistics) // Course Generation from Training Modules academyRoutes.POST("/courses/generate", academyHandlers.GenerateCourseFromTraining) academyRoutes.POST("/courses/generate-all", academyHandlers.GenerateAllCourses) // Certificate PDF academyRoutes.GET("/certificates/:id/pdf", academyHandlers.DownloadCertificatePDF) } // Training Engine routes - Compliance Training Content Pipeline trainingRoutes := v1.Group("/training") { // Module CRUD trainingRoutes.GET("/modules", trainingHandlers.ListModules) trainingRoutes.GET("/modules/:id", trainingHandlers.GetModule) trainingRoutes.POST("/modules", trainingHandlers.CreateModule) trainingRoutes.PUT("/modules/:id", trainingHandlers.UpdateModule) trainingRoutes.DELETE("/modules/:id", trainingHandlers.DeleteModule) // Compliance Training Matrix (CTM) trainingRoutes.GET("/matrix", trainingHandlers.GetMatrix) trainingRoutes.GET("/matrix/:role", trainingHandlers.GetMatrixForRole) trainingRoutes.POST("/matrix", trainingHandlers.SetMatrixEntry) trainingRoutes.DELETE("/matrix/:role/:moduleId", trainingHandlers.DeleteMatrixEntry) // Assignments trainingRoutes.POST("/assignments/compute", trainingHandlers.ComputeAssignments) trainingRoutes.GET("/assignments", trainingHandlers.ListAssignments) trainingRoutes.GET("/assignments/:id", trainingHandlers.GetAssignment) trainingRoutes.POST("/assignments/:id/start", trainingHandlers.StartAssignment) trainingRoutes.POST("/assignments/:id/progress", trainingHandlers.UpdateAssignmentProgress) trainingRoutes.POST("/assignments/:id/complete", trainingHandlers.CompleteAssignment) trainingRoutes.PUT("/assignments/:id", trainingHandlers.UpdateAssignment) // Quiz trainingRoutes.GET("/quiz/:moduleId", trainingHandlers.GetQuiz) trainingRoutes.POST("/quiz/:moduleId/submit", trainingHandlers.SubmitQuiz) trainingRoutes.GET("/quiz/attempts/:assignmentId", trainingHandlers.GetQuizAttempts) // Content Generation (LLM) trainingRoutes.POST("/content/generate", trainingHandlers.GenerateContent) trainingRoutes.POST("/content/generate-quiz", trainingHandlers.GenerateQuiz) trainingRoutes.POST("/content/generate-all", trainingHandlers.GenerateAllContent) trainingRoutes.POST("/content/generate-all-quiz", trainingHandlers.GenerateAllQuizzes) trainingRoutes.GET("/content/:moduleId", trainingHandlers.GetContent) // PublishContent expects c.Param("id") but route uses :moduleId for Gin compatibility trainingRoutes.POST("/content/:moduleId/publish", func(c *gin.Context) { c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("moduleId")}) trainingHandlers.PublishContent(c) }) // Media (Audio/Video via TTS Service) trainingRoutes.POST("/content/:moduleId/generate-audio", trainingHandlers.GenerateAudio) trainingRoutes.POST("/content/:moduleId/generate-video", trainingHandlers.GenerateVideo) trainingRoutes.POST("/content/:moduleId/preview-script", trainingHandlers.PreviewVideoScript) trainingRoutes.GET("/media/module/:moduleId", trainingHandlers.GetModuleMedia) // Media detail routes use :mediaId consistently trainingRoutes.GET("/media/:mediaId/url", func(c *gin.Context) { c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("mediaId")}) trainingHandlers.GetMediaURL(c) }) trainingRoutes.POST("/media/:mediaId/publish", func(c *gin.Context) { c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("mediaId")}) trainingHandlers.PublishMedia(c) }) trainingRoutes.GET("/media/:mediaId/stream", func(c *gin.Context) { c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("mediaId")}) trainingHandlers.StreamMedia(c) }) // Deadlines & Escalation trainingRoutes.GET("/deadlines", trainingHandlers.GetDeadlines) trainingRoutes.GET("/deadlines/overdue", trainingHandlers.GetOverdueDeadlines) trainingRoutes.POST("/escalation/check", trainingHandlers.CheckEscalation) // Audit & Statistics trainingRoutes.GET("/audit-log", trainingHandlers.GetAuditLog) trainingRoutes.GET("/stats", trainingHandlers.GetStats) // Certificates trainingRoutes.POST("/certificates/generate/:assignmentId", trainingHandlers.GenerateCertificate) trainingRoutes.GET("/certificates", trainingHandlers.ListCertificates) trainingRoutes.GET("/certificates/:id/verify", trainingHandlers.VerifyCertificate) trainingRoutes.GET("/certificates/:id/pdf", trainingHandlers.DownloadCertificatePDF) // Training Blocks — Controls → Schulungsmodule Pipeline trainingRoutes.GET("/blocks", trainingHandlers.ListBlockConfigs) trainingRoutes.POST("/blocks", trainingHandlers.CreateBlockConfig) trainingRoutes.GET("/blocks/:id", trainingHandlers.GetBlockConfig) trainingRoutes.PUT("/blocks/:id", trainingHandlers.UpdateBlockConfig) trainingRoutes.DELETE("/blocks/:id", trainingHandlers.DeleteBlockConfig) trainingRoutes.POST("/blocks/:id/preview", trainingHandlers.PreviewBlock) trainingRoutes.POST("/blocks/:id/generate", trainingHandlers.GenerateBlock) trainingRoutes.GET("/blocks/:id/controls", trainingHandlers.GetBlockControls) // Canonical Controls Browsing trainingRoutes.GET("/canonical/controls", trainingHandlers.ListCanonicalControls) trainingRoutes.GET("/canonical/meta", trainingHandlers.GetCanonicalMeta) // Interactive Video (Narrator + Checkpoints) trainingRoutes.POST("/content/:moduleId/generate-interactive", trainingHandlers.GenerateInteractiveVideo) trainingRoutes.GET("/content/:moduleId/interactive-manifest", trainingHandlers.GetInteractiveManifest) trainingRoutes.POST("/checkpoints/:checkpointId/submit", trainingHandlers.SubmitCheckpointQuiz) trainingRoutes.GET("/checkpoints/progress/:assignmentId", trainingHandlers.GetCheckpointProgress) } // Whistleblower routes - Hinweisgebersystem (HinSchG) whistleblowerRoutes := v1.Group("/whistleblower") { // Public endpoints (anonymous reporting) whistleblowerRoutes.POST("/reports/submit", whistleblowerHandlers.SubmitReport) whistleblowerRoutes.GET("/reports/access/:accessKey", whistleblowerHandlers.GetReportByAccessKey) whistleblowerRoutes.POST("/reports/access/:accessKey/messages", whistleblowerHandlers.SendPublicMessage) // Admin endpoints whistleblowerRoutes.GET("/reports", whistleblowerHandlers.ListReports) whistleblowerRoutes.GET("/reports/:id", whistleblowerHandlers.GetReport) whistleblowerRoutes.PUT("/reports/:id", whistleblowerHandlers.UpdateReport) whistleblowerRoutes.DELETE("/reports/:id", whistleblowerHandlers.DeleteReport) whistleblowerRoutes.POST("/reports/:id/acknowledge", whistleblowerHandlers.AcknowledgeReport) whistleblowerRoutes.POST("/reports/:id/investigate", whistleblowerHandlers.StartInvestigation) whistleblowerRoutes.POST("/reports/:id/measures", whistleblowerHandlers.AddMeasure) whistleblowerRoutes.POST("/reports/:id/close", whistleblowerHandlers.CloseReport) whistleblowerRoutes.POST("/reports/:id/messages", whistleblowerHandlers.SendAdminMessage) whistleblowerRoutes.GET("/reports/:id/messages", whistleblowerHandlers.ListMessages) // Statistics whistleblowerRoutes.GET("/stats", whistleblowerHandlers.GetStatistics) } // IACE routes - Industrial AI Compliance Engine (CE-Risikobeurteilung SW/FW/KI) iaceRoutes := v1.Group("/iace") { // Hazard Library (project-independent) iaceRoutes.GET("/hazard-library", iaceHandler.ListHazardLibrary) // Controls Library (project-independent) iaceRoutes.GET("/controls-library", iaceHandler.ListControlsLibrary) // ISO 12100 reference data (project-independent) iaceRoutes.GET("/lifecycle-phases", iaceHandler.ListLifecyclePhases) iaceRoutes.GET("/roles", iaceHandler.ListRoles) iaceRoutes.GET("/evidence-types", iaceHandler.ListEvidenceTypes) iaceRoutes.GET("/protective-measures-library", iaceHandler.ListProtectiveMeasures) // Component Library & Energy Sources (Hazard Matching Engine) iaceRoutes.GET("/component-library", iaceHandler.ListComponentLibrary) iaceRoutes.GET("/energy-sources", iaceHandler.ListEnergySources) // Tag Taxonomy iaceRoutes.GET("/tags", iaceHandler.ListTags) // Hazard Patterns iaceRoutes.GET("/hazard-patterns", iaceHandler.ListHazardPatterns) // Project Management iaceRoutes.POST("/projects", iaceHandler.CreateProject) iaceRoutes.GET("/projects", iaceHandler.ListProjects) iaceRoutes.GET("/projects/:id", iaceHandler.GetProject) iaceRoutes.PUT("/projects/:id", iaceHandler.UpdateProject) iaceRoutes.DELETE("/projects/:id", iaceHandler.ArchiveProject) // Onboarding iaceRoutes.POST("/projects/:id/init-from-profile", iaceHandler.InitFromProfile) iaceRoutes.POST("/projects/:id/completeness-check", iaceHandler.CheckCompleteness) // Components iaceRoutes.POST("/projects/:id/components", iaceHandler.CreateComponent) iaceRoutes.GET("/projects/:id/components", iaceHandler.ListComponents) iaceRoutes.PUT("/projects/:id/components/:cid", iaceHandler.UpdateComponent) iaceRoutes.DELETE("/projects/:id/components/:cid", iaceHandler.DeleteComponent) // Regulatory Classification iaceRoutes.POST("/projects/:id/classify", iaceHandler.Classify) iaceRoutes.GET("/projects/:id/classifications", iaceHandler.GetClassifications) iaceRoutes.POST("/projects/:id/classify/:regulation", iaceHandler.ClassifySingle) // Hazards iaceRoutes.POST("/projects/:id/hazards", iaceHandler.CreateHazard) iaceRoutes.GET("/projects/:id/hazards", iaceHandler.ListHazards) iaceRoutes.PUT("/projects/:id/hazards/:hid", iaceHandler.UpdateHazard) iaceRoutes.POST("/projects/:id/hazards/suggest", iaceHandler.SuggestHazards) // Pattern Matching Engine iaceRoutes.POST("/projects/:id/match-patterns", iaceHandler.MatchPatterns) iaceRoutes.POST("/projects/:id/apply-patterns", iaceHandler.ApplyPatternResults) iaceRoutes.POST("/projects/:id/hazards/:hid/suggest-measures", iaceHandler.SuggestMeasuresForHazard) iaceRoutes.POST("/projects/:id/mitigations/:mid/suggest-evidence", iaceHandler.SuggestEvidenceForMitigation) // Risk Assessment iaceRoutes.POST("/projects/:id/hazards/:hid/assess", iaceHandler.AssessRisk) iaceRoutes.GET("/projects/:id/risk-summary", iaceHandler.GetRiskSummary) iaceRoutes.POST("/projects/:id/hazards/:hid/reassess", iaceHandler.ReassessRisk) // Mitigations iaceRoutes.POST("/projects/:id/hazards/:hid/mitigations", iaceHandler.CreateMitigation) iaceRoutes.PUT("/mitigations/:mid", iaceHandler.UpdateMitigation) iaceRoutes.POST("/mitigations/:mid/verify", iaceHandler.VerifyMitigation) iaceRoutes.POST("/projects/:id/validate-mitigation-hierarchy", iaceHandler.ValidateMitigationHierarchy) // Evidence iaceRoutes.POST("/projects/:id/evidence", iaceHandler.UploadEvidence) iaceRoutes.GET("/projects/:id/evidence", iaceHandler.ListEvidence) // Verification Plans iaceRoutes.POST("/projects/:id/verification-plan", iaceHandler.CreateVerificationPlan) iaceRoutes.PUT("/verification-plan/:vid", iaceHandler.UpdateVerificationPlan) iaceRoutes.POST("/verification-plan/:vid/complete", iaceHandler.CompleteVerification) // CE Technical File iaceRoutes.POST("/projects/:id/tech-file/generate", iaceHandler.GenerateTechFile) iaceRoutes.GET("/projects/:id/tech-file", iaceHandler.ListTechFileSections) iaceRoutes.PUT("/projects/:id/tech-file/:section", iaceHandler.UpdateTechFileSection) iaceRoutes.POST("/projects/:id/tech-file/:section/approve", iaceHandler.ApproveTechFileSection) iaceRoutes.POST("/projects/:id/tech-file/:section/generate", iaceHandler.GenerateSingleSection) iaceRoutes.GET("/projects/:id/tech-file/export", iaceHandler.ExportTechFile) // Monitoring iaceRoutes.POST("/projects/:id/monitoring", iaceHandler.CreateMonitoringEvent) iaceRoutes.GET("/projects/:id/monitoring", iaceHandler.ListMonitoringEvents) iaceRoutes.PUT("/projects/:id/monitoring/:eid", iaceHandler.UpdateMonitoringEvent) // Audit Trail iaceRoutes.GET("/projects/:id/audit-trail", iaceHandler.GetAuditTrail) // RAG Library Search (Phase 6) iaceRoutes.POST("/library-search", iaceHandler.SearchLibrary) iaceRoutes.POST("/projects/:id/tech-file/:section/enrich", iaceHandler.EnrichTechFileSection) } } // Create HTTP server srv := &http.Server{ Addr: ":" + cfg.Port, Handler: router, ReadTimeout: 30 * time.Second, WriteTimeout: 5 * time.Minute, // LLM requests can take longer IdleTimeout: 60 * time.Second, } // Start server in goroutine 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) } }() // Graceful shutdown 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") }