Retenção de Dados e Bloqueios Legais
Políticas de retenção entram em conflito: direito à exclusão do GDPR, trilhas de auditoria SOC2 e congelamentos de litígio por bloqueio legal. O Postgres implementa a política através de particionamento, exclusão lógica (soft delete) e tabelas de auditoria imutáveis com propriedade clara.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
-- Metadados de retenção em eventos particionados
CREATE TABLE events (
id bigint GENERATED ALWAYS AS IDENTITY,
tenant_id uuid NOT NULL,
occurred_at timestamptz NOT NULL,
payload jsonb NOT NULL,
PRIMARY KEY (id, occurred_at)
) PARTITION BY RANGE (occurred_at);
-- Sinalizador de bloqueio legal (tabela separada evita reescrita de histórico)
CREATE TABLE legal_holds (
subject_type text NOT NULL,
subject_id uuid NOT NULL,
hold_until date,
PRIMARY KEY (subject_type, subject_id)
);Quando usar isso: Solicitações de exclusão do GDPR, retenção de auditoria financeira, bloqueio legal ou crescimento de disco da tabela de logs.
Exemplo de Trabalho
O cliente solicita a exclusão sob o GDPR. As finanças exigem retenção de faturas por 7 anos.
-- Pseudonimizar PII em linha de fatura compartilhada (reter fatos financeiros)
UPDATE customers
SET email = 'deleted-' || id::text || '@invalid.local',
name = 'REDACTED',
deleted_at = now()
WHERE id = $1;
-- Bloquear exclusão se houver bloqueio legal ativo
SELECT 1 FROM legal_holds
WHERE subject_type = 'customer' AND subject_id = $1
AND (hold_until IS NULL OR hold_until >= current_date);-- Remover partições de eventos antigas que excederam a retenção (sem linhas de bloqueio na partição)
ALTER TABLE events DETACH PARTITION events_2023_q1;
DROP TABLE events_2023_q1;O que isso demonstra:
- Pseudonimização atende a algumas solicitações de exclusão, mantendo as faturas.
- Bloqueio legal verificado antes de DML destrutivo.
- O desanexamento/exclusão de partições é o mecanismo escalável de retenção.
- A política vive em documentos de produto + legais, aplicada em jobs SQL.
Mergulho Profundo
Matriz de Política
| Classe de dados | Retenção típica | Exclusão |
|---|---|---|
| Eventos de marketing | 13-24 meses | Exclusão física (hard delete) |
| Faturas | 7 anos fiscais | Pseudonimizar PII apenas |
| Ações administrativas de auditoria | 3-7 anos | Imutável somente adição (append-only) |
| Logs de aplicação no BD | 30-90 dias | Exclusão de partição |
Implementação de Exclusão do GDPR
-- Padrão de exclusão lógica (soft delete)
ALTER TABLE customers ADD COLUMN deleted_at timestamptz;
CREATE INDEX customers_active_idx ON customers (id) WHERE deleted_at IS NULL;
-- RLS oculta linhas excluídas da role do aplicativo
CREATE POLICY customers_active ON customers
FOR SELECT TO app_role
USING (deleted_at IS NULL);A exclusão física (hard delete) só ocorre em cascata quando o jurídico confirma que não há bloqueio e nenhuma retenção legal.
Imutabilidade de Auditoria
REVOKE UPDATE, DELETE ON audit_log FROM PUBLIC;
GRANT INSERT ON audit_log TO app_audit_role;
-- Opcional: pgaudit ou trigger para aplicação somente adição (append-only)Job de Retenção
# Cron mensal: remover partições mais antigas que a política
psql -c "SELECT drop_expired_event_partitions(24);" # mesesArmadilhas
- DELETE sem revisão legal - Risco de espólio durante litígio. Correção: Tabela de bloqueio (hold table) + ticket de fluxo de trabalho legal.
- Exclusão lógica sem RLS - Aplicativos ainda vazam linhas "excluídas". Correção: RLS ou views com
deleted_at IS NULL. - Exclusão em backups - Backups retêm dados até o vencimento. Correção: Documentar retenção de backup; política de criptografia e destruição (crypto-shred).
- Surpresa do CASCADE - Exclusão do GDPR remove faturas não intencionalmente. Correção: FK
ON DELETE RESTRICTem filhos regulamentados. - DELETE de tabela inteira para retenção - Bloqueios e inchaço (bloat). Correção: Exclusão de partição ou exclusão em lote com intervalos de chaves.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Arquivar para armazenamento frio | Retenção longa e barata | Necessidade de consulta SQL no arquivo |
| Cluster de auditoria separado | Conformidade pesada | Carga operacional para equipe pequena |
| Streaming de eventos para SIEM | Logs saem do Postgres | BD é o sistema de registro |
| Função de anonimização | Exclusão repetível | Risco de reidentificação permanece |
FAQs
O GDPR exige exclusão física (hard delete)?
Frequentemente, a pseudonimização é suficiente quando a retenção legal se aplica; o jurídico decide por solicitação.
Como implementar bloqueio legal (legal hold)?
Sinalizador em legal_holds; jobs pulam exclusão/remoção de partição para assuntos sinalizados.
Partições podem acelerar a exclusão?
Sim, para dados com limite de tempo; dados vinculados a inquilinos (tenant-bound) podem precisar de purga em nível de linha ou fragmento por inquilino.
E as réplicas?
Exclusões se replicam; garanta que o comportamento em cascata seja idêntico nos assinantes.
Retenção vs vacuum?
Retenção reduz a contagem de linhas; vacuum recupera espaço após exclusão ou remoção.
Quem é o proprietário da política de retenção?
O jurídico + produto são proprietários da política; engenharia implementa automação e auditorias.
PCI no mesmo banco de dados?
Isole o esquema de dados do titular do cartão; retenção e registro de acesso mais rigorosos.
Como provar a exclusão?
Entrada no log de auditoria com ID da solicitação, tabelas afetadas, contagens de linhas, timestamp.
Direito de acesso?
Job de exportação une a chave do cliente; separado do runbook de exclusão.
O que devo ler a seguir?
Veja Retenção e Desanexamento.
Relacionados
- Noções Básicas de Stakeholder - enquadramento executivo
- Segurança em Nível de Linha - isolamento de inquilino
- pgaudit e Registro de Conformidade - trilha de auditoria
- Noções Básicas de Particionamento - retenção de tempo
Versões da Stack: Esta página foi escrita para PostgreSQL 18.4 (estável 18, manutenção 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x e PostGIS 3.5+.