# Smoke local do compose de desenvolvimento Smoke do ambiente Docker local. Confere o Adaptador depois de atualizar código, reinstalar dependências ou recriar os contêineres, sem Supabase de homologação. Não altera `scripts/smoke-staging.ts` nem o comando `npm run smoke:staging`. ## Separação | | Smoke local | Smoke de homologação | | --- | --- | --- | | Comando | `npm run smoke:local` | `npm run smoke:staging` | | Script | `scripts/smoke-local.ts` | `scripts/smoke-staging.ts` | | Alvo | `http://127.0.0.1:3000` (`ADAPTER_SMOKE_LOCAL_URL` só se for HTTP em loopback) | `ADAPTER_SMOKE_URL` público | | Identidade | `POST /api/dev/session` com as fixtures de desenvolvimento | Supabase Auth de homologação | | Banco | Postgres 16 do `docker-compose.yml`, publicado em loopback | Banco de homologação | | Jornada | modelo XLSX, upload, mapeamento, prévia, worker, XLSX, CSV e PDF | fase 1 anônima; fase 2 só leitura autenticada. Upload e download continuam no runbook | | Resultado | evidência do compose local | evidência de `hml-ada.elopro.app` | Um PASS local não preenche nem aprova os gates de homologação externa do [checklist](21-checklist-validacao.md): deploy real (F7), smoke de homologação (F10) e ensaio de rollback (F11) continuam pendentes até rodarem no ambiente externo. ## Quando rodar Com o compose local no ar: ```bash docker compose up --build docker compose exec web /app/docker/entrypoint.sh migrate npm run smoke:local ``` A migration é um passo anterior e manual. O smoke não executa `migrate`, `seed`, `seed:staging` nem `flag`. ## O que verifica 1. `GET /api/health/ready` com HTTP 200 e `status=ready`. 2. `checks.database=ok`. 3. `checks.migrations=ok`, sem ids pendentes. Se houver migration pendente, a jornada não grava. 4. `checks.redis=ok`. 5. Leitura e escrita no volume privado: o contêiner `web` grava, relê e apaga um arquivo em `/app/.data/storage/_smoke-local`. O health de storage só cria diretório; esta prova é separada. 6. `ADAPTER_JOB_MODE=worker` nos contêineres `web` e `worker`. 7. Sessão local emitida e `POST /api/auth/staging/session` respondendo 404. 8. Ana enxerga só o workspace Alpha. 9. `GET /api/spreadsheet-adapter/models` autenticado. 10. Cadastro de um XLSX fictício, upload, mapeamento, prévia, fila do worker e download XLSX, CSV e PDF pelos contratos reais em `src/app/api/spreadsheet-adapter/`. 11. Conteúdo da sentinela fictícia nos três formatos e hash do modelo original inalterado. No PDF a sentinela é lida nos operadores de texto do arquivo gerado: a fonte padrão grava os caracteres em hexadecimal, não como texto solto. 12. Anônimo recebe 401; Diego, no workspace Beta com o módulo desligado, recebe 403 `FEATURE_DISABLED`; Ana não seleciona Beta; Diego não lê, baixa nem exclui o recurso de Alpha; corpo com `workspace_id` de Beta recebe 403 `WORKSPACE_FORBIDDEN`. 13. Logs de `web` e `worker` durante a execução, mais respostas HTTP 5xx. Os dados são colunas `Nome` e `Codigo` e um valor `SMOKELOCAL` mais um sufixo da execução. Não há planilha real. ## Segurança da gravação Antes de cadastrar o modelo, o script: - recusa `ADAPTER_ENV=staging` ou `production` no processo; - recusa URL que não seja HTTP em loopback; - interrompe se `/api/health/ready` reportar outro ambiente; - lê `DATABASE_URL` só dentro do contêiner `web` e só aceita host `postgres` e database `adaptador`; - conecta no host pela porta publicada por `docker compose port`, e só se o bind for loopback; - exige role com `rolsuper` ou `rolbypassrls`, porque a RLS força política e não há `DELETE` de modelo ou de job para `app_user`; - fotografa modelos, jobs, feature flags e configuração de upload. A limpeza, na mesma transação, apaga somente o modelo e as operações criados nesta execução (nome, ids e autor conferidos, ids anteriores excluídos da cláusula). Auditoria removida é só a da Ana, posterior ao início da gravação, ligada a esses ids ou à tentativa de workspace forjado. Se a contagem de auditoria alheia mudar, a transação é desfeita. Os arquivos apagados no volume são só as chaves `original`, `source`, `out.csv` e `out.xlsx` desse modelo e dessa operação. O script não roda `docker compose down` nem remove volume. A feature flag não é ligada, desligada nem restaurada. Se ela mudar durante a execução, o item correspondente falha. Se a limpeza não puder ser garantida, os itens de gravação ficam **PENDENTE** e não entram na conta de aprovados. Código de saída diferente de zero ocorre quando uma verificação executada falha. Pendência sozinha não reprova o processo. ## Relatório Ao terminar, o script imprime executados, aprovados, reprovados, pendentes, tempo, o estado de XLSX, CSV e PDF, as falhas e as pendências.