# Integração WMS desacoplada (WMS-driven, bidirecional) — PRD bruto

> Ponto de entrada do pipeline `/genesis-feature`.
> Introduz a camada de integração desacoplada para plugar um WMS completo e
> externo, que passa a comandar o Genesis (entrada) e a receber resultados
> (saída), sem quebrar os fluxos nativos do Genesis (pedidos/romaneios) nem o push
> legado atual (strangler-fig).

## Problema / dor

Hoje o Genesis é o "cérebro" da operação logística: ele cria as missões
(separação, conferência, etc.) a partir de pedidos/romaneios, os operadores
executam, e o Genesis **empurra** o registro pra fora (ERP/WMS legado). Essa
integração de saída é **soldada a um único sistema** (`galpaodasembalagens`): URL e
token chumbados no código, sem abstração de provedor, sem config por empresa, e
**só de saída** — nada do WMS entra no Genesis.

Vamos plugar um **WMS completo e externo** que é a **fonte da verdade** do estoque
e que vai, em vários momentos, **comandar o Genesis** — dizer o que separar, o que
movimentar, o que guardar (recebimento) e o que inventariar. O Genesis passa a ser
a **camada de execução** (app do operador + bipagem) que recebe ordens do WMS e
devolve o resultado.

Pra isso funcionar de forma **isolada e desacoplada** (trocar de WMS sem reescrever
o core, ligar/desligar por empresa, não derrubar quem não usa WMS), falta a
estrutura: não existe abstração de provedor de WMS, não existe config de integração
por tenant, e **não existe caminho de entrada** (receiver/webhook) — o `/api/v1` de
hoje é interno do frontend e gateado por allowlist de devs.

## Quem usa

- **WMS externo (sistema)**: fonte da verdade; emite ordens (separação,
  movimentação, alocação/recebimento, inventário) via **webhook** para o Genesis e
  consome de volta os resultados/baixas.
- **Operador (separador/conferente)**: executa no app de missões de hoje as
  tarefas — agora também as originadas pelo WMS — sem mudança de UX.
- **Gestor / TI da empresa**: configura por empresa qual WMS está plugado
  (endpoint, credenciais, liga/desliga, sentido), sem deploy.
- **Time Genesis**: mantém o core agnóstico ao WMS específico; adiciona/troca
  provedor sem editar o núcleo.

## O que precisa fazer (alto nível)

**Saída (Genesis → WMS), tornando plugável o que já existe:**
- Abstrair o provedor de WMS atrás de uma interface + registry (mover o push do
  galpão pra um provedor registrado, virando "mais um" provedor — não o único).
- Tirar endpoint/token do código e levar pra config por empresa (e/ou env), com
  liga/desliga.
- Reportar ao WMS o resultado da execução (baixas/movimentos/acks), reusando o
  pipeline assíncrono de hoje (`wms_movimentos` + estados de integração + cron).

**Entrada (WMS → Genesis), o que é novo:**
- Expor um **receiver de webhook autenticado por empresa** (superfície externa
  nova, separada do `/api/v1` interno) que recebe ordens do WMS.
- Traduzir a ordem do WMS numa **missão do Genesis** do tipo certo (separação /
  movimentação / alocação / inventário), criando `missao_logistica` + itens —
  reusando os domínios que já existem (`OperacaoTipo` + `MissaoLogistica`).
- Mapear identidades WMS↔Genesis (produto via `importacao_id`/`codigomd5`,
  endereço via `wms_localizacoes.codigo`).
- Idempotência: dedup por referência externa da ordem (o WMS pode reenviar).
- Ciclo fechado: ordem recebida → executada pelo operador → resultado devolvido ao
  WMS.

**Coexistência (regra dura):**
- Missões nativas do Genesis (pedidos/romaneios) continuam funcionando intactas.
- Missões originadas pelo WMS são uma **nova origem**, marcada como tal; as duas
  convivem.
- Tudo é **opt-in por empresa**: quem não plugou WMS não vê diferença.

## O que NÃO precisa fazer (escopo negativo)

- **Não** reescrever o app do operador / a bipagem — a execução é a de hoje; muda
  só a *origem* da missão e o *report* de volta.
- **Não** apagar/migrar de imediato o push legado do galpão — ele vira um provedor
  registrado e segue funcionando (strangler-fig).
- **Não** transformar o Genesis num WMS (o WMS externo é a fonte da verdade do
  estoque) — o Genesis é execução, não gestão de estoque.
- **Não** abrir o `/api/v1` interno pro WMS — o receiver de entrada é uma
  superfície externa própria, com auth própria por empresa.
- **Não** definir aqui o schema final do contrato nem o mecanismo exato de auth —
  isso é refino (PO / Tech Lead).

## Restrições conhecidas

- **Reusar o padrão canônico de provedor plugável**: Registry + Interface (+
  `Adapters/<Domínio>/`), igual ao OTP (`OtpCanalRegistry`/`OtpCanalInterface` +
  `Canais/<Provedor>/`) e ao Edicaorota (`EdicaoRotaCallbackRegistry` +
  `Adapters/Romaneio/`). Já existe inclusive um registry de provedor no contexto
  WMS: `Inventariociclico/Esperado/EsperadoProviderRegistry`.
- **Hoje a saída está soldada**: URL chumbada em `ErpAlocacaoWmsHookStrategy.php:28`
  e `WmsAlocacaoWmsHookStrategy.php:28`; token `'gnesistk'` em
  `HookSincronizadorBase.php:15`; instanciação direta no cron
  `crons/wms_alocacao_integracao.php:117-118`. A refatoração para provedor não pode
  regredir esse fluxo.
- **Config por empresa**: seguir o precedente — Sonda por `block_empresa_id`
  (`ScanCotaConfigSonda`) e/ou Config por env com gate `configurado()`
  (`EvolutionConfig`), registrada no bootstrap multi-camada (`Api/Bootstrap.php`).
- **Superfície de entrada nova = segurança nova**: o webhook do WMS precisa de auth
  por empresa (token/HMAC), idempotência (dedup por id externo), proteção a replay
  e versionamento de contrato. O `/api/v1` é interno (frontend), gateado por
  allowlist de devs — não serve para isso.
- **Mapeamento de identidade**: produto Genesis ↔ WMS via `importacao_id` (=
  `codigomd5` do ERP legado); endereço via `wms_localizacoes.codigo`. Já há
  divergência de namespace de endereço (legado `codigo_enderecamento` vs
  `wms_localizacoes`).
- **Armadilha multi-tenant**: `wms_movimentos` usa `customerControl=true` (block) e
  `missao_logistica`/itens usam `block_empresa_id` (`customerControl=false`);
  cruzar exige resolver o mesmo tenant (o cron faz via sessão sintética). Erro
  silencioso de escopo.
- **Mudança de fonte da verdade**: com o WMS dono do estoque, os fluxos locais que
  hoje calculam "saldo local" (alocação) podem precisar deferir ao WMS — definir
  precedência/conflito.
- **Reusar a infra assíncrona existente** pro report de saída: `wms_movimentos` +
  `EstadoIntegracao` (`integracao_erp`/`integracao_wms`) + cron com retry
  idempotente e estados independentes.

## Inspirações / referências (com o que já existe no código)

- Provedor plugável (gold standard):
  `componentes/Missoes/Mensageria/sinais/Otp/Canais/{OtpCanalRegistry,OtpCanalInterface}.php`
  + `Canais/Whatsapp/Evolution.php`, `Canais/Email/Smtp.php`, fallback `LogCanal.php`.
- Callbacks + Adapters de domínio:
  `componentes/Missoes/Logistica/sinais/Edicaorota/Callbacks/{EdicaoRotaCallbackRegistry,EdicaoRotaCallbackInterface}.php`
  + `Adapters/Romaneio/`.
- Registry de provedor já no contexto WMS:
  `componentes/Missoes/Logistica/sinais/Inventariociclico/Esperado/EsperadoProviderRegistry.php`
  (e `Selecao/SelecaoEstrategiaRegistry.php`).
- Bootstrap multi-camada + gate `configurado()`:
  `componentes/Missoes/Plataforma/sinais/Api/Bootstrap.php`,
  `Otp/Canais/Whatsapp/EvolutionConfig.php`.
- Saída atual a desacoplar:
  `componentes/Constelacoes/Logistica/MissaoLogistica/Strategies/{ErpAlocacaoWmsHookStrategy,WmsAlocacaoWmsHookStrategy,HookSincronizadorBase}.php`,
  `crons/wms_alocacao_integracao.php`.
- Operações + payload por tipo (reuso na tradução de ordens):
  `componentes/Missoes/Logistica/sinais/AlocacaoWms/Strategies/Operacao/{OperacaoAdapterInterface,OperacaoAdapterFactory}.php`,
  `Enums/OperacaoTipo.php`.
- Modelo de missão a criar a partir de ordens:
  `componentes/Constelacoes/Logistica/MissaoLogistica/` (Satelites de
  persistência/status), `Enums/TipoMissao`.
- Config por tenant:
  `componentes/Constelacoes/Logistica/MissaoLogistica/Sondas/ScanCotaConfigSonda.php`.
- Superfície de API e auth: skill `genesis-api-handler`; memória `project_api_interna`
  (/api/v1 interno + allowlist de devs).

## Defaults / decisões já tomadas (com o usuário)

- **WMS é completo e fonte da verdade**, e vai **comandar o Genesis** (entrada)
  além de receber resultado (saída) — contrato **bidirecional**.
- **Tipos de ordem do WMS (entrada)**: separação/picking, movimentação interna,
  alocação/recebimento e inventário/contagem (os quatro).
- **Transporte da entrada**: **webhook** (o WMS chama o Genesis numa rota nova
  autenticada).
- **Genesis = camada de execução**; mantém os fluxos nativos (pedidos/romaneios)
  coexistindo com as ordens do WMS.
- **Opt-in por empresa**; o push legado do galpão vira um provedor registrado e não
  regride (strangler-fig).
- **Reuso do padrão Registry+Interface(+Adapters)** já consolidado no repo.

## Pontos em aberto para o PO / Tech Lead

- **Auth do webhook**: token estático por empresa, HMAC assinado, mTLS? Rotação de
  credencial?
- **Schema/versão do contrato**: formato das ordens (campos por tipo),
  versionamento, envelope comum.
- **Idempotência**: chave externa da ordem (id do WMS) — onde guardar/dedup;
  reentrega e atualização de ordem (cancelar/repriorizar) entram nesta fase?
- **Mapeamento de identidade**: confirmar `importacao_id`=`codigomd5` cobre todos os
  casos; o que fazer com produto/endereço que o WMS manda e o Genesis não conhece.
- **Conflito de fonte da verdade**: quando o WMS manda algo que diverge do estado
  local (saldo, status), quem ganha? Como reconciliar?
- **Report de volta**: quais eventos o WMS espera receber (início, conclusão por
  item, baixa, divergência) e em que sentido (webhook reverso? polling?).
- **Migração do legado**: quando/como aposentar o push direto do galpão depois que
  o provedor abstrato estiver no ar.
- **Escopo de release**: faseamento (1º saída plugável → 2º receiver de entrada →
  3º por tipo de ordem) e qual ordem de operação entra primeiro.
- **Relação com `separacao-por-endereco`**: aquela feature é um consumidor desta
  camada (a ordem de separação do WMS já traz o endereço); decidir se sai junto ou
  depois.
