All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 36s
CI / test-python-backend-compliance (push) Successful in 31s
CI / test-python-document-crawler (push) Successful in 23s
CI / test-python-dsms-gateway (push) Successful in 21s
Phase A: 8 new IT-Security training modules (SEC-PWD, SEC-DESK, SEC-KIAI, SEC-BYOD, SEC-VIDEO, SEC-USB, SEC-INC, SEC-HOME) with CTM entries. Bulk content and quiz generation endpoints for all 28 modules. Phase B: Piper TTS service (Python/FastAPI) for local German speech synthesis. training_media table, TTSClient in Go backend, audio generation endpoints, AudioPlayer component in frontend. MinIO storage integration. Phase C: FFmpeg presentation video pipeline — LLM generates slide scripts, ImageMagick renders 1920x1080 slides, FFmpeg combines with audio to MP4. VideoPlayer and ScriptPreview components in frontend. New files: 15 created, 9 modified - compliance-tts-service/ (Dockerfile, main.py, tts_engine.py, storage.py, slide_renderer.py, video_generator.py) - migrations 014-016 (training engine, IT-security modules, media table) - training package (models, store, content_generator, media, handlers) - frontend (AudioPlayer, VideoPlayer, ScriptPreview, api, types, page) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
784 lines
31 KiB
Go
784 lines
31 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/ucca"
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/whistleblower"
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/dsb"
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/multitenant"
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/reporting"
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/sso"
|
|
"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/breakpilot/ai-compliance-sdk/internal/gci"
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/training"
|
|
"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)
|
|
reportingStore := reporting.NewStore(pool, dsgvoStore, vendorStore, incidentStore, whistleblowerStore, academyStore)
|
|
ssoStore := sso.NewStore(pool)
|
|
multitenantStore := multitenant.NewStore(pool, rbacStore, reportingStore)
|
|
dsbStore := dsb.NewStore(pool, reportingStore)
|
|
|
|
// 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 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)
|
|
reportingHandlers := handlers.NewReportingHandlers(reportingStore)
|
|
ssoHandlers := handlers.NewSSOHandlers(ssoStore, cfg.JWTSecret)
|
|
multitenantHandlers := handlers.NewMultiTenantHandlers(multitenantStore, rbacStore)
|
|
industryHandlers := handlers.NewIndustryHandlers()
|
|
dsbHandlers := handlers.NewDSBHandlers(dsbStore)
|
|
|
|
// Initialize GCI engine and handlers
|
|
gciEngine := gci.NewEngine()
|
|
gciHandlers := handlers.NewGCIHandlers(gciEngine)
|
|
|
|
// Initialize Training Engine
|
|
trainingStore := training.NewStore(pool)
|
|
ttsClient := training.NewTTSClient(cfg.TTSServiceURL)
|
|
contentGenerator := training.NewContentGenerator(providerRegistry, piiDetector, trainingStore, ttsClient)
|
|
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.GET("/certificates/:id/pdf", academyHandlers.DownloadCertificatePDF)
|
|
academyRoutes.POST("/enrollments/:id/certificate", academyHandlers.GenerateCertificate)
|
|
|
|
// Quiz
|
|
academyRoutes.POST("/courses/:id/quiz", academyHandlers.SubmitQuiz)
|
|
|
|
// Statistics
|
|
academyRoutes.GET("/stats", academyHandlers.GetStatistics)
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
// Reporting routes - Executive Compliance Reporting Dashboard
|
|
reportingRoutes := v1.Group("/reporting")
|
|
{
|
|
reportingRoutes.GET("/executive", reportingHandlers.GetExecutiveReport)
|
|
reportingRoutes.GET("/score", reportingHandlers.GetComplianceScore)
|
|
reportingRoutes.GET("/deadlines", reportingHandlers.GetUpcomingDeadlines)
|
|
reportingRoutes.GET("/risks", reportingHandlers.GetRiskOverview)
|
|
}
|
|
|
|
// SSO routes - Single Sign-On (SAML/OIDC)
|
|
ssoRoutes := v1.Group("/sso")
|
|
{
|
|
// Config CRUD
|
|
ssoRoutes.POST("/configs", ssoHandlers.CreateConfig)
|
|
ssoRoutes.GET("/configs", ssoHandlers.ListConfigs)
|
|
ssoRoutes.GET("/configs/:id", ssoHandlers.GetConfig)
|
|
ssoRoutes.PUT("/configs/:id", ssoHandlers.UpdateConfig)
|
|
ssoRoutes.DELETE("/configs/:id", ssoHandlers.DeleteConfig)
|
|
|
|
// SSO Users
|
|
ssoRoutes.GET("/users", ssoHandlers.ListUsers)
|
|
|
|
// OIDC Flow
|
|
ssoRoutes.GET("/oidc/login", ssoHandlers.InitiateOIDCLogin)
|
|
ssoRoutes.GET("/oidc/callback", ssoHandlers.HandleOIDCCallback)
|
|
}
|
|
|
|
// Multi-Tenant Administration routes
|
|
mtRoutes := v1.Group("/multi-tenant")
|
|
{
|
|
mtRoutes.GET("/overview", multitenantHandlers.GetOverview)
|
|
mtRoutes.POST("/tenants", multitenantHandlers.CreateTenant)
|
|
mtRoutes.GET("/tenants/:id", multitenantHandlers.GetTenantDetail)
|
|
mtRoutes.PUT("/tenants/:id", multitenantHandlers.UpdateTenant)
|
|
mtRoutes.GET("/tenants/:id/namespaces", multitenantHandlers.ListNamespaces)
|
|
mtRoutes.POST("/tenants/:id/namespaces", multitenantHandlers.CreateNamespace)
|
|
mtRoutes.POST("/switch", multitenantHandlers.SwitchTenant)
|
|
}
|
|
|
|
// Industry-Specific Templates routes (Phase 3.3)
|
|
industryRoutes := v1.Group("/industry/templates")
|
|
{
|
|
industryRoutes.GET("", industryHandlers.ListIndustries)
|
|
industryRoutes.GET("/:slug", industryHandlers.GetIndustry)
|
|
industryRoutes.GET("/:slug/vvt", industryHandlers.GetVVTTemplates)
|
|
industryRoutes.GET("/:slug/tom", industryHandlers.GetTOMRecommendations)
|
|
industryRoutes.GET("/:slug/risks", industryHandlers.GetRiskScenarios)
|
|
}
|
|
|
|
// DSB-as-a-Service Portal routes (Phase 3.4)
|
|
dsbRoutes := v1.Group("/dsb")
|
|
{
|
|
dsbRoutes.GET("/dashboard", dsbHandlers.GetDashboard)
|
|
dsbRoutes.POST("/assignments", dsbHandlers.CreateAssignment)
|
|
dsbRoutes.GET("/assignments", dsbHandlers.ListAssignments)
|
|
dsbRoutes.GET("/assignments/:id", dsbHandlers.GetAssignment)
|
|
dsbRoutes.PUT("/assignments/:id", dsbHandlers.UpdateAssignment)
|
|
dsbRoutes.POST("/assignments/:id/hours", dsbHandlers.CreateHourEntry)
|
|
dsbRoutes.GET("/assignments/:id/hours", dsbHandlers.ListHours)
|
|
dsbRoutes.GET("/assignments/:id/hours/summary", dsbHandlers.GetHoursSummary)
|
|
dsbRoutes.POST("/assignments/:id/tasks", dsbHandlers.CreateTask)
|
|
dsbRoutes.GET("/assignments/:id/tasks", dsbHandlers.ListTasks)
|
|
dsbRoutes.PUT("/tasks/:taskId", dsbHandlers.UpdateTask)
|
|
dsbRoutes.POST("/tasks/:taskId/complete", dsbHandlers.CompleteTask)
|
|
dsbRoutes.POST("/assignments/:id/communications", dsbHandlers.CreateCommunication)
|
|
dsbRoutes.GET("/assignments/:id/communications", dsbHandlers.ListCommunications)
|
|
}
|
|
|
|
// GCI routes - Gesamt-Compliance-Index
|
|
gciRoutes := v1.Group("/gci")
|
|
{
|
|
// Core GCI endpoints
|
|
gciRoutes.GET("/score", gciHandlers.GetScore)
|
|
gciRoutes.GET("/score/breakdown", gciHandlers.GetScoreBreakdown)
|
|
gciRoutes.GET("/score/history", gciHandlers.GetHistory)
|
|
gciRoutes.GET("/matrix", gciHandlers.GetMatrix)
|
|
gciRoutes.GET("/audit-trail", gciHandlers.GetAuditTrail)
|
|
gciRoutes.GET("/profiles", gciHandlers.GetWeightProfiles)
|
|
|
|
// NIS2 sub-routes
|
|
gciRoutes.GET("/nis2/score", gciHandlers.GetNIS2Score)
|
|
gciRoutes.GET("/nis2/roles", gciHandlers.ListNIS2Roles)
|
|
gciRoutes.POST("/nis2/roles/assign", gciHandlers.AssignNIS2Role)
|
|
|
|
// ISO 27001 sub-routes
|
|
gciRoutes.GET("/iso/gap-analysis", gciHandlers.GetISOGapAnalysis)
|
|
gciRoutes.GET("/iso/mappings", gciHandlers.ListISOMappings)
|
|
gciRoutes.GET("/iso/mappings/:controlId", gciHandlers.GetISOMapping)
|
|
}
|
|
|
|
|
|
// Training Engine routes - Compliance Training Management
|
|
trainingRoutes := v1.Group("/training")
|
|
{
|
|
// Modules
|
|
trainingRoutes.GET("/modules", trainingHandlers.ListModules)
|
|
trainingRoutes.GET("/modules/:id", trainingHandlers.GetModule)
|
|
trainingRoutes.POST("/modules", trainingHandlers.CreateModule)
|
|
trainingRoutes.PUT("/modules/:id", trainingHandlers.UpdateModule)
|
|
|
|
// 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
|
|
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)
|
|
|
|
// Audio/Media
|
|
trainingRoutes.POST("/content/:moduleId/generate-audio", trainingHandlers.GenerateAudio)
|
|
trainingRoutes.GET("/media/:moduleId", trainingHandlers.GetModuleMedia)
|
|
trainingRoutes.GET("/media/:id/url", trainingHandlers.GetMediaURL)
|
|
trainingRoutes.POST("/media/:id/publish", trainingHandlers.PublishMedia)
|
|
|
|
// Video
|
|
trainingRoutes.POST("/content/:moduleId/generate-video", trainingHandlers.GenerateVideo)
|
|
trainingRoutes.POST("/content/:moduleId/preview-script", trainingHandlers.PreviewVideoScript)
|
|
|
|
// Deadlines and Escalation
|
|
trainingRoutes.GET("/deadlines", trainingHandlers.GetDeadlines)
|
|
trainingRoutes.GET("/deadlines/overdue", trainingHandlers.GetOverdueDeadlines)
|
|
trainingRoutes.POST("/escalation/check", trainingHandlers.CheckEscalation)
|
|
|
|
// Audit and Stats
|
|
trainingRoutes.GET("/audit-log", trainingHandlers.GetAuditLog)
|
|
trainingRoutes.GET("/stats", trainingHandlers.GetStats)
|
|
trainingRoutes.GET("/certificates/:id/verify", trainingHandlers.VerifyCertificate)
|
|
}
|
|
}
|
|
|
|
// 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")
|
|
}
|