-- ============================================================================= -- Migration: 20260420000003_audit_logs_unified_view -- Sessao 11 - Fase 2a (Opcao C). -- -- View audit_log_unified que junta: -- - audit_logs (nova, trigger generico em patients/agenda/etc) -- - document_access_logs (visualizacao/download/impressao de documento) -- - patient_status_history (mudancas de status de paciente) -- - notification_logs (envio de SMS/email/WhatsApp) -- - addon_transactions (compras/consumos de recursos extras) -- -- RLS: aplica-se das tabelas base. View usa security_invoker para herdar. -- ============================================================================= DROP VIEW IF EXISTS public.audit_log_unified CASCADE; CREATE VIEW public.audit_log_unified WITH (security_invoker = true) AS -- 1) audit_logs (trigger generico) SELECT 'audit:' || al.id::text AS uid, al.tenant_id AS tenant_id, al.user_id AS user_id, al.entity_type AS entity_type, al.entity_id AS entity_id, al.action AS action, CASE al.action WHEN 'insert' THEN 'Criou ' || al.entity_type WHEN 'update' THEN 'Alterou ' || al.entity_type || COALESCE(' (' || array_to_string(al.changed_fields, ', ') || ')', '') WHEN 'delete' THEN 'Excluiu ' || al.entity_type END AS description, al.created_at AS occurred_at, 'audit_logs' AS source, jsonb_build_object( 'old_values', al.old_values, 'new_values', al.new_values, 'changed_fields', al.changed_fields ) AS details FROM public.audit_logs al UNION ALL -- 2) document_access_logs SELECT 'doc_access:' || dal.id::text, dal.tenant_id, dal.user_id, 'document' AS entity_type, dal.documento_id::text AS entity_id, dal.acao AS action, CASE dal.acao WHEN 'visualizou' THEN 'Visualizou documento' WHEN 'baixou' THEN 'Baixou documento' WHEN 'imprimiu' THEN 'Imprimiu documento' WHEN 'compartilhou' THEN 'Compartilhou documento' WHEN 'assinou' THEN 'Assinou documento' ELSE dal.acao END AS description, dal.acessado_em AS occurred_at, 'document_access_logs' AS source, jsonb_build_object( 'ip', dal.ip::text, 'user_agent', dal.user_agent ) AS details FROM public.document_access_logs dal UNION ALL -- 3) patient_status_history SELECT 'psh:' || psh.id::text, psh.tenant_id, psh.alterado_por, 'patient_status' AS entity_type, psh.patient_id::text AS entity_id, 'status_change' AS action, 'Status do paciente: ' || COALESCE(psh.status_anterior, '—') || ' → ' || psh.status_novo || COALESCE(' (' || psh.motivo || ')', '') AS description, psh.alterado_em AS occurred_at, 'patient_status_history' AS source, jsonb_build_object( 'status_anterior', psh.status_anterior, 'status_novo', psh.status_novo, 'motivo', psh.motivo, 'encaminhado_para', psh.encaminhado_para, 'data_saida', psh.data_saida ) AS details FROM public.patient_status_history psh UNION ALL -- 4) notification_logs SELECT 'notif:' || nl.id::text, nl.tenant_id, nl.owner_id AS user_id, 'notification' AS entity_type, nl.patient_id::text AS entity_id, nl.status AS action, 'Notificação ' || nl.channel || ' ' || nl.status || COALESCE(' para ' || nl.recipient_address, '') AS description, nl.created_at AS occurred_at, 'notification_logs' AS source, jsonb_build_object( 'channel', nl.channel, 'template_key', nl.template_key, 'status', nl.status, 'provider', nl.provider, 'failure_reason', nl.failure_reason ) AS details FROM public.notification_logs nl UNION ALL -- 5) addon_transactions SELECT 'addon:' || at.id::text, at.tenant_id, at.admin_user_id AS user_id, 'addon_transaction' AS entity_type, at.id::text AS entity_id, at.type AS action, CASE at.type WHEN 'purchase' THEN 'Compra de ' || at.amount || ' créditos de ' || at.addon_type WHEN 'consumption' THEN 'Consumo de ' || abs(at.amount) || ' crédito(s) ' || at.addon_type WHEN 'adjustment' THEN 'Ajuste de créditos ' || at.addon_type WHEN 'refund' THEN 'Reembolso de ' || abs(at.amount) || ' créditos ' || at.addon_type ELSE at.type || ' ' || at.addon_type END AS description, at.created_at AS occurred_at, 'addon_transactions' AS source, jsonb_build_object( 'addon_type', at.addon_type, 'amount', at.amount, 'balance_after', at.balance_after, 'price_cents', at.price_cents, 'payment_reference', at.payment_reference ) AS details FROM public.addon_transactions at; COMMENT ON VIEW public.audit_log_unified IS 'Timeline unificada de eventos auditaveis (LGPD). Herda RLS das tabelas base via security_invoker.'; GRANT SELECT ON public.audit_log_unified TO authenticated;