O importMap commitado ficou sem a entrada @payloadcms/storage-s3/client#S3ClientUploadHandler
desde o OPS52 (dabc00f4 removeu o handler do blob sem adicionar o do S3, porque o
generate:importmap rodou sem as envs S3_*). Com o plugin s3Storage condicional, sem as
envs o importMap sai consistente (dev/test) mas em produção (envs ativas) o admin falhava
ao montar a view — getFromImportMap: PayloadComponent not found in importMap — login nunca
renderizava. Fix: regenerar com as 4 S3_* dummy inline (loadEnvConfig do @next/env não
sobrescreve envs do processo; iterateConfig não toca DB) — diff de exatamente +2 linhas.
Smoke headless com S3 ativo: /admin/login renderiza, zero erros de console. Gates verdes
(tsc/lint/format/knip/cycles/unit+int 791/build). Sem migration/access/UI. Docs: nota no
AGENTS.md (generate:importmap precisa das S3_* enquanto o plugin for condicional) +
changelog. Guard de CI registrado como OPS70 (#87, depends #77).
6.6 KiB
Impl: Admin do Payload abre em branco em produção (importMap sem o handler do storage S3)
Status: aprovado Atualizado em: 2026-08-19 Issue: #77 Intenção: docs/plans/ops69-admin-branco-importmap-s3.md Appetite restante: herdado (~0,25–0,5 dia eng)
Leitura da intenção
- Outcome: o
/adminrenderiza o formulário de login em produção; o importMap commitado volta a ser consistente com o config que as envs de produção ativam; dev/test semS3_*seguem com storage local. - O que NÃO negociar: não mexer no contrato
/api/media/file/..., não mudar o storage (Garage S3), não mudar o comportamento do plugin em dev/test, não tocar em nada além do fix mínimo do P0. - O que reavaliar: a hipótese "regenerar com envs S3 + diff só de storage" — verificado em evidência da intenção (reprodução local); a mecânica do
payload generate:importmapfoi confirmada no código (gera sem tocar DB; plugin só registra o handler quando ativo; env inline no processo vence os env-files vialoadEnvConfigdo@next/env).
Abordagem recomendada
flowchart LR
A[generate:importmap com S3_* dummy inline] --> B[Diff: só +2 linhas do S3ClientUploadHandler]
B --> C[Gates locais: tsc/lint/format/knip/cycles/unit+int/build]
C --> D[Smoke: dev local com S3_* dummy → /admin renderiza]
D --> E[changelog + linha AGENTS.md + item sucessor do guard]
E --> F[PR em main → CI verde → deploy automático]
Opções consideradas: A | B | C | D
Recomendação: A — regenerar o importMap com as 4 envs S3_* (valores dummy inline) e commitar o diff, porque é o fix mínimo que elimina exatamente a divergência dev/prod: o generate:importmap walka o config via iterateConfig (sem DB), o plugin s3Storage registra o ClientUploadHandler da collection media só quando mediaStorage.enabled, e o CLI carrega env-files com @next/env sem sobrescrever envs já no processo — valores dummy inline garantem o enable sem depender de .env.local/secrets.
Alternativas rejeitadas:
- B — editar
importMap.jsà mão: arquivo gerado; o próximopnpm generate:importmapapaga a edição e a divergência volta sem aviso; nenhuma verificação de consistência. - C — tornar o
s3Storageincondicional (sempre ativo, inclusive sem envs): quebra dev/test (anti-goal da intenção — storage local semS3_*), exigiria Garage local em todo dev e muda o aceite OPS52. - D — guard de CI embutido neste item (rodar
generate:importmapcom envs dummy no gate e falhar se o arquivo commitado divergir): é a resposta certa para a classe de bug, mas a intenção cortou explicitamente melhorias de build/deploy do fix mínimo (questão em aberto → "C como item sucessor"). Registra-se como Issue sucessora no fechamento (dependsem #77).
Componentes / mudanças
src/app/(payload)/admin/importMap.js(gerado, commitado): ganha 2 linhas — import + entrada@payloadcms/storage-s3/client#S3ClientUploadHandler(export confirmado emnode_modules/@payloadcms/storage-s3/dist/exports/client.js). Nenhuma outra entrada muda.package.json/ scripts: nada muda; usa-se opnpm generate:importmapexistente com envs inline.AGENTS.md: uma linha na checklist de verificação local —generate:importmapdeve rodar com as envsS3_*setadas (dummy ok) enquanto o plugin de storage for condicional; sem elas o importMap fica órfão do handler (classe OPS69).- Migration: sem migration. Access / Consent: não se aplica. UI: Impeccable A — sem UI nova.
Guardas de consistência da regeneração
Antes de commitar: git diff do importMap.js deve conter exclusivamente as 2 linhas do storage S3. Se aparecer qualquer outra entrada (drift de componentes admin desde a última regen, a638a8ac), parar e investigar: se o drift é real (componente admin novo sem regen posterior), incluí-lo é consistência correta, mas exige conferir o commit que o introduziu; nunca commitar um diff não compreendido.
Fases verificáveis
- Regeneração —
S3_BUCKET=teqo-media S3_ENDPOINT=http://localhost:3900 S3_ACCESS_KEY_ID=test S3_SECRET_ACCESS_KEY=test pnpm generate:importmap; diff restrito às 2 linhas do S3. (Quota: minutos) - Verificação de consistência + smoke —
git grepdo handler no importMap;pnpm devlocal com as mesmas envs dummy:/admin/loginrenderiza o formulário (o repro da intenção documenta que com S3 ativas + importMap órfão o admin fica branco; com o handler presente, renderiza). O e2eadmin.e2e.spec.tsroda semS3_*(CI) e continua passando — a entrada extra fica inerte. - Gates —
tsc --noEmit,pnpm lint,pnpm format:check,pnpm exec knip,pnpm check:cycles,pnpm test,pnpm build(DB local). E2e: CI (PR). - Fechamento —
docs/changelog/2026-08-19-ops69.md+pnpm changelog:build; linha no AGENTS.md; registrar Issue sucessora do guard via capture-review-debts (depends#77).
Rabbit holes / Não escopo (engenharia)
- Regenerar e ver drift — acima: diff não compreendido = parada obrigatória.
- "Aproveita e roda o guard no CI já" — item sucessor, não este P0.
- Perseguir o erro de beacon do Cloudflare — ruído de console, fora de escopo (já cortado na intenção).
- Testar upload real contra Garage local no dev — o smoke só precisa que a view renderize; o fluxo de upload S3 já é coberto pelo OPS52 em produção.
Riscos e mitigação
- Regeneração traz drift além do S3 (componente admin adicionado desde
a638a8acsem regen): parar, conferir o commit que introduziu o componente, incluir só se for consistência legítima. - Alguém regenera sem envs no futuro e reintroduz o bug: mitigado pela linha do AGENTS.md + Issue sucessora do guard de CI (que falha o gate na divergência).
- Deploy em produção com o importMap novo: verificação pós-deploy pelo runbook
docs/ops/teqo-1313-deploy.md—/adminabre o login e o log do container não re-emitegetFromImportMap: PayloadComponent not found in importMappara@payloadcms/storage-s3/client#S3ClientUploadHandler.
Aceite de engenharia
- Aceite de produto da intenção ainda coberto (admin renderiza em prod; upload S3 intacto; dev/test sem
S3_*intactos) - Invariantes AGENTS/engineering-standards (nenhum schema/access/UI tocado; importMap é arquivo gerado e commitado)
- Diff do importMap restrito às 2 linhas do handler S3, verificado e compreendido
- Gates verdes (tsc/lint/format/knip/cycles/unit+int/build; e2e no CI)
- Changelog + AGENTS.md + Issue sucessora do guard registrada