Auditoria
Leitura da trilha de auditoria unificada (tabela audit_log): quem fez o quê, quando, de onde e em qual entidade. A trilha é append-only na aplicação - este router só tem rotas GET, e um teste da API falha se alguém criar uma rota de escrita aqui.
Só pessoas leem a trilha
Todas as rotas exigem perfil administrador ou diretoria com JWT de pessoa (guard somente_leitor_humano). API Key recebe 403 mesmo com escopo *:*. Toda consulta (listagem e detalhe) também é registrada na própria trilha como consulta_auditoria.
Base path
Todos os endpoints abaixo são montados sob o prefixo:
/api/v1/auditoriaA URL completa em produção é https://api.contabilidadealcance.com.br/api/v1/auditoria.
Escopos necessários
| Escopo | Operações |
|---|---|
auditoria:read | GET /auditoria, GET /{audit_id}, GET /filtros |
O escopo é derivado da rota via _SCOPE_DEP (prefixo /auditoria, método GET). Não existe auditoria:write porque não existe rota de escrita. O gate real é o somente_leitor_humano, rota a rota.
Todas as respostas saem com Cache-Control: no-store (a trilha tem IP e autoria).
Endpoints
GET /auditoria/filtros
Catálogo dos filtros da tela de auditoria: entidades auditadas, ações e origens, cada item com valor (o que vai no filtro) e rotulo (o que o Hub exibe).
Parâmetros
Este endpoint não recebe parâmetros.
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Filtros recuperados",
"data": {
"entidades": [
{ "valor": "configuracao_sistema", "rotulo": "Configuração do sistema" },
{ "valor": "customer", "rotulo": "Cliente" }
],
"acoes": [
{ "valor": "create", "rotulo": "Criação" },
{ "valor": "login_falha", "rotulo": "Login com falha" }
],
"origens": [
{ "valor": "hub", "rotulo": "Hub" },
{ "valor": "api_key", "rotulo": "API Key" }
]
}
}Escopo: auditoria:read + administrador/diretoria com JWT de pessoa
GET /auditoria
Lista a trilha, paginada, com filtros combináveis.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
page | int | query | não | Página (padrão 1, entre 1 e 10000). |
per_page | int | query | não | Itens por página (padrão 25, entre 1 e 100). |
entidade | str | query | não | Tabela auditada (máx. 80), ex.: customer. |
entidade_id | str | query | não | Id da entidade (máx. 64). |
acao | str | query | não | Ação (máx. 40), ex.: update, login. |
ator_usuario_id | int | query | não | Usuário interno autor (>= 1). |
origem | str | query | não | Origem (máx. 40), ex.: hub, portal, worker. |
cliente_id | int | query | não | Cliente relacionado (>= 1). |
de | date | query | não | Dia inicial YYYY-MM-DD (dia em America/Sao_Paulo). |
ate | date | query | não | Dia final YYYY-MM-DD, inclusivo. de posterior a ate → 422. |
q | str | query | não | Busca textual (máx. 100) em entidade_rotulo e rota. |
sort_by | str | query | não | criado_em (padrão), acao, entidade ou origem. |
sort_dir | str | query | não | desc (padrão) ou asc. |
Request
Sem corpo de requisição.
Response 200 OK
{
"status": "success",
"message": "Auditoria recuperada com sucesso",
"data": {
"itens": [
{
"id": 120345,
"criado_em": "2026-10-14T19:02:11.482113",
"acao": "update",
"sucesso": true,
"ator_tipo": "user",
"ator_usuario_id": 7,
"ator_portal_user_id": null,
"api_key_id": null,
"api_key_prefixo": null,
"origem": "hub",
"job": null,
"ip_conexao": "10.0.0.15",
"ip_cliente": "10.0.0.15",
"ip_verificado": true,
"user_agent": "Mozilla/5.0",
"request_id": "5b1f0e7c-2a7d-4c1e-9f0a-3d2b1c0e9a8f",
"metodo": "PUT",
"rota": "/api/v1/customers/42",
"entidade": "customer",
"entidade_id": "42",
"entidade_rotulo": "Empresa Exemplo Ltda",
"cliente_id": 42,
"alteracoes": null,
"detalhes": null,
"ator_nome": "Maria Operadora",
"ator_login": "maria.op"
}
],
"total": 1,
"page": 1,
"per_page": 25
}
}Escopo: auditoria:read + administrador/diretoria com JWT de pessoa
GET /auditoria/{audit_id}
Detalhe de um registro da trilha (mesmo formato de um item da listagem).
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
audit_id | int | path | sim | Id do audit_log. |
Request
Sem corpo de requisição.
Response 200 OK
Envelope com o registro em data e a mensagem "Registro recuperado com sucesso". Id inexistente → 404 (Registro de auditoria não encontrado).
Escopo: auditoria:read + administrador/diretoria com JWT de pessoa
Schemas
Item da trilha
Cada item traz todas as colunas de audit_log mais o nome do ator, resolvido na leitura:
| Campo | Tipo | Descrição |
|---|---|---|
id | int | Id do registro. |
criado_em | str (ISO) | Momento do evento em UTC (sem offset), com microssegundos. |
acao | str | Ação (vocabulário em GET /filtros). |
sucesso | bool | Se a ação teve sucesso. |
ator_tipo | str | Tipo do ator (ex.: user, api_key, portal_user, sistema). |
ator_usuario_id | int | null | Usuário interno. |
ator_portal_user_id | int | null | Usuário do Portal do Cliente. |
api_key_id | int | null | API Key usada. |
api_key_prefixo | str | null | Prefixo da API Key (snapshot). |
origem | str | Origem (vocabulário em GET /filtros). |
job | str | null | Nome da rotina, quando o ator é o sistema. |
ip_conexao | str | null | IP da conexão. |
ip_cliente | str | null | IP do cliente final. |
ip_verificado | bool | Se ip_cliente foi verificado. |
user_agent | str | null | User-Agent. |
request_id | str | null | Id da requisição. |
metodo | str | null | Método HTTP. |
rota | str | null | Rota chamada. |
entidade | str | null | Tabela afetada. |
entidade_id | str | null | Id da entidade. |
entidade_rotulo | str | null | Rótulo legível da entidade. |
cliente_id | int | null | Cliente relacionado. |
alteracoes | object | null | Alterações registradas (JSON). |
detalhes | object | null | Detalhes do evento (JSON). |
ator_nome | str | null | Nome do ator, resolvido por JOIN. |
ator_login | str | null | Login do ator, resolvido por JOIN. |
Notas
- Nome do ator por JOIN (LGPD): a trilha não guarda nome/login como texto. Usuário anonimizado aparece com o nome anonimizado; usuário do Portal apagado aparece como
Usuário do Portal removido; atorsistemaaparece com o nome dojob(ouSistema); demais casos,Anônimo. - Filtro de datas:
de/atesão dias de Brasília convertidos para o intervalo UTC[00:00 de de, 00:00 do dia seguinte a ate), para não perder as últimas horas do dia. - A consulta também é auditada: a listagem grava
consulta_auditoriacom os filtros usados; o texto deqnão é gravado (só que houve busca e o tamanho). O detalhe grava oidconsultado e se foi encontrado. Essa gravação é best-effort e nunca derruba a consulta.