CREATE TABLE audit_log ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), clinic_id UUID REFERENCES clinics(id), user_id UUID, table_name TEXT NOT NULL, record_id UUID, action TEXT NOT NULL CHECK (action IN ('INSERT','UPDATE','DELETE')), old_data JSONB, new_data JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_audit_clinic ON audit_log(clinic_id, created_at DESC); CREATE OR REPLACE FUNCTION audit_trigger_func() RETURNS TRIGGER AS $$ BEGIN IF TG_OP = 'INSERT' THEN INSERT INTO audit_log (clinic_id, user_id, table_name, record_id, action, new_data) VALUES (NEW.clinic_id, auth.uid(), TG_TABLE_NAME, NEW.id, 'INSERT', to_jsonb(NEW)); RETURN NEW; ELSIF TG_OP = 'UPDATE' THEN INSERT INTO audit_log (clinic_id, user_id, table_name, record_id, action, old_data, new_data) VALUES (NEW.clinic_id, auth.uid(), TG_TABLE_NAME, NEW.id, 'UPDATE', to_jsonb(OLD), to_jsonb(NEW)); RETURN NEW; ELSIF TG_OP = 'DELETE' THEN INSERT INTO audit_log (clinic_id, user_id, table_name, record_id, action, old_data) VALUES (OLD.clinic_id, auth.uid(), TG_TABLE_NAME, OLD.id, 'DELETE', to_jsonb(OLD)); RETURN OLD; END IF; END; $$ LANGUAGE plpgsql SECURITY DEFINER; CREATE TRIGGER audit_patients AFTER INSERT OR UPDATE OR DELETE ON patients FOR EACH ROW EXECUTE FUNCTION audit_trigger_func(); CREATE TRIGGER audit_appointments AFTER INSERT OR UPDATE OR DELETE ON appointments FOR EACH ROW EXECUTE FUNCTION audit_trigger_func(); CREATE TRIGGER audit_consultation_notes AFTER INSERT OR UPDATE OR DELETE ON consultation_notes FOR EACH ROW EXECUTE FUNCTION audit_trigger_func(); CREATE TRIGGER audit_invoices AFTER INSERT OR UPDATE OR DELETE ON invoices FOR EACH ROW EXECUTE FUNCTION audit_trigger_func(); CREATE TRIGGER audit_inventory_movements AFTER INSERT ON inventory_movements FOR EACH ROW EXECUTE FUNCTION audit_trigger_func(); ALTER TABLE audit_log ENABLE ROW LEVEL SECURITY; CREATE POLICY "Admins view audit" ON audit_log FOR SELECT USING (clinic_id = auth.clinic_id());