Auditoria — Logs de Transações: cobertura de filtros e fuso horário
Data: 2026-04-27 Escopo: Admin → Monitoramento → Logs de Transações Severidade: Alta (filtros inutilizáveis para 42 ações; janela de data 3h deslocada)
Sintomas reportados
- Ações
assinatura.*,fatura.*,auth.*(entre outras) não apareciam no dropdown de filtro — impossível filtrar. - Filtrar
Data Início = Data Fim = 19/04/2026não retornava registros após 21:00 BRT desse mesmo dia.
Diagnóstico
Bug 1 — Catálogo SSOT defasado
src/constants/log-actions.ts (LOG_ACTION_OPTIONS) é a fonte única do dropdown de filtro e do label exibido nos badges. Ações registradas via registrarLog() no backend que não estão nesse array ficam invisíveis no filtro embora persistam no DB.
Query agregada em logs_transacoes (últimos 30 dias) revelou 42 ações órfãs, com destaque:
| Ação | Volume 30d | Categoria |
|---|---|---|
auth.select_role | 599 | Troca de papel |
login.e2e_bypass | 325 | Bypass E2E |
assinatura.update_valor_personalizado | 13 | Faturamento admin |
fatura.recalculate_due_date | 6 | Faturamento admin |
manutencao.cleanup_* | ~85 (somatório) | CRON granular |
header.programar, header.reorder, header.placeholder_* | ~25 | Header avançado |
Lista completa no commit que adicionou as 42 entradas em LOG_ACTION_OPTIONS (seção "COMPLEMENTOS — auditoria 2026-04-27").
Bug 2 — Janela de data em UTC, sem conversão BRT
supabase/functions/admin-logs/index.ts usava:
query = query.gte('criado_em', filters.dataInicio); // "2026-04-19" → 00:00 UTCComo o frontend manda YYYY-MM-DD puro, o backend interpretava como 00:00 UTC = 21:00 BRT do dia anterior. Resultado: registros após 21:00 BRT do dia consultado caíam no "dia seguinte UTC" e eram filtrados fora.
Para 19/04/2026 em fuso BRT (UTC−3), a janela correta é:
>= 2026-04-19T03:00:00Z(00:00 BRT)< 2026-04-20T03:00:00Z(00:00 BRT do dia seguinte)
Correções aplicadas
1. Catálogo (frontend)
src/constants/log-actions.ts: +42 entradas em seção dedicada "COMPLEMENTOS — auditoria 2026-04-27", organizadas por domínio (Auth, Assinatura, Fatura, Faturamento CRON, Header, Manutenção, Mural, Olimpíada, Pagamento, Importação, Perfil, Usuário). Labels em português seguindo o padrão existente.
2. Fuso horário (backend)
supabase/functions/admin-logs/index.ts (linhas 92–110): aplica BRT_OFFSET_HOURS = 3 antes de .gte() e .lt(). Frontend continua enviando YYYY-MM-DD puro — única fonte de verdade do fuso é o edge function.
const BRT_OFFSET_HOURS = 3;
const inicio = new Date(`${filters.dataInicio}T00:00:00.000Z`);
inicio.setUTCHours(inicio.getUTCHours() + BRT_OFFSET_HOURS);
query = query.gte('criado_em', inicio.toISOString());3. Guardrail — script de auditoria
scripts/audit/log-actions-coverage.ts: compara SELECT DISTINCT acao FROM logs_transacoes (90d) contra LOG_ACTION_OPTIONS e sai com código 2 se houver órfãs. Roda mensalmente (proposta: integrar ao @audit logs).
Regra preventiva
Toda nova string passada para registrarLog() DEVE ser adicionada a LOG_ACTION_OPTIONS no mesmo PR. Sem entrada no catálogo, a ação é invisível para o operador de monitoramento.
Documentado em docs/security/AUDIT_LOG.md.
Validação
- ✅ Build do frontend passa.
- ⏭️ Validação manual: filtrar
auth.select_roleno admin retorna ≥ 599 registros. - ⏭️ Validação manual: filtrar
19/04 → 19/04em BRT retorna registros até 23:59 BRT.