From a1a6160ed8a1fcf9842bc9a7576bc3dda1d311af Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Tue, 18 Aug 2026 19:31:07 -0300 Subject: [PATCH] =?UTF-8?q?plan(OPS69):=20admin=20em=20branco=20em=20produ?= =?UTF-8?q?=C3=A7=C3=A3o=20=E2=80=94=20importMap=20sem=20o=20handler=20do?= =?UTF-8?q?=20storage=20S3=20(Related=20#77)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/plans/ops69-admin-branco-importmap-s3.md | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 docs/plans/ops69-admin-branco-importmap-s3.md diff --git a/docs/plans/ops69-admin-branco-importmap-s3.md b/docs/plans/ops69-admin-branco-importmap-s3.md new file mode 100644 index 00000000..2a4a4b1e --- /dev/null +++ b/docs/plans/ops69-admin-branco-importmap-s3.md @@ -0,0 +1,72 @@ +# Admin do Payload abre em branco em produção (importMap sem o handler do storage S3) + +Status: aguardando execução (blocked) +Atualizado em: 2026-08-18 +Issue: #77 +Priority: P0 +Model: composer-2.5 +Impeccable: A — sem mudança de UI (corrige regressão que deixa o admin em branco) +Rascunho UI: N/A — sem UI nova +Appetite: ~0,25–0,5 dia eng; um outcome verificável (login do admin renderiza em prod) +Responsável: — + +## Intenção + +O admin do Payload (`/admin`) está **em branco em produção** (jorgesolla1313.com.br): a página carrega (HTML 200, chunks 200, `/api/users/me` 200), o shell do app hidrata, mas o formulário de login nunca renderiza — nada aparece. Isso trava o time editorial e de campanha: sem admin não há CMS, não há gestão de conteúdo, não há import/export de contatos. + +**Diagnóstico verificado (evidência abaixo):** a causa raiz é o `importMap` commitado (`src/app/(payload)/admin/importMap.js`) **sem** a entrada `@payloadcms/storage-s3/client#S3ClientUploadHandler`. O plugin `s3Storage` (OPS52) é ativado só quando as envs `S3_*` estão presentes — em produção elas estão, então o admin precisa resolver o handler do upload do `media` via importMap, e a entrada não existe → o admin falha ao montar a view. Em dev/test as `S3_*` não existem → plugin desligado → importMap consistente → admin funciona. É a divergência dev/prod exata. + +O erro reportado no console ("Cross-Origin Request Blocked" + SRI mismatch do `beacon.min.js` do Cloudflare) é **ruído, não causa**: o hash `sha512` declarado no HTML bate com o arquivo real servido (verificado), e o "computed hash" de conteúdo vazio no erro do usuário indica apenas que o fetch do beacon foi bloqueado no browser dele. Bloquear o beacon não muda nada no admin. Não seguir por esse caminho. + +## Persona e fluxo + +- **Persona / contexto:** time editorial/campanha (staff com acesso ao `/admin`); hoje está parado — abriu o admin, página branca, sem erro aparente. +- **Job principal:** entrar no `/admin` e fazer login. +- **Fluxo desejado:** abrir `jorgesolla1313.com.br/admin` → redirecionar para `/admin/login` → formulário de login visível → logar e usar o CMS normalmente. +- **Anti-goals de produto:** não é para redesenhar o admin, nem mudar o storage de media, nem mexer no contrato `/api/media/file/...`; é restaurar o comportamento que existia. + +## Objetivo e aceite + +- `/admin` e `/admin/login` renderizam o formulário de login em produção (não página branca), sem erros no console do browser. +- Login no admin funciona de ponta a ponta em prod (autenticar e abrir uma collection/global). +- O upload de media continua funcionando (Garage S3) — o fix não pode quebrar o fluxo OPS52. +- O importMap commitado volta a ser consistente com o config ativado por envs de produção. +- Dev/test continuam funcionando sem as envs `S3_*` (storage local, como hoje). + +## Dados (intenção) + +- **Vou apresentar dados?** Não — item de infra/regressão, sem superfície de dados. +- **Decisões desbloqueadas:** nenhuma de produto; decisão de engenharia (ver Questões em aberto). + +## Direção no codebase (hipótese) + +- **Áreas prováveis:** `src/app/(payload)/admin/importMap.js` (arquivo gerado, commitado), `src/payload.config.ts` (plugin `s3Storage` condicional, linhas ~150–172), `src/utilities/mediaStorage.ts` (resolução das envs `S3_*`), `src/collections/Media.ts` (upload), `package.json` (`pnpm generate:importmap`). +- **Precedente a olhar:** commit `dabc00f4` (OPS52 — trocou vercel-blob por s3 e regenerou o importMap **sem** as envs S3, removendo o handler do blob e não adicionando o do S3); o e2e do admin (`tests/e2e/admin.e2e.spec.ts`) não pega isso porque roda sem `S3_*` (mesma divergência dev/prod). +- **Risco de acoplamento:** o importMap é regenerado inteiro por `pnpm generate:importmap` — regenerar com envs S3 altera só as entradas do storage (verificado: +2 linhas do `S3ClientUploadHandler`); não deve tocar nas entradas existentes do lexical/import-export. + +## Dependências + +- Soft: OPS52 (introduziu a regressão — contexto, não blocker). + +## Fora de escopo + +- Seguir o erro do beacon do Cloudflare (`static.cloudflareinsights.com`) — é ruído de console; registrar como nota para a equipe, não como trabalho. +- Mudar o storage de media (S3→outro), o contrato de URL `/api/media/file/...`, ou o comportamento do plugin em dev/test. +- Melhorias de build/deploy fora do fix mínimo (guard no CI pode entrar como item sucessor — ver Questões). + +## Rabbit holes de produto + +- **"Já que vou mexer no importMap, aproveito e atualizo tudo".** Regenerar sem envs de produção corretas introduz a MESMA classe de bug de novo. **Corte neste item:** regenerar com as envs S3 setadas (mesmo as de teste apontando para localhost/garage de teste), conferir o diff (só storage), e não tocar em mais nada. +- **"O erro do beacon deve ser o problema, vamos mexer no Cloudflare".** Caminho morto: o beacon não bloqueia o admin (evidência: admin branco também via origem direta, sem Cloudflare no meio). **Corte:** registrar como ruído e focar no importMap. + +## Questões em aberto (produto) + +- **Como impedir que a divergência dev/prod volte a acontecer?** **Opções:** A) só regenerar e commitear o importMap (mínimo, risco de regressão futura quando um plugin condicional mudar de novo); B) regenerar + nota/documentação no `local-database` ou no AGENTS.md dizendo que `generate:importmap` precisa das envs de produção quando o config for condicional; C) regenerar + guard de CI (ex.: rodar `generate:importmap` com envs S3 de teste e falhar o gate se o arquivo commitado divergir). **Recomendação:** A agora (fix do incidente, mínimo e verificado) + **C como item sucessor** (evidência de que CI/e2e não pegam essa classe de bug — vale um guard, mas não bloqueia o P0). _(assumido — validar com produto)_ +- **Prioridade P0 confirmada?** **Recomendação:** sim — admin é a ferramenta central do time; cada dia em branco é dia sem CMS. _(assumido — validar com produto)_ + +## Referências + +- GitHub Issue #77 +- Rascunho UI (gate): N/A +- `src/payload.config.ts` (plugin condicional `s3Storage`), `src/app/(payload)/admin/importMap.js` (entrada ausente), `src/utilities/mediaStorage.ts`, commit `dabc00f4` (OPS52), `tests/e2e/admin.e2e.spec.ts` (por que CI não pega) +- Evidência: logs do container prod (`getFromImportMap: PayloadComponent not found in importMap` para `@payloadcms/storage-s3/client#S3ClientUploadHandler`); reprodução local (admin branco com `S3_*` setadas + importMap atual; admin renderiza após regenerar o importMap com as envs e reverter o arquivo)