Initial commit: breakpilot-compliance - Compliance SDK Platform
Services: Admin-Compliance, Backend-Compliance, AI-Compliance-SDK, Consent-SDK, Developer-Portal, PCA-Platform, DSMS Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
475
ai-compliance-sdk/cmd/server/main.go
Normal file
475
ai-compliance-sdk/cmd/server/main.go
Normal file
@@ -0,0 +1,475 @@
|
||||
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/roadmap"
|
||||
"github.com/breakpilot/ai-compliance-sdk/internal/ucca"
|
||||
"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)
|
||||
|
||||
// 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)
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
Reference in New Issue
Block a user