Auditoria
Este guia detalha o sistema de auditoria completo do ArqSystem para rastreamento de todas as operações.
Visão Geral
O ArqSystem mantém registro completo de auditoria para:
- Criação de documentos
- Atualização de documentos (com mudanças campo a campo)
- Exclusão de documentos (soft delete)
- Criação/edição/exclusão de campos
- Upload de arquivos
- Operações de configuração
Arquitetura
Tabela AuditLog
Modelo central de auditoria:
model AuditLog {
id String @id @default(uuid())
entityType AuditEntityType // DOCUMENT | UPLOADED_FILE | FIELD_CONFIGURATION
entityId String
action AuditAction // CREATE | UPDATE | SOFT_DELETE | etc.
userId String
changes Json?
documentId Int?
createdAt DateTime @default(now())
user User
document Document?
}Tipos de Entidade
AuditEntityType:
DOCUMENT: Operações com documentosUPLOADED_FILE: Operações com arquivosFIELD_CONFIGURATION: Operações com configuração de campos
Tipos de Ação
AuditAction:
CREATE: Criação de entidadeUPDATE: Atualização de entidadeSOFT_DELETE: Exclusão lógicaFIELD_CREATED: Campo criadoFIELD_UPDATED: Campo atualizadoFIELD_DELETED: Campo excluído
Auditoria de Documentos
Criação de Documento
Quando um documento é criado:
await createAuditLog(tx, {
entityType: "DOCUMENT",
entityId: document.id.toString(),
action: "CREATE",
userId: ctx.user.id,
documentId: document.id
});Registro criado:
{
"id": "audit-uuid",
"entityType": "DOCUMENT",
"entityId": "42",
"action": "CREATE",
"userId": "user-uuid",
"documentId": 42,
"changes": null,
"createdAt": "2026-01-14T10:30:00Z"
}Atualização de Documento
Sistema registra mudanças campo a campo:
Processo:
- Busca documento antes da atualização
- Converte para formato de formulário
- Compara valores antigos vs novos
- Registra apenas campos alterados
Exemplo de mudanças:
{
"title": {
"old": "Relatório 2023",
"new": "Relatório Anual 2023"
},
"accessLevel": {
"old": "Restrito",
"new": "Público"
},
"description": {
"old": "Relatório preliminar",
"new": "Relatório final das atividades desenvolvidas em 2023"
}
}Registro completo:
{
"id": "audit-uuid",
"entityType": "DOCUMENT",
"entityId": "42",
"action": "UPDATE",
"userId": "user-uuid",
"documentId": 42,
"changes": {
"title": { "old": "...", "new": "..." },
"accessLevel": { "old": "...", "new": "..." }
},
"createdAt": "2026-01-14T11:45:00Z"
}Exclusão de Documento
Soft delete registrado:
await createAuditLog(tx, {
entityType: "DOCUMENT",
entityId: input.id.toString(),
action: "SOFT_DELETE",
userId: ctx.user.id,
documentId: input.id
});Nota: Documento permanece no banco com deletedAt preenchido.
Auditoria de Campos
Criação de Campo
Quando administrador cria novo campo:
{
"entityType": "FIELD_CONFIGURATION",
"entityId": "field-uuid",
"action": "FIELD_CREATED",
"userId": "admin-uuid",
"changes": {
"fieldKey": { "old": null, "new": "numeroProcesso" },
"label": { "old": null, "new": "Número do Processo" },
"fieldType": { "old": null, "new": "TEXT" }
}
}Atualização de Campo
Mudanças em configuração de campo:
{
"entityType": "FIELD_CONFIGURATION",
"entityId": "field-uuid",
"action": "FIELD_UPDATED",
"userId": "admin-uuid",
"changes": {
"label": {
"old": "Número do Processo",
"new": "Nº do Processo Administrativo"
},
"required": {
"old": false,
"new": true
}
}
}Exclusão de Campo
Remoção de campo personalizado:
{
"entityType": "FIELD_CONFIGURATION",
"entityId": "field-uuid",
"action": "FIELD_DELETED",
"userId": "admin-uuid",
"changes": null
}Função calculateChanges
Utilitário que compara objetos e gera diff:
function calculateChanges(
oldData: Record<string, unknown>,
newData: Record<string, unknown>
): Record<string, { old: unknown; new: unknown }> {
const changes: Record<string, { old: unknown; new: unknown }> = {};
// Compara todos os campos do objeto novo
for (const key in newData) {
if (oldData[key] !== newData[key]) {
changes[key] = {
old: oldData[key],
new: newData[key]
};
}
}
// Verifica campos removidos
for (const key in oldData) {
if (!(key in newData) && oldData[key] !== undefined) {
changes[key] = {
old: oldData[key],
new: undefined
};
}
}
return changes;
}Consulta de Logs
API Endpoint (Futuro)
// Buscar logs de um documento
GET /api/trpc/audit.getDocumentHistory
{
"documentId": 42
}
// Resposta
[
{
"id": "log-3",
"action": "UPDATE",
"userId": "user-uuid",
"user": { "name": "João Silva" },
"changes": { "title": { "old": "...", "new": "..." } },
"createdAt": "2026-01-14T11:45:00Z"
},
{
"id": "log-2",
"action": "UPDATE",
"userId": "user-uuid",
"user": { "name": "Maria Santos" },
"changes": { "accessLevel": { "old": "Restrito", "new": "Público" } },
"createdAt": "2026-01-13T09:20:00Z"
},
{
"id": "log-1",
"action": "CREATE",
"userId": "user-uuid",
"user": { "name": "João Silva" },
"changes": null,
"createdAt": "2026-01-10T14:30:00Z"
}
]Buscar por Usuário
GET /api/trpc/audit.getUserActivity
{
"userId": "user-uuid",
"startDate": "2026-01-01",
"endDate": "2026-01-31"
}Buscar por Período
GET /api/trpc/audit.getActivityByPeriod
{
"startDate": "2026-01-01T00:00:00Z",
"endDate": "2026-01-31T23:59:59Z",
"entityType": "DOCUMENT" // Opcional
}Interface de Visualização
Histórico de Documento
Página de visualização do documento (/documents/:id/view) pode exibir histórico:
┌─ Histórico de Alterações ─────────────────────┐
│ │
│ 14/01/2026 11:45 - João Silva │
│ Atualização │
│ • Título: "Relatório 2023" → "Relatório │
│ Anual 2023" │
│ • Acesso: "Restrito" → "Público" │
│ │
│ 13/01/2026 09:20 - Maria Santos │
│ Atualização │
│ • Descrição: alterada │
│ │
│ 10/01/2026 14:30 - João Silva │
│ Criação do documento │
│ │
└────────────────────────────────────────────────┘Timeline de Atividades
Interface administrativa para visualizar todas as atividades:
┌─ Auditoria do Sistema ────────────────────────┐
│ │
│ Filtros: │
│ [Tipo: Todos ▼] [Ação: Todas ▼] │
│ [Usuário: Todos ▼] │
│ [01/01/2026] - [31/01/2026] │
│ │
│ ──────────────────────────────────────────── │
│ │
│ 14/01 11:45 | João Silva │
│ Documento #42 - Atualização │
│ 2 campos alterados │
│ │
│ 14/01 10:30 | Maria Santos │
│ Documento #43 - Criação │
│ │
│ 13/01 16:20 | Admin │
│ Campo "Número Processo" - Criação │
│ │
│ 13/01 09:20 | João Silva │
│ Documento #42 - Atualização │
│ 1 campo alterado │
│ │
└────────────────────────────────────────────────┘Conformidade e Segurança
Retenção de Logs
Política atual: Logs permanentes
Recomendado (futuro):
- Logs de documentos: Prazo de guarda conforme legislação
- Logs de configuração: Mínimo 5 anos
- Logs de acesso: Mínimo 1 ano
Imutabilidade
Logs são append-only:
- Não podem ser editados
- Não podem ser deletados (exceto via script de manutenção)
- Garantia de integridade do histórico
Rastreabilidade
Todo log inclui:
- Quem: userId do autor da ação
- O que: action + changes detalhadas
- Quando: createdAt (timestamp UTC)
- Onde: entityType + entityId
Privacidade
LGPD/GDPR Compliance:
- Logs de dados sensíveis podem ser anonimizados
- Usuários podem solicitar histórico de suas ações
- Sistema pode exportar logs para análise externa
Relatórios
Relatório de Atividades por Usuário
Quantidade de operações por usuário em período:
┌─ Atividades - Janeiro 2026 ────────────────┐
│ │
│ João Silva │
│ • 45 documentos criados │
│ • 123 documentos atualizados │
│ • 5 documentos excluídos │
│ │
│ Maria Santos │
│ • 23 documentos criados │
│ • 67 documentos atualizados │
│ • 2 documentos excluídos │
│ │
└─────────────────────────────────────────────┘Relatório de Documentos Mais Editados
Documentos com mais alterações:
┌─ Documentos com Mais Edições ──────────────┐
│ │
│ 1. Relatório Anual 2024 (#42) │
│ 15 edições - Última: 14/01/2026 │
│ │
│ 2. Ata de Reunião (#38) │
│ 12 edições - Última: 13/01/2026 │
│ │
│ 3. Memorando Interno (#25) │
│ 8 edições - Última: 10/01/2026 │
│ │
└─────────────────────────────────────────────┘Relatório de Campos Mais Alterados
Quais campos são alterados com mais frequência:
┌─ Campos Mais Editados ──────────────────────┐
│ │
│ 1. Descrição - 234 alterações │
│ 2. Palavras-chave - 189 alterações │
│ 3. Nível de Acesso - 78 alterações │
│ 4. Título - 56 alterações │
│ 5. Observações - 43 alterações │
│ │
└─────────────────────────────────────────────┘Exportação de Logs
Formato CSV
Exportar logs para análise externa:
ID,Data,Usuário,Tipo,Ação,Entidade,Mudanças
log-1,2026-01-14T11:45:00Z,João Silva,DOCUMENT,UPDATE,42,"título: Relatório 2023 → Relatório Anual 2023; acesso: Restrito → Público"
log-2,2026-01-14T10:30:00Z,Maria Santos,DOCUMENT,CREATE,43,
log-3,2026-01-13T16:20:00Z,Admin,FIELD_CONFIGURATION,FIELD_CREATED,field-uuid,"fieldKey: numeroProcesso; label: Número do Processo"Formato JSON
Exportar logs estruturados:
[
{
"id": "log-1",
"timestamp": "2026-01-14T11:45:00Z",
"user": {
"id": "user-uuid",
"name": "João Silva",
"email": "[email protected]"
},
"entityType": "DOCUMENT",
"entityId": "42",
"action": "UPDATE",
"changes": {
"title": {
"old": "Relatório 2023",
"new": "Relatório Anual 2023"
},
"accessLevel": {
"old": "Restrito",
"new": "Público"
}
}
}
]Best Practices
Para Usuários
- Sempre preencha descrições: Facilita entender mudanças no histórico
- Evite edições em lote: Dificulta rastreamento de mudanças
- Revise antes de salvar: Cada salvamento gera log de auditoria
Para Administradores
- Monitore logs regularmente: Detecte atividades suspeitas
- Configure retenção: Defina política de retenção de logs
- Exporte periodicamente: Backup de logs para análise externa
- Analise relatórios: Identifique padrões de uso e problemas
Para Desenvolvedores
- Sempre crie logs: Toda operação deve gerar auditoria
- Use transações: Garanta atomicidade de operação + log
- Capture mudanças: Use
calculateChangespara diffs precisos - Evite informações sensíveis: Não logue senhas ou tokens
Troubleshooting
Log não foi criado
Causas:
- Transação falhou antes do commit
- Erro no
createAuditLog - Permissões insuficientes
Solução:
- Verifique logs de erro do servidor
- Confirme que transação foi commitada
- Adicione try-catch apropriado
Mudanças não aparecem
Causas:
calculateChangesnão detectou diferença- Campos não foram alterados de fato
- Comparação de objetos complexos
Solução:
- Verifique se valores realmente mudaram
- Use
JSON.stringifypara comparação profunda - Adicione logging de debug
Performance de consulta
Causas:
- Tabela de auditoria muito grande
- Falta de índices
- Queries sem filtros
Solução:
- Adicione índices em
userId,entityId,createdAt - Use paginação em consultas
- Implemente arquivamento de logs antigos
Próxima Etapa
Continue para a seção API Reference para detalhes técnicos da API.