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:
160
admin-compliance/ai-compliance-sdk/cmd/server/main.go
Normal file
160
admin-compliance/ai-compliance-sdk/cmd/server/main.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/breakpilot/ai-compliance-sdk/internal/api"
|
||||
"github.com/breakpilot/ai-compliance-sdk/internal/db"
|
||||
"github.com/breakpilot/ai-compliance-sdk/internal/llm"
|
||||
"github.com/breakpilot/ai-compliance-sdk/internal/rag"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Load environment variables
|
||||
if err := godotenv.Load(); err != nil {
|
||||
log.Println("No .env file found, using environment variables")
|
||||
}
|
||||
|
||||
// Get configuration from environment
|
||||
port := getEnv("PORT", "8085")
|
||||
dbURL := getEnv("DATABASE_URL", "postgres://localhost:5432/sdk_states?sslmode=disable")
|
||||
qdrantURL := getEnv("QDRANT_URL", "http://localhost:6333")
|
||||
anthropicKey := getEnv("ANTHROPIC_API_KEY", "")
|
||||
|
||||
// Initialize database connection
|
||||
dbPool, err := db.NewPostgresPool(dbURL)
|
||||
if err != nil {
|
||||
log.Printf("Warning: Database connection failed: %v", err)
|
||||
// Continue without database - use in-memory fallback
|
||||
}
|
||||
|
||||
// Initialize RAG service
|
||||
ragService, err := rag.NewService(qdrantURL)
|
||||
if err != nil {
|
||||
log.Printf("Warning: RAG service initialization failed: %v", err)
|
||||
// Continue without RAG - will return empty results
|
||||
}
|
||||
|
||||
// Initialize LLM service
|
||||
llmService := llm.NewService(anthropicKey)
|
||||
|
||||
// Create Gin router
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
if os.Getenv("GIN_MODE") == "debug" {
|
||||
gin.SetMode(gin.DebugMode)
|
||||
}
|
||||
|
||||
router := gin.Default()
|
||||
|
||||
// CORS middleware
|
||||
router.Use(corsMiddleware())
|
||||
|
||||
// Health check
|
||||
router.GET("/health", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": "healthy",
|
||||
"timestamp": time.Now().UTC().Format(time.RFC3339),
|
||||
"services": gin.H{
|
||||
"database": dbPool != nil,
|
||||
"rag": ragService != nil,
|
||||
"llm": anthropicKey != "",
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
// API routes
|
||||
v1 := router.Group("/sdk/v1")
|
||||
{
|
||||
// State Management
|
||||
stateHandler := api.NewStateHandler(dbPool)
|
||||
v1.GET("/state/:tenantId", stateHandler.GetState)
|
||||
v1.POST("/state", stateHandler.SaveState)
|
||||
v1.DELETE("/state/:tenantId", stateHandler.DeleteState)
|
||||
|
||||
// RAG Search
|
||||
ragHandler := api.NewRAGHandler(ragService)
|
||||
v1.GET("/rag/search", ragHandler.Search)
|
||||
v1.GET("/rag/status", ragHandler.GetCorpusStatus)
|
||||
v1.POST("/rag/index", ragHandler.IndexDocument)
|
||||
|
||||
// Document Generation
|
||||
generateHandler := api.NewGenerateHandler(llmService, ragService)
|
||||
v1.POST("/generate/dsfa", generateHandler.GenerateDSFA)
|
||||
v1.POST("/generate/tom", generateHandler.GenerateTOM)
|
||||
v1.POST("/generate/vvt", generateHandler.GenerateVVT)
|
||||
v1.POST("/generate/gutachten", generateHandler.GenerateGutachten)
|
||||
|
||||
// Checkpoint Validation
|
||||
checkpointHandler := api.NewCheckpointHandler()
|
||||
v1.GET("/checkpoints", checkpointHandler.GetAll)
|
||||
v1.POST("/checkpoints/validate", checkpointHandler.Validate)
|
||||
}
|
||||
|
||||
// Create server
|
||||
srv := &http.Server{
|
||||
Addr: ":" + port,
|
||||
Handler: router,
|
||||
}
|
||||
|
||||
// Graceful shutdown
|
||||
go func() {
|
||||
log.Printf("SDK Backend starting on port %s", port)
|
||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("Failed to start server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for interrupt signal
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
log.Println("Shutting down server...")
|
||||
|
||||
// Give outstanding requests 5 seconds to complete
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
log.Fatal("Server forced to shutdown:", err)
|
||||
}
|
||||
|
||||
// Close database connection
|
||||
if dbPool != nil {
|
||||
dbPool.Close()
|
||||
}
|
||||
|
||||
log.Println("Server exited")
|
||||
}
|
||||
|
||||
func getEnv(key, defaultValue string) string {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func corsMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, If-Match, If-None-Match")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
|
||||
c.Writer.Header().Set("Access-Control-Expose-Headers", "ETag, Last-Modified")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(204)
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user