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/auditoria

A URL completa em produção é https://api.contabilidadealcance.com.br/api/v1/auditoria.

Escopos necessários

EscopoOperações
auditoria:readGET /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âmetroTipoLocalObrigatórioDescrição
pageintquerynãoPágina (padrão 1, entre 1 e 10000).
per_pageintquerynãoItens por página (padrão 25, entre 1 e 100).
entidadestrquerynãoTabela auditada (máx. 80), ex.: customer.
entidade_idstrquerynãoId da entidade (máx. 64).
acaostrquerynãoAção (máx. 40), ex.: update, login.
ator_usuario_idintquerynãoUsuário interno autor (>= 1).
origemstrquerynãoOrigem (máx. 40), ex.: hub, portal, worker.
cliente_idintquerynãoCliente relacionado (>= 1).
dedatequerynãoDia inicial YYYY-MM-DD (dia em America/Sao_Paulo).
atedatequerynãoDia final YYYY-MM-DD, inclusivo. de posterior a ate → 422.
qstrquerynãoBusca textual (máx. 100) em entidade_rotulo e rota.
sort_bystrquerynãocriado_em (padrão), acao, entidade ou origem.
sort_dirstrquerynãodesc (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âmetroTipoLocalObrigatórioDescrição
audit_idintpathsimId 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:

CampoTipoDescrição
idintId do registro.
criado_emstr (ISO)Momento do evento em UTC (sem offset), com microssegundos.
acaostrAção (vocabulário em GET /filtros).
sucessoboolSe a ação teve sucesso.
ator_tipostrTipo do ator (ex.: user, api_key, portal_user, sistema).
ator_usuario_idint | nullUsuário interno.
ator_portal_user_idint | nullUsuário do Portal do Cliente.
api_key_idint | nullAPI Key usada.
api_key_prefixostr | nullPrefixo da API Key (snapshot).
origemstrOrigem (vocabulário em GET /filtros).
jobstr | nullNome da rotina, quando o ator é o sistema.
ip_conexaostr | nullIP da conexão.
ip_clientestr | nullIP do cliente final.
ip_verificadoboolSe ip_cliente foi verificado.
user_agentstr | nullUser-Agent.
request_idstr | nullId da requisição.
metodostr | nullMétodo HTTP.
rotastr | nullRota chamada.
entidadestr | nullTabela afetada.
entidade_idstr | nullId da entidade.
entidade_rotulostr | nullRótulo legível da entidade.
cliente_idint | nullCliente relacionado.
alteracoesobject | nullAlterações registradas (JSON).
detalhesobject | nullDetalhes do evento (JSON).
ator_nomestr | nullNome do ator, resolvido por JOIN.
ator_loginstr | nullLogin 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; ator sistema aparece com o nome do job (ou Sistema); demais casos, Anônimo.
  • Filtro de datas: de/ate sã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_auditoria com os filtros usados; o texto de q não é gravado (só que houve busca e o tamanho). O detalhe grava o id consultado e se foi encontrado. Essa gravação é best-effort e nunca derruba a consulta.