Pular para conteúdo

0032 — A tela de login é servida pela lib

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

Contexto

O XadmLoginController mora no xadm-seguranca desde a 0.5.0 (0019): a lib manda no fluxo (rotas, CSRF, callback, sessão). A view, não — cada app tem a sua src/main/jte/login.jte. Cinco apps, cinco cópias.

Caracterizando os cinco corpos — não estimando pela similaridade textual, que enganava:

app usa kit.layout marca grande + rodapé Firebase fluxo
bi-comercial-xls sim sim 10.13.2 popup
webstorm-ecom sim sim 10.13.2 popup
bi-transporte-xls sim sim 10.13.2 popup
int-sascar sim não 10.13.2 popup
integrador-server sim não 10.13.2 popup

O mecanismo é idêntico nos cinco — mesma versão do SDK, mesmo signInWithPopup, mesmo POST em /login/callback com o token CSRF. O que diverge é moldura: o bloco de marca (3 têm, 2 não) e o título, em quatro formatos (Login, Login — …, Login | …, Login - …).

Ou seja: está duplicado exatamente o que não deveria — o fluxo de autenticação, onde mora o risco — e o que varia é cosmético. Um bug de auth custa 5 PRs em 5 repos, cada um com uma cópia que já divergiu.

Decisão

A lib é dona da tela inteira; o app parametriza. A login.jte sobe para o xadm-seguranca e sai dos 5 repos. O app não escreve view — configura:

xadm:
  views:
    app-nome: "Integração X-Adm Webstorm"   # já existente: opt-in do XadmViewModel
    login:
      marca: true                            # default false
      tagline: "Um ERP Completo para sua empresa"

O título é derivado do app-nome ("Login — ${app-nome}"), o que mata os quatro formatos por construção em vez de pedir que cinco apps escrevam a mesma string do mesmo jeito. Property ausente degrada para o default e nunca falha o boot — são cosméticas, diferente de property de segredo/auth, onde a casa é fail-closed.

A view da lib é AUTOCONTIDA — não chama o kit.layout (emenda de 2026-09-08, abaixo).

A view de lib mora sob namespace (xadm/login.jte), e isso virou norma para qualquer view empacotada em lib — ver 0025 (emenda de 2026-09-08) e Micronaut §UI. Não é estilo: o JTE transforma subdiretório em pacote, então uma view na raiz do jar geraria a mesma FQCN que a do app, uma sombreando a outra sem erro nem aviso.

Adoção é migração, no mesmo PR (§5): sobe a lib, apaga a view local e o ViewModelProcessor de appVersao, põe as properties.

Consequências

  • Um bug de auth vira um bump de lib, não 5 PRs — que é o ponto.
  • A identidade para de divergir na porta do app: a tela que alguém de fora vê primeiro passa a ser a mesma em toda a casa.
  • O appVersao passa a vir da lib. O kit/headerRight.jte já o renderiza sob @if(appVersao != null); a lib já tem o valor (VersaoInfo). Some o processor per-app.
  • Acoplamento novo, que nenhum gate pega: o markup vem do jar da lib e o CSS que o estiliza (.xadm-login-logo, .xadm-login-tagline) vem do custom-theme.css, template rastreado do central. Dois repos, dois versionamentos. App com tema velho + lib nova renderiza a marca sem estilo, e só o olho pega — por isso o CHANGELOG do módulo declara a versão mínima da constituição, e o sintoma está nomeado na receita.
  • O JTE entra no xadm-seguranca como compileOnly — VERIFICADO no artefato (2026-09-08). Preserva a decisão do módulo ("o runtime de views é provido pelo app consumidor"): app API-only que usa a lib de auth não ganha motor de view. O jar traz a JteloginGenerated sob namespace e o reflection-config.json gerado; o POM não tem nenhuma entrada gg.jte. Os planos B — cair para implementation, ou criar o módulo xadm-seguranca-views — saem da mesa. Mas há uma condição, e ela não é opcional: o POM só fica limpo porque o implementation.extendsFrom(jteGenerate) do plugin foi desfeito no módulo. Sem isso, a extensão de build (jte-native-resources + o jte-runtime que ela arrasta) sai como dependência de runtime de todo adotante e o compileOnly vira letra morta — em silêncio, porque só o POM publicado revela. Receita e cura em Micronaut §Native.
  • View órfã não quebra o build (a da lib está sob namespace) — fica arquivo morto, cobrável pelo §3b da /xadm-docs.

Correção 2026-09-08 — a view da lib é autocontida, não usa o kit.layout

O que motivou: a decisão original dizia que a view usaria o kit.layout, como as telas dos apps. Isso não compila. Verificado no artefato gerado: @template.kit.layout(...) é resolvido em tempo de geração, não em runtime — o JteloginGenerated.java:9 de um app real contém a chamada Java direta gg.jte.generated.precompiled.kit.JtelayoutGenerated.render(...). Logo, uma view empacotada na lib que chamasse o kit exigiria kit/layout.jte dentro do build da lib — e o kit é template rastreado, copiado para os apps.

A saída adotada: a xadm/login.jte traz o próprio documento mínimo — logo, nome do app e versão —, usando o custom-theme.css e o Bootstrap vendorizado que o app já serve. A identidade continua vindo de onde sempre veio: o CSS, não a estrutura do layout. E a tela não perde nada do que o kit tem de rico, porque sem sessão nada disso existe: não há menu (todo item redirecionaria de volta) nem chip de usuário.

Custo aceito: ~10 linhas de header vivem duplicadas no jar e podem divergir visualmente do header logado com o tempo. É o preço de não ter dependência de template entre repos.

Alternativas descartadas nesta emenda:

  • Lib carrega o kit sob namespace próprio (xadm/kit/layout.jte): compila e não colide, mas cria duas cópias do layout — o login renderiza a do jar, o resto do app a dele. Quando o kit muda no central (como acabou de mudar, CDN→asset local), o app re-deriva e a lib só na release seguinte: a tela de login carregaria o Bootstrap do CDN enquanto o resto carrega local, ou pediria um asset que o app não copiou. Skew declarável, não eliminável.
  • Mover o kit para a lib, com os apps chamando @template.xadm.kit.layout: um dono só, o mais limpo em tese. Custo em dois eixos — 98 views em 6 apps mudam a chamada, e correção no kit deixa de chegar por /xadm-docs re-derive, passando a exigir release da lib e bump em cada app; mais lento que hoje.
  • Kit como artefato de template publicado, consumido no build por lib e apps: manteria um dono sem migrar as 98 views, ao custo de um mecanismo de distribuição de template JTE que a casa não tem — infra nova para um problema que a saída adotada resolve sem nenhuma.

Alternativas descartadas

  • Template rastreado no kit (templates/views-jte/kit/login.jte, re-derivado pela /xadm-docs): é a mecânica que a casa já usa e entende, e mataria o drift de conteúdo. Mas a view continuaria copiada em 5 repos: um fix de auth exigiria os 5 re-derivarem e re-releasarem, e a divergência voltaria em quem editasse a cópia. O que se quer eliminar é a cópia, não só o drift.
  • Lib dona só do mecanismo (um fragmento/JS com Firebase + CSRF + callback, markup no app): preservaria liberdade total de layout. Mas continuariam 5 arquivos vivos, e o drift voltaria pelo markup — que é exatamente onde os 5 já divergiram.
  • Bean customizador (LoginPageCustomizer implementado pelo app) em vez de properties: mais poder, mas vira API pública da lib (quebrar depois é breaking) e exige código onde bastaria uma linha de YAML.
  • Slot JTE para o app injetar markup próprio: é a armadilha do kit em 2026-07 — slot especulativo, zero uso, que derrubou 126 views (0015). A variação real observada cabe nas properties.
  • Módulo novo xadm-seguranca-views: fronteira de dependência mais limpa que o compileOnly, mas seria o nono módulo do xadm-commons — a constituição §5 nomeia oito — e separaria o controller da view dele.

Referências

  • Receita e properties: Micronaut §UI
  • Norma do namespace: 0025 (emenda) · constituição §5
  • 0019 (os módulos e suas capacidades) · 0010 (UI unificada) · 0017 (a fronteira custom-theme.css × app.css)