Pular para conteúdo

0014 — Smoke de produção pós-deploy (adota a central 0031)

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-08 · Decidido em: 2026-09-08

Contexto

O deploy do tradutor sai pelo control-plane (POST /api/ci/deploy, central 0026, adotada localmente na 0013) e esse POST é assíncrono: ele retorna sucesso e o pipeline fica verde antes de o container novo servir. O /health que o Coolify observa é liveness — o processo subiu e o Flyway passou —, não "as telas respondem". Entre os dois cabe a classe de falha que a frota já entregou com o app healthy: tela em 500 e segredo ausente que só apareceu como 401 no cliente.

Aqui a superfície é concreta: o tradutor serve views JTE atrás de sessão (/, /admin, /admin/monitor) e roda native (0011), onde o AOT pode podar uma rota registrada — 404 no binário e 200 no jar, sem erro de build. Até agora nada no pipeline afirmava produção depois do deploy.

A casa fixou o alvo na ADR central 0031 — Smoke de produção pós-deploy (constituição §9; receita em smoke-producao).

Decisão

Adotar a central 0031 neste repo, sem variação local. O que isso significa aqui:

  • Job smoke no pipeline.yml, depois do deploy, rodando scripts/smoke.py da toolchain. Reprovou em qualquer camada → reverte para a tag imutável <imagem>:<sha anterior>-<target>, confirma a reversão e fica vermelho.
  • Manifesto em docs/app.json → smoke: base https://webstorm.thoms.xadm.biz, projeto thoms-integracao-produto-ecom no GlitchTip e as rotas críticas — /health e /login como public; /, /admin e /admin/monitor como session. Sem rota m2m: os dois endpoints Bearer do tradutor (POST /api/csv/processar, POST /api/integrador/produto) são POST, e o smoke só faz GET — declarar um deles daria 405, não cobertura. A mesma lista serve o e2e native (afirma ≠404 no binário, antes do deploy).
  • Seam de sessão do xadm-seguranca 0.7.0 (POST /smoke/session, header X-Smoke-Token), ligado por smoke.token ← env SMOKE_TOKEN. Nasce desligado: sem a env o @Requires(pattern=".+") reprova e /smoke/** nem existe (404). Sem ele as rotas session degradariam para asserção negativa (302/401), que é o que o login Google interativo permite.
  • Identidade de build cabeada: XADM_COMMIT=${{ github.sha }} como build-arg nos dois jobs de build e ARG/ENV tarde nos dois Dockerfiles (declarado no topo, invalidaria o cache e o nativeCompile de ~13 min rodaria em todo build). O mesmo valor é o commit do /health, a release no Sentry e o sufixo da tag imutável.

Consequências

  • Dois segredos novos por ambiente. SMOKE_TOKEN precisa existir igual nos dois lados — secret no GitHub (job smoke) e env no recurso do Coolify (o app) —; GT_TOKEN (read-only do GlitchTip) habilita a camada 3. Faltando o GT_TOKEN, a camada é pulada; faltando o SMOKE_TOKEN de um dos lados, as rotas session reprovam.
  • bases cobre uma URL. O app tem dois alvos de deploy (jar e native) e o manifesto declara a production_url. Se os dois flavors servirem hostnames distintos, o smoke só afirma o que está declarado — a segunda base tem de entrar na lista, senão metade do deploy fica sem asserção.
  • A reversão é por imagem, não por instância. O POST do control-plane não tem eixo de instância: uma reversão reverte todas as bases. Divergência de commit entre bases é tratada como drift e trava o rollback, por desenho da central.
  • O smoke não prova regressão visual nem que o container velho não respondeu durante a troca (ponto cego declarado na central).

Alternativas descartadas

  • Seguir só com o /health do Coolify. É liveness: foi exatamente o que deixou tela em 500 com app healthy passar por deploy bem-sucedido.
  • Esperar o e2e native cobrir. Ele roda antes do deploy, contra o binário, e afirma só ≠404 — não vê o que produção responde depois que o container troca.
  • Reusar credencial de gente no seam. Daria mais permissão do que o smoke precisa e apagaria a fronteira entre quem testou e quem opera; o principal smoke é próprio, e só-leitura por verbo.