package handlers import ( "encoding/json" "net/http" "github.com/breakpilot/ai-compliance-sdk/internal/iace" "github.com/breakpilot/ai-compliance-sdk/internal/rbac" "github.com/gin-gonic/gin" "github.com/google/uuid" ) // ============================================================================ // Monitoring // ============================================================================ // CreateMonitoringEvent handles POST /projects/:id/monitoring // Creates a new post-market monitoring event. func (h *IACEHandler) CreateMonitoringEvent(c *gin.Context) { projectID, err := uuid.Parse(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"}) return } var req iace.CreateMonitoringEventRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // Override project ID from URL path req.ProjectID = projectID event, err := h.store.CreateMonitoringEvent(c.Request.Context(), req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } // Audit trail userID := rbac.GetUserID(c) newVals, _ := json.Marshal(event) h.store.AddAuditEntry( c.Request.Context(), projectID, "monitoring_event", event.ID, iace.AuditActionCreate, userID.String(), nil, newVals, ) c.JSON(http.StatusCreated, gin.H{"monitoring_event": event}) } // ListMonitoringEvents handles GET /projects/:id/monitoring // Lists all monitoring events for a project. func (h *IACEHandler) ListMonitoringEvents(c *gin.Context) { projectID, err := uuid.Parse(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"}) return } events, err := h.store.ListMonitoringEvents(c.Request.Context(), projectID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if events == nil { events = []iace.MonitoringEvent{} } c.JSON(http.StatusOK, gin.H{ "monitoring_events": events, "total": len(events), }) } // UpdateMonitoringEvent handles PUT /projects/:id/monitoring/:eid // Updates a monitoring event with the provided fields. func (h *IACEHandler) UpdateMonitoringEvent(c *gin.Context) { _, err := uuid.Parse(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"}) return } eventID, err := uuid.Parse(c.Param("eid")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid monitoring event ID"}) return } var updates map[string]interface{} if err := c.ShouldBindJSON(&updates); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } event, err := h.store.UpdateMonitoringEvent(c.Request.Context(), eventID, updates) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if event == nil { c.JSON(http.StatusNotFound, gin.H{"error": "monitoring event not found"}) return } c.JSON(http.StatusOK, gin.H{"monitoring_event": event}) } // GetAuditTrail handles GET /projects/:id/audit-trail // Returns all audit trail entries for a project, newest first. func (h *IACEHandler) GetAuditTrail(c *gin.Context) { projectID, err := uuid.Parse(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"}) return } entries, err := h.store.ListAuditTrail(c.Request.Context(), projectID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if entries == nil { entries = []iace.AuditTrailEntry{} } c.JSON(http.StatusOK, gin.H{ "audit_trail": entries, "total": len(entries), }) }