package audit import ( "context" "database/sql" "encoding/json" "log" "time" "github.com/google/uuid" ) type Event struct { ID string Timestamp time.Time UserID string Action string ResourceType string ResourceID string Success bool Details map[string]any } type AuditLogger interface { Record(ctx context.Context, e Event) error } type SQLAuditLogger struct { DB *sql.DB } func NewSQLAuditLogger(db *sql.DB) *SQLAuditLogger { return &SQLAuditLogger{DB: db} } func (l *SQLAuditLogger) Record(ctx context.Context, e Event) error { if e.ID == "" { e.ID = uuid.New().String() } if e.Timestamp.IsZero() { e.Timestamp = time.Now() } detailsJSON, _ := json.Marshal(e.Details) _, err := l.DB.ExecContext(ctx, `INSERT INTO audit_events (id, ts, user_id, action, resource_type, resource_id, success, details) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, e.ID, e.Timestamp, e.UserID, e.Action, e.ResourceType, e.ResourceID, boolToInt(e.Success), string(detailsJSON)) if err != nil { log.Printf("audit record failed: %v", err) } return err } func boolToInt(b bool) int { if b { return 1 } return 0 }