-
Status do intake: implemented-pending-homologation
-
Data: 2026-08-30
-
Origem: relato do Engenheiro Chefe — "a caixa de alerta tah com problemas visuais" em
http://localhost/photon/signin/, com o HTML do modal colado -
Classificação: defeito visual, arquitetura de compilação CSS
-
Batch: BATCH-150
1. O sintoma
Na tela de login do Photon, um erro de senha abre o modal de alerta. Ele aparecia sem estilo: o botão "Ok" tinha texto branco sobre fundo transparente — ilegível — e o cartão não tinha sombra nem largura máxima.
Medido no navegador, com o alerta aberto:
| Classe | Esperado | Entregue |
|---|---|---|
bg-sky-600 |
azul | rgba(0, 0, 0, 0) |
shadow-xl |
sombra | none |
max-w-md |
448px | 361px (sem limite) |
7 das 12 classes do modal não tinham regra nenhuma na página.
2. A causa
O componente interface-alerta-modal-tailwind tem seu CSS compilado — 4.694 bytes, no disco e no
banco. O problema não era ausência de CSS, e sim de qual página ele fazia parte.
A compilação Tailwind é por recurso: cada página compila as utilities que o HTML dela usa, mais as
dos recursos declarados em tailwind_dependencies. O modal é injetado em runtime por
interface_alerta(), então nenhuma varredura de HTML o encontra — ele precisa ser declarado.
E estava, em algumas páginas:
perfil-usuario -> declara os 3 modais
Area-restrita -> declara os 3 modais
acessar-sistema -> declara apenas 2FA e login-metodos ← a tela de logininterface_alerta() pode disparar em qualquer tela. Enquanto a declaração fosse manual, a lista
seria uma lista de exceções — e bastava estar incompleta uma vez para a tela quebrar. Foi
exatamente o que aconteceu.
Nas variantes Fomantic o problema nunca existiu: as classes delas (ui modal, ui button) vivem na
folha global do Fomantic, que toda tela carrega. É uma armadilha exclusiva do Tailwind, onde cada
utility precisa ser compilada por quem a usa.
3. A correção
Os três modais que a biblioteca de interface injeta em runtime passaram a ser dependência
automática de toda página Tailwind, resolvida no compilador
(tailwind_recursos_dependencies()), e não declaração por página.
if ($type === 'pages') {
foreach (tailwind_recursos_modais_de_sistema() as $modalId) {
$dependencies[] = ['type' => 'components', 'id' => $modalId,
'scope' => 'global', 'opcional' => true];
}
}Cobertura estrutural: nenhuma página nova precisa lembrar de nada.
Por que opcional
A primeira versão era estrita e abortou a compilação do Photon inteiro:
❌ Erro fatal: Dependência Tailwind do Gestor não encontrada: interface-alerta-modal-tailwindO projeto traz os modais em pt-br e não em en. Ausência aqui não é erro — é uma instalação que
não tem aquele componente naquele idioma.
A distinção que ficou: dependência declarada continua falhando alto (ali a ausência significa erro de digitação); dependência automática degrada em silêncio, porque quem a acrescentou foi o sistema, não o autor do recurso.
Uma tentativa descartada no caminho
Antes disso tentei emitir o CSS do componente junto com o HTML dele, dentro de
interface_componentes_incluir(). Não funcionou, e a razão é instrutiva: aquela rotina faz
$_GESTOR['pagina'] .= $html, ou seja, roda depois de a <head> estar montada. Chamar
gestor_pagina_recursos_incluir() ali é inócuo — ninguém mais vai ler $_GESTOR['css-precompiled'].
Descartada em favor da solução de build, que é onde o problema realmente vive.
4. Validação
| Medida (modal aberto, senha inválida) | Antes | Depois |
|---|---|---|
| Classes sem regra | 7 | 0 |
shadow-xl |
none |
sombra completa |
bg-sky-600 (botão) |
rgba(0,0,0,0) |
oklch(0.588 0.158 241.966) |
max-w-md |
361px | 448px |
-
34 recursos recompilados no core; pipelines de
[REDACTED]-locale[REDACTED]-localpassam. -
PHPUnit 955/955 (4 novos); Vitest 378/378.
-
Confirmação visual: cartão branco, título, mensagem e botão azul legível.
5. Observações registradas, não corrigidas
-
O Photon não tem os componentes do core em
en— sópt-br. Se o projeto for usar inglês, a sincronização de core precisa trazê-los. Hoje a compilação apenas os ignora. -
Bloqueio de IP disparado pelos testes: as repetições de login inválido acionaram a proteção contra força bruta (
acessos.status = 'bloqueado', tipologin, IP[REDACTED]do Docker). O registro foi removido do ambiente local. É o sistema funcionando como projetado.