Files
breakpilot-compliance/ai-compliance-sdk/cmd/server/main.go
Benjamin Admin e5cb5e37ad feat(training): register training routes and add missing academy API functions
Connect the existing training engine handlers (40+ endpoints) to the router
in main.go. This was the critical blocker preventing the training content
pipeline from being accessible. Also adds generateCourse, generateVideos,
and getVideoStatus functions to the academy API client, plus the
GenerateCourseRequest type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 09:46:16 +01:00

747 lines
30 KiB
Go

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/dsgvo"
"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/incidents"
"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/vendor"
"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)
dsgvoStore := dsgvo.NewStore(pool)
uccaStore := ucca.NewStore(pool)
escalationStore := ucca.NewEscalationStore(pool)
roadmapStore := roadmap.NewStore(pool)
workshopStore := workshop.NewStore(pool)
portfolioStore := portfolio.NewStore(pool)
academyStore := academy.NewStore(pool)
whistleblowerStore := whistleblower.NewStore(pool)
incidentStore := incidents.NewStore(pool)
vendorStore := vendor.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)
dsgvoHandlers := handlers.NewDSGVOHandlers(dsgvoStore)
uccaHandlers := handlers.NewUCCAHandlers(uccaStore, escalationStore, providerRegistry)
escalationHandlers := handlers.NewEscalationHandlers(escalationStore, uccaStore)
roadmapHandlers := handlers.NewRoadmapHandlers(roadmapStore)
workshopHandlers := handlers.NewWorkshopHandlers(workshopStore)
portfolioHandlers := handlers.NewPortfolioHandlers(portfolioStore)
draftingHandlers := handlers.NewDraftingHandlers(accessGate, providerRegistry, piiDetector, auditStore, trailBuilder)
academyHandlers := handlers.NewAcademyHandlers(academyStore)
whistleblowerHandlers := handlers.NewWhistleblowerHandlers(whistleblowerStore)
incidentHandlers := handlers.NewIncidentHandlers(incidentStore)
vendorHandlers := handlers.NewVendorHandlers(vendorStore)
iaceHandler := handlers.NewIACEHandler(iaceStore)
trainingHandlers := handlers.NewTrainingHandlers(trainingStore, contentGenerator)
// 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)
}
// DSGVO routes (Art. 30, 32, 35, 15-22 DSGVO)
dsgvoRoutes := v1.Group("/dsgvo")
{
// Statistics
dsgvoRoutes.GET("/stats", dsgvoHandlers.GetStats)
// VVT - Verarbeitungsverzeichnis (Art. 30)
vvt := dsgvoRoutes.Group("/processing-activities")
{
vvt.GET("", dsgvoHandlers.ListProcessingActivities)
vvt.GET("/:id", dsgvoHandlers.GetProcessingActivity)
vvt.POST("", dsgvoHandlers.CreateProcessingActivity)
vvt.PUT("/:id", dsgvoHandlers.UpdateProcessingActivity)
vvt.DELETE("/:id", dsgvoHandlers.DeleteProcessingActivity)
}
// TOM - Technische und Organisatorische Maßnahmen (Art. 32)
tom := dsgvoRoutes.Group("/tom")
{
tom.GET("", dsgvoHandlers.ListTOMs)
tom.GET("/:id", dsgvoHandlers.GetTOM)
tom.POST("", dsgvoHandlers.CreateTOM)
}
// DSR - Data Subject Requests / Betroffenenrechte (Art. 15-22)
dsr := dsgvoRoutes.Group("/dsr")
{
dsr.GET("", dsgvoHandlers.ListDSRs)
dsr.GET("/:id", dsgvoHandlers.GetDSR)
dsr.POST("", dsgvoHandlers.CreateDSR)
dsr.PUT("/:id", dsgvoHandlers.UpdateDSR)
}
// Retention Policies - Löschfristen (Art. 17)
retention := dsgvoRoutes.Group("/retention-policies")
{
retention.GET("", dsgvoHandlers.ListRetentionPolicies)
retention.POST("", dsgvoHandlers.CreateRetentionPolicy)
}
// DSFA - Datenschutz-Folgenabschätzung (Art. 35)
dsfa := dsgvoRoutes.Group("/dsfa")
{
dsfa.GET("", dsgvoHandlers.ListDSFAs)
dsfa.GET("/:id", dsgvoHandlers.GetDSFA)
dsfa.POST("", dsgvoHandlers.CreateDSFA)
dsfa.PUT("/:id", dsgvoHandlers.UpdateDSFA)
dsfa.DELETE("/:id", dsgvoHandlers.DeleteDSFA)
dsfa.GET("/:id/export", dsgvoHandlers.ExportDSFA)
}
// Export routes
exports := dsgvoRoutes.Group("/export")
{
exports.GET("/vvt", dsgvoHandlers.ExportVVT)
exports.GET("/tom", dsgvoHandlers.ExportTOM)
exports.GET("/dsr", dsgvoHandlers.ExportDSR)
exports.GET("/retention", dsgvoHandlers.ExportRetentionPolicies)
}
}
// 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.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)
// Statistics
uccaRoutes.GET("/stats", uccaHandlers.GetStats)
// Wizard routes - Legal Assistant integrated
uccaRoutes.GET("/wizard/schema", uccaHandlers.GetWizardSchema)
uccaRoutes.POST("/wizard/ask", uccaHandlers.AskWizardQuestion)
// Escalation management (E0-E3 workflow)
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)
// DSB Pool management
uccaRoutes.GET("/dsb-pool", escalationHandlers.ListDSBPool)
uccaRoutes.POST("/dsb-pool", escalationHandlers.AddDSBPoolMember)
}
// 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)
}
// Drafting Engine routes - Compliance Document Drafting & Validation
draftingRoutes := v1.Group("/drafting")
draftingRoutes.Use(rbacMiddleware.RequireLLMAccess())
{
draftingRoutes.POST("/draft", draftingHandlers.DraftDocument)
draftingRoutes.POST("/validate", draftingHandlers.ValidateDocument)
draftingRoutes.GET("/history", draftingHandlers.GetDraftHistory)
}
// 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)
// Statistics
academyRoutes.GET("/stats", academyHandlers.GetStatistics)
}
// 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)
// 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)
// 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)
trainingRoutes.POST("/content/:id/publish", trainingHandlers.PublishContent)
// 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)
trainingRoutes.GET("/media/:id/url", trainingHandlers.GetMediaURL)
trainingRoutes.POST("/media/:id/publish", trainingHandlers.PublishMedia)
// 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.GET("/certificates/:id/verify", trainingHandlers.VerifyCertificate)
}
// 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)
}
// Incidents routes - Datenpannen-Management (DSGVO Art. 33/34)
incidentRoutes := v1.Group("/incidents")
{
// Incident CRUD
incidentRoutes.POST("", incidentHandlers.CreateIncident)
incidentRoutes.GET("", incidentHandlers.ListIncidents)
incidentRoutes.GET("/:id", incidentHandlers.GetIncident)
incidentRoutes.PUT("/:id", incidentHandlers.UpdateIncident)
incidentRoutes.DELETE("/:id", incidentHandlers.DeleteIncident)
// Risk Assessment
incidentRoutes.POST("/:id/assess-risk", incidentHandlers.AssessRisk)
// Authority Notification (Art. 33)
incidentRoutes.POST("/:id/notify-authority", incidentHandlers.SubmitAuthorityNotification)
// Data Subject Notification (Art. 34)
incidentRoutes.POST("/:id/notify-subjects", incidentHandlers.NotifyDataSubjects)
// Measures
incidentRoutes.POST("/:id/measures", incidentHandlers.AddMeasure)
incidentRoutes.PUT("/:id/measures/:measureId", incidentHandlers.UpdateMeasure)
incidentRoutes.POST("/:id/measures/:measureId/complete", incidentHandlers.CompleteMeasure)
// Timeline
incidentRoutes.POST("/:id/timeline", incidentHandlers.AddTimelineEntry)
// Lifecycle
incidentRoutes.POST("/:id/close", incidentHandlers.CloseIncident)
// Statistics
incidentRoutes.GET("/stats", incidentHandlers.GetStatistics)
}
// Vendor Compliance routes - Vendor Management & AVV/DPA (DSGVO Art. 28)
vendorRoutes := v1.Group("/vendors")
{
// Vendor CRUD
vendorRoutes.POST("", vendorHandlers.CreateVendor)
vendorRoutes.GET("", vendorHandlers.ListVendors)
vendorRoutes.GET("/:id", vendorHandlers.GetVendor)
vendorRoutes.PUT("/:id", vendorHandlers.UpdateVendor)
vendorRoutes.DELETE("/:id", vendorHandlers.DeleteVendor)
// Contracts (AVV/DPA)
vendorRoutes.POST("/contracts", vendorHandlers.CreateContract)
vendorRoutes.GET("/contracts", vendorHandlers.ListContracts)
vendorRoutes.GET("/contracts/:id", vendorHandlers.GetContract)
vendorRoutes.PUT("/contracts/:id", vendorHandlers.UpdateContract)
vendorRoutes.DELETE("/contracts/:id", vendorHandlers.DeleteContract)
// Findings
vendorRoutes.POST("/findings", vendorHandlers.CreateFinding)
vendorRoutes.GET("/findings", vendorHandlers.ListFindings)
vendorRoutes.GET("/findings/:id", vendorHandlers.GetFinding)
vendorRoutes.PUT("/findings/:id", vendorHandlers.UpdateFinding)
vendorRoutes.POST("/findings/:id/resolve", vendorHandlers.ResolveFinding)
// Control Instances
vendorRoutes.POST("/controls", vendorHandlers.UpsertControlInstance)
vendorRoutes.GET("/controls", vendorHandlers.ListControlInstances)
// Templates
vendorRoutes.GET("/templates", vendorHandlers.ListTemplates)
vendorRoutes.GET("/templates/:templateId", vendorHandlers.GetTemplate)
vendorRoutes.POST("/templates", vendorHandlers.CreateTemplate)
vendorRoutes.POST("/templates/:templateId/apply", vendorHandlers.ApplyTemplate)
// Statistics
vendorRoutes.GET("/stats", vendorHandlers.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)
// 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)
// 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)
// 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.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)
}
}
// 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")
}