# Review — alocacao-wms

**Base**: `dev_team`
**HEAD**: `feature/alocacao-wms`
**Arquivos tocados**: 42 (39 de código/i18n + 3 docs de PRD)
**Linhas**: +4997 / -18 (excluindo PRD)

## Sumário

A entrega imita corretamente o padrão V2 canônico (`SugestoesCodigoBarras` para sinal vertical-slice, `InventarioHandler` para execução): dispatcher fino, Sondas com `propeties.db`, Validators e Laboratórios dedicados, Enums backed em `Enums/`, migrations `NNN_*.sql` Postgres, testes espelhando a árvore em `Testes/*TddTest.php`, **zero raw SQL** (todos os writes via `create()`/`update()` do `ModelInteligencia`), e blocos `block_*` sem `DEFAULT`. Arquitetura geral está aderente ao techplan. Porém há **2 blockers** reais: o worker assíncrono (`crons/`) opera sem sessão contra Sondas `customerControl=true` (risco de escopo de tenant errado em produção), e o `Handler` referencia uma view inexistente (`Luz_AlocacaoWmsItemCard` → fatal). Os 3 bugs documentados no `05-testes.md` (migration 002/003, validator linha 151) **já foram corrigidos** no código commitado — confirmei. Há também contaminação de escopo (mudanças de `Edicaorota`/`central.php` não relacionadas à feature) e gaps de i18n (chaves `show()` da UI sem entrada em nenhum idioma). Recomendação: **voltar pro dev** para os 2 blockers; o resto entra com TODOs.

## Issues

### 🔴 Blocker (2 issues)

#### B1 — Worker cron usa Sonda `customerControl=true` sem sessão de usuário
**Onde**: `crons/wms_alocacao_integracao.php:19-101` (bootstrap "sem sessão de usuário") consumindo `WmsAlocacaoSonda` (`Sondas/WmsAlocacaoSonda.php:56` `customerControl => true`)
**Problema**: O bootstrap do worker é explicitamente "mínimo, sem sessão de usuário" (linha 19). Mas `WmsAlocacaoSonda` e a propagação dependem de `customerControl=true`, que resolve a coluna `block` (tenant) a partir da sessão Galaxia. Sem sessão, `buscarPendentesIntegracaoErp/Wms()` e `marcarIntegracaoErp/Wms()` rodam com `block` nulo/zero — podendo (a) não retornar nenhuma linha (fila nunca drena) ou (b) atualizar/varrer o tenant errado. As filas ERP/WMS nunca foram exercitadas com o bootstrap real do cron — o `AlocacaoFluxoTest` testa as Sondas com sessão de teste, não o worker.
**Por que é blocker**: É o caminho que cumpre AC5.1/5.2/5.3 (propagação ERP/WMS). Mesma classe de problema do `feedback_integration_tests` (contexto sem sessão precisa setar `$_SESSION` explicitamente). Em produção multi-tenant, integração que nunca dispara ou dispara no tenant errado é falha silenciosa — exatamente o que AC5.3 proíbe.
**Como corrigir**: O worker precisa iterar por tenant e estabelecer o contexto de `block` antes de cada varredura (setar `$_SESSION`/`galaxiaUserInfo` do tenant, como nos integration tests), OU as queries de fila do worker precisam ser tenant-aware explicitamente (passar `block` como parâmetro e desligar o `customerControl` automático para esse caminho de varredura). Validar com um integration test que rode o `crons/wms_alocacao_integracao.php` de ponta a ponta e prove que `integracao_erp` de uma linha de tenant X vira `enviado`.

#### B2 — `Handler` referencia view inexistente `item_card.php` (fatal em runtime)
**Onde**: `App/Handlers/AlocacaoWmsHandler.php:124` → `renderView('../html/luz/alocacaowms/item_card', $data)`
**Problema**: `Luz_AlocacaoWmsItemCard()` renderiza `html/luz/alocacaowms/item_card`, mas esse arquivo não existe (`html/luz/alocacaowms/` não existe; as views estão em `html/alocacaowms/`). O delegate está registrado em `App.php:566` e exposto como Luz, então qualquer chamada a essa Luz dá fatal/erro de include.
**Por que é blocker**: Código novo referenciando arquivo ausente; quebra em runtime. Não há `<view>.js` pareado nem o `.php` correspondente.
**Como corrigir**: Criar `html/luz/alocacaowms/item_card.php` (+ `.js` se necessário) ou remover o delegate `Luz_AlocacaoWmsItemCard` de `App.php` e do `Handler` enquanto não houver card. Se o card real é o trecho já presente em `html/alocacaowms/item.php`, apontar `renderView` para o path correto.

### 🟡 Major (4)

#### M1 — Progressão automática de status da missão (AC6.2/6.3) não acontece na confirmação
**Onde**: `Laboratorios/ConfirmarAlocacaoLaboratorio.php:96-114` + `MissoesBipagem.php:870` (`garantirMissaoIniciada`)
**Problema**: Após confirmar, o fluxo marca o item concluído (`concluirItemMissao`) e chama `garantirMissaoIniciada()` — que só faz `MissoesStatus::iniciarMissao` (→ EM_ANDAMENTO), cobrindo AC6.1. Mas **não há recálculo de conclusão**: quando o último item é alocado, a missão **não** transita para CONCLUIDA automaticamente (AC6.3), nem reflete "parcialmente concluída" (AC6.2). O techplan §Fluxo passo 3 dizia "atualiza status da missão via `MissoesStatus` (AC3.6/6.1/6.2/6.3)". A conclusão depende do operador acionar `finalizarMissao` manualmente.
**Por que é major**: Diverge do techplan e de 2 ACs. Pode ser intencional (espelha o fluxo de biparItem, onde a finalização é manual) — se for, **documentar o desvio em `03-backend.md`** e ajustar a spec. Hoje o comentário em `MissoesBipagem.php:835` afirma cobrir "AC6.1/6.2/6.3", o que é incorreto.
**Como corrigir**: Ou disparar `MissoesStatus::verificarConclusao`/finalização quando `itensPendentes == 0` no Laboratório, ou registrar explicitamente que a conclusão é manual e corrigir o comentário enganoso.

#### M2 — Contaminação de escopo: mudanças de Edicaorota/Central não pertencem a esta feature
**Onde**: `Central/html/central.php:5128-6108`, `Edicaorota/Sondas/EdicaoRotaSonda.php`, `Edicaorota/html/_layout.php`, `Edicaorota/html/editar_rota.php`
**Problema**: O diff inclui alterações de countdown/aprovação de edição de rota (lógica `podeAprovar`, tooltip de prazo expirado) sem relação com Alocação WMS. Isso infla o review, mistura responsabilidades e dificulta rollback.
**Por que é major**: Branch de feature deveria conter só a feature. Risco de arrastar/reverter trabalho alheio junto.
**Como corrigir**: Mover essas mudanças para a branch/PR própria de Edicaorota. Se forem dependência real, justificar em `03-backend.md`.

#### M3 — i18n: strings da UI usam `show()` mas as chaves não existem em nenhum idioma
**Onde**: `App/html/alocacaowms/item.php` (19 chamadas `show()`: `show('Confirmar alocação')`, `show('Localização')`, `show('Concluídos')`, `show('Buscar produto...')`, etc.) — nenhuma entrada em `linguagens/pt-br.json`, `en.json`, `es.json`
**Problema**: O diff dos arquivos de idioma só acrescenta registros de **caminho de view** (auto-gerado), não chaves de tradução `alocacao_*`. Logo en/es (e o próprio pt-br) caem no fallback literal — viola o requisito de chave i18n nos 3 idiomas. Além disso, `03-backend.md:41-44` afirma que as views são "placeholders documentados", mas `item.php` tem 873 linhas de UI real — a doc está desatualizada.
**Por que é major**: Checklist hard — "String visível sem chave i18n em en/es" é blocker de i18n; classifico como major porque `show()` ao menos está aplicado (não é string crua) e o fallback PT funciona.
**Como corrigir**: Adicionar as chaves correspondentes em `pt-br/en/es.json` para cada string passada a `show()` em `item.php`/`lista.php`/`menu.php`. Atualizar `03-backend.md` para refletir que as views foram implementadas (não placeholders).

#### M4 — Criação da missão no Central (passo 12) não entregue — feature não é utilizável fim-a-fim
**Onde**: ausência em `Central/` (`grep ALOCACAO_WMS` no Central retorna vazio)
**Problema**: O techplan passo 12 e `03-backend.md:204-208` reconhecem que o gestor ainda não consegue criar missão `ALOCACAO_WMS` nem setar `quantidade_obrigatoria`. Sem isso, US1 inteira fica fora e nada do resto é exercitável por usuário real.
**Por que é major**: É um desvio assumido e documentado (não é surpresa), mas deixa a feature incompleta — merge não destrava o fluxo. Aceitável entrar com TODO explícito se a próxima entrega já estiver planejada.
**Como corrigir**: Implementar a exposição de `ALOCACAO_WMS` + checkbox `quantidade_obrigatoria` no Central, ou abrir issue/TODO rastreável vinculada a esta branch antes do merge.

### 🟢 Minor (3)

#### m1 — `buscarPendentes*` aplica `LIMIT` em PHP, não na query
**Onde**: `Sondas/WmsAlocacaoSonda.php:181-209` (`array_slice($rows, 0, $limite)`)
**Problema**: Busca todas as linhas pendentes/falha e corta em PHP. O índice parcial `idx_wms_alocacoes_integ_*` existe justamente para varredura eficiente; trazer tudo pra memória e fatiar derrota o propósito sob volume.
**Como corrigir**: Aplicar limite no `find()`/`order()` (ex.: `->limit($limite)` se a API da Sonda suportar) para que o LIMIT chegue ao Postgres.

#### m2 — `WmsLocalizacaoSonda` declara `$required = ['codigo']`
**Onde**: `Sondas/WmsLocalizacaoSonda.php:45`
**Problema**: Pela memória `modelinteligencia_save_gotchas`, `$required` populado pode quebrar `create()`. A Sonda é read-only (sem inserts), então é inofensivo hoje — mas é inconsistente com `WmsAlocacaoSonda.php:50` que deixa `$required = []` justamente por esse motivo.
**Como corrigir**: Zerar `$required` por consistência, já que a tabela é só consultada.

#### m3 — Comentário enganoso em `MissoesBipagem::alocarLocalizacao`
**Onde**: `MissoesBipagem.php:835-837`
**Problema**: O docblock diz "aciona `MissoesStatus::iniciarMissao` ... ciclo (pendente → em_andamento → parcial → concluída) (AC6.1/6.2/6.3)", mas o código só inicia (AC6.1). Ver M1.
**Como corrigir**: Alinhar o comentário ao comportamento real após decidir M1.

### ⚪ Nit (2)

#### n1 — 45 cores hex hardcoded em `item.php`
**Onde**: `App/html/alocacaowms/item.php` (`#4f46e5`, `#a5b4fc`, `#e2e8f0`, `#f87171`, ...)
**Problema**: Cores cravadas em vez de `var(--bg-*)`/tokens de tema. Vários trechos já usam `var(--app-texto-opaco, #...)` com fallback (bom), mas a paleta indigo está cravada.
**Como corrigir**: Migrar para variáveis de tema do app onde existirem.

#### n2 — `Migration 003` insere `id=14` mas o nome do arquivo/cabeçalho ainda diz "id=14" corrigido sobre o original id=13
**Onde**: `Migrations/003_seed_tipo_missao_alocacao_wms.sql:1-22` + `TipoMissao.php:56,94`
**Problema**: Já corrigido (id=14, `codigo`, sem `ativo`, enum sincronizado) — apenas registro de que `02-techplan.md` ainda fala em "id 13" em vários pontos, divergindo do código final (id 14). Atualizar o techplan para evitar confusão de quem lê depois.

## Pontos fortes
- **Zero raw SQL** em todo o código novo — escritas via `create()`/`update()` e leituras via `find()` do `ModelInteligencia` (atende `feedback_no_raw_sql`).
- **Padrão V2 limpo**: imitou `SugestoesCodigoBarras`/`InventarioHandler`, não o legado `Designacoes/Pessoas` (atende `feedback_referencias_v2`). Dispatcher fino, Validator e Laboratório separados, Enums backed em `Enums/`.
- **`block_*` sem `DEFAULT`** nas duas migrations (atende `feedback_block_columns`), com comentário explicando que o framework popula via `customerControl`.
- **Sondas com `propeties.db` definido** (`gx_goldie`) e `customerControl` consciente/justificado por tabela.
- **Controller nomeado corretamente** (`AlocacaoWms/AlocacaoWms.php` = nome do diretório, atende `feedback_controller_naming`); registros idiomáticos nas factories (uma chave em cada mapa, sem `if/else` no core).
- **Validator centraliza as regras** (AC4.1–4.4 + quantidade); nenhuma validação inline no Handler/Satélite. `MissoesBipagem::alocarLocalizacao` delega 100% ao Laboratório (sem lógica de domínio no Satélite).
- **Decisão correta de NÃO introduzir Registry/Adapter** (um único consumidor) — evitou over-engineering, alinhado ao techplan.
- **Dois Hooks ERP/WMS independentes** com estados de integração separados e `integracao_erro` persistido (AC5.2/5.3) — desenho certo, ressalva só no runner (B1).
- **Cobertura de teste boa** onde aplicável (Enums, Sondas, Validator, Laboratório, fluxo 1:N) com `TddTest.php` espelhando a árvore; os 3 bugs detectados nos testes foram efetivamente corrigidos no código commitado.

## Recomendação

⚠️ **Voltar pro dev** — 2 blockers em aberto (B1 worker sem contexto de tenant; B2 view inexistente). Após resolvê-los, os Majors M2 (descontaminar escopo) e M3 (i18n) devem ser tratados; M1 e M4 podem entrar com TODO rastreável **se** o desvio for documentado em `03-backend.md`. A arquitetura está correta — não é caso de repensar techplan.
