0005 — Auth in-app em 3 camadas + telas de auditoria¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-07-28 · Decidido em: 2026-07-28
Atualização (08/2026, decisão 0006): o motor de auth descrito aqui deixou de ser cópia local e passou a vir da lib
br.com.xadm:xadm-seguranca(pacotebr.com.xadm.comum.seguranca). O modelo de 3 camadas segue igual; só mudou a origem do código. A policy de rota app-específica (whitelist,/webhook/, views públicas por UUID) vive agora emsecurity/ViewWhitelist(local). Oissuerdo cookie virou config (AUTH_ISSUER).
Contexto¶
O tradutor rodava com micronaut-security desligado: as telas de auditoria ficavam atrás do
middleware do Coolify e os endpoints de máquina usavam filtros Bearer dedicados
(ProdutoAuthFilter, WebhookAuthFilter). A operação precisava de três níveis de acesso:
API de máquina, área admin (reprocesso/processamentos) e uma tela pública para a equipe
Thoms/WebStorm ver a auditoria sem login. Com o Coolify na frente de tudo não dá para abrir um path
anônimo — a tela pública exige auth in-app.
Decisão¶
Portar o padrão de segurança in-app do onpetro (bi-comercial-xls) e ligar o
micronaut-security com tri-estado (ViewSecurityRule): enabled (envs AUTH_* presentes)
exige login; bypass em dev/test; fail-closed (503) em prod sem envs. Três camadas:
| Camada | Rotas | Mecanismo |
|---|---|---|
| API (máquina) | /api/csv/processar, /api/integrador/produto (+ alias /webhook/estoque-mudou) |
@Secured("ROLE_API") + StaticBearerTokenValidator (Bearer API_BEARER_TOKEN) |
| Pública (anônima) | / e /{id} (payloads/saída, valores no detalhe) |
ViewSecurityRule retorna ALLOWED direto (ViewWhitelist.isPublicView) |
| Admin (humano) | /admin, /admin/{id}, /admin/produto/{cod}/reprocessar |
login Google @xadm.com.br (Firebase xadm-6ab81, cookie xadm_session); reprocesso com CSRF |
- Um
API_BEARER_TOKENcompartilhado consolida os dois Bearers de entrada antigos (PRODUTO_TOKENdo X-Adm +WEBHOOK_TOKENdo integrador). - Convenção nova: todo callback integrador→app fica sob
/api/integrador/<recurso>(este poke =/api/integrador/produto). O/webhook/estoque-mudouvira alias temporário até o integrador migrar (o poke não cai no deploy; o sweep é a rede).
Consequências¶
- Telas saem de trás do Coolify (auth é do app); em prod, sem
AUTH_*→ 503 (fail-closed), por isso o deploy tem que setar osAUTH_*. - O integrador tem que mandar o
API_BEARER_TOKEN(não maisWEBHOOK_TOKEN) e migrar o path do poke — coordenação cross-repo, coberta pelo alias. - A tela pública expõe preço/estoque completos (decisão do usuário; dado da Thoms).
- Auditoria em duas trilhas sem join por
lote_id:/(payloads/saída) ×/admin(processamentos/entrada,webstorm_ecom_ingestao) — a saída é async por produto/versão.
Alternativas descartadas¶
- Manter só o Coolify na frente — zero código, mas impede a tela pública anônima (tudo ficaria atrás do guard).
- Híbrido Coolify + rota anônima — dois modelos de auth convivendo + config de proxy fina; frágil.
- Dois tokens de API (emissores separados) — mais higiênico, mas o usuário optou por um token só (simples, igual onpetro).
- Pattern greedy no
intercept-url-map(/*isAnonymous) para o detalhe público — exporia o/admin(o intercept-url-map, ordem -100, ganha daViewSecurityRule). Por isso aViewSecurityRuleretornaALLOWEDdireto para/e/{uuid}.
Linhagem de trabalho: .ia/006-auth-camadas-telas-auditoria-*.