Files
breakpilot-compliance/ai-compliance-sdk/internal/api/handlers/registration_handlers.go
Benjamin Admin 532febe35c fix: Build-Fehler — LegalContext Namenskollision + Registration Handler
- LegalContext → LegalDomainContext (Kollision mit legal_rag.go LegalContext)
- ExplainResponse.LegalContext bleibt unveraendert (RAG-Typ)
- Registration Handler: Intake ist struct, kein []byte
- Unbenutzten json Import entfernt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 23:57:00 +02:00

221 lines
6.2 KiB
Go

package handlers
import (
"net/http"
"github.com/breakpilot/ai-compliance-sdk/internal/ucca"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// RegistrationHandlers handles EU AI Database registration endpoints
type RegistrationHandlers struct {
store *ucca.RegistrationStore
uccaStore *ucca.Store
}
// NewRegistrationHandlers creates new registration handlers
func NewRegistrationHandlers(store *ucca.RegistrationStore, uccaStore *ucca.Store) *RegistrationHandlers {
return &RegistrationHandlers{store: store, uccaStore: uccaStore}
}
// Create creates a new registration
func (h *RegistrationHandlers) Create(c *gin.Context) {
var reg ucca.AIRegistration
if err := c.ShouldBindJSON(&reg); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()})
return
}
tenantID, _ := uuid.Parse(c.GetHeader("X-Tenant-ID"))
if tenantID == uuid.Nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
return
}
reg.TenantID = tenantID
if reg.SystemName == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "system_name required"})
return
}
if err := h.store.Create(c.Request.Context(), &reg); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create registration: " + err.Error()})
return
}
c.JSON(http.StatusCreated, reg)
}
// List lists all registrations for the tenant
func (h *RegistrationHandlers) List(c *gin.Context) {
tenantID, _ := uuid.Parse(c.GetHeader("X-Tenant-ID"))
if tenantID == uuid.Nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
return
}
registrations, err := h.store.List(c.Request.Context(), tenantID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list registrations: " + err.Error()})
return
}
if registrations == nil {
registrations = []ucca.AIRegistration{}
}
c.JSON(http.StatusOK, gin.H{"registrations": registrations, "total": len(registrations)})
}
// Get returns a single registration
func (h *RegistrationHandlers) Get(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
return
}
reg, err := h.store.GetByID(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Registration not found"})
return
}
c.JSON(http.StatusOK, reg)
}
// Update updates a registration
func (h *RegistrationHandlers) Update(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
return
}
existing, err := h.store.GetByID(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Registration not found"})
return
}
var updates ucca.AIRegistration
if err := c.ShouldBindJSON(&updates); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request: " + err.Error()})
return
}
// Merge updates into existing
updates.ID = existing.ID
updates.TenantID = existing.TenantID
updates.CreatedAt = existing.CreatedAt
if err := h.store.Update(c.Request.Context(), &updates); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update: " + err.Error()})
return
}
c.JSON(http.StatusOK, updates)
}
// UpdateStatus changes the registration status
func (h *RegistrationHandlers) UpdateStatus(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
return
}
var body struct {
Status string `json:"status"`
SubmittedBy string `json:"submitted_by"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
return
}
validStatuses := map[string]bool{
"draft": true, "ready": true, "submitted": true,
"registered": true, "update_required": true, "withdrawn": true,
}
if !validStatuses[body.Status] {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid status. Valid: draft, ready, submitted, registered, update_required, withdrawn"})
return
}
if err := h.store.UpdateStatus(c.Request.Context(), id, body.Status, body.SubmittedBy); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update status: " + err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"id": id, "status": body.Status})
}
// Prefill creates a registration pre-filled from a UCCA assessment
func (h *RegistrationHandlers) Prefill(c *gin.Context) {
assessmentID, err := uuid.Parse(c.Param("assessment_id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid assessment ID"})
return
}
tenantID, _ := uuid.Parse(c.GetHeader("X-Tenant-ID"))
if tenantID == uuid.Nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "tenant ID required"})
return
}
// Load UCCA assessment
assessment, err := h.uccaStore.GetAssessment(c.Request.Context(), assessmentID)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Assessment not found"})
return
}
// Pre-fill registration from assessment intake
intake := assessment.Intake
reg := ucca.AIRegistration{
TenantID: tenantID,
SystemName: intake.Title,
SystemDescription: intake.UseCaseText,
IntendedPurpose: intake.UseCaseText,
RiskClassification: string(assessment.RiskLevel),
GPAIClassification: "none",
RegistrationStatus: "draft",
UCCAAssessmentID: &assessmentID,
}
// Map domain to readable text
if intake.Domain != "" {
reg.IntendedPurpose = string(intake.Domain) + ": " + intake.UseCaseText
}
c.JSON(http.StatusOK, reg)
}
// Export generates the EU AI Database submission JSON
func (h *RegistrationHandlers) Export(c *gin.Context) {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
return
}
reg, err := h.store.GetByID(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Registration not found"})
return
}
exportJSON := h.store.BuildExportJSON(reg)
// Save export data to DB
reg.ExportData = exportJSON
h.store.Update(c.Request.Context(), reg)
c.Header("Content-Type", "application/json")
c.Header("Content-Disposition", "attachment; filename=eu_ai_registration_"+reg.SystemName+".json")
c.Data(http.StatusOK, "application/json", exportJSON)
}