# PRD — Central Logística: Sincronização de Estado via WebSocket

## Contexto

O módulo **Central Logística** (`sinais/Central`) gerencia a criação e distribuição de romaneios de entrega. Múltiplos usuários podem estar conectados simultaneamente (gestores, supervisores em telas diferentes) e o estado das rotas é mantido localmente no frontend via `rotasGeradas` (textarea oculto) + `rotasState` (in-memory).

A infraestrutura de WebSocket via Scaledrone (`galaxia_logistica_central`) já existe e está funcional após as correções recentes. O canal recebe eventos `route_update` do backend e os processa via `CentralSocketHandler.handleRouteUpdate()` em `maps.js`.

Porém, o handler atual sincroniza apenas campos de status operacional (separado, carregado, faturamento, nomes). Há lacunas que causam divergência de estado entre usuários e, em alguns casos, sobrescrita silenciosa de dados já persistidos no banco.

---

## Problemas

### P1 — `confirmado` não flui via socket (Alto risco)

**Situação atual:** quando o backend confirma uma rota (via EdicaoRota, aprovação de liberação, ou outro usuário), o campo `confirmado` não é incluído no payload do `route_update`. `handleRouteUpdate()` também não o processa mesmo que chegue.

**Estrago:** na próxima `forceSave()` do usuário local, a rota é reenviada com `confirmado=0`, sobrescrevendo a confirmação no banco.

---

### P2 — Rota excluída não notifica outros usuários (Alto risco)

**Situação atual:** `excluirRotaVazia()` apaga o romaneio no DB mas não emite nenhum evento socket. Outros usuários conectados ao Central continuam com a rota em `rotasGeradas`.

**Estrago:** quando esses usuários salvam, `criarRota()` pode recriar um romaneio para uma rota que foi intencionalmente removida, ou falhar com erro ao tentar vincular pedidos que já foram realocados.

---

### P3 — Flag `alterada` não é resetada após save confirmado (Médio risco)

**Situação atual:** depois que `broadcastRouteUpdates()` confirma que as rotas foram salvas, `handleRouteUpdate()` não remove a flag `alterada` das rotas recém-persistidas. O estado local mantém `alterada: true`.

**Consequência:** a rota aparece com o ícone de "editada" no painel de resumo e será reenviada no próximo `forceSave()` desnecessariamente, causando chamadas redundantes ao banco.

---

### P4 — Marcadores do mapa não atualizam para outros usuários (Médio risco)

**Situação atual:** `alterarImagemDosMarkers()` é chamada via `chamarFuncoes` apenas para o usuário que submeteu a ação. Outros usuários conectados ao mesmo Central veem os ícones de marcadores desatualizados (cor/estado da rota antiga) até recarregarem a página.

**Consequência:** operador vê pedido como "disponível" no mapa quando já foi alocado a uma rota por outro usuário.

---

### P5 — `romaneio_id` não retornava ao frontend após `salvarRotas()` (Resolvido)

Corrigido nesta sprint: `criarRota()` agora retorna `romaneio_id`; `salvarRotas()` escreve de volta em `$rota['romaneios']`; `normalizarDadosRota()` inclui o campo no payload; `handleRouteUpdate()` processa o campo.

---

## Objetivo

Completar a sincronização de estado via socket no Central para que **nenhum usuário conectado precise recarregar a página** para ver o estado atual das rotas, e para que **`forceSave()` nunca sobrescreva dados já persistidos por outro usuário**.

---

## Usuários Afetados

- Gestores logísticos usando o Central em múltiplas abas ou máquinas simultaneamente
- Supervisores que abrem o Central enquanto um gestor já está operando
- Qualquer fluxo que dispara `liberacao`, `edicaorota` ou `separação` enquanto o Central está aberto

---

## User Stories

**US1 — Confirmação protegida**
> Como gestor, quando outro usuário confirma uma rota via EdicaoRota, quero que meu Central atualize automaticamente o estado dessa rota para `confirmado=1`, para que meu próximo salvamento não desfaça a confirmação.

**US2 — Rota excluída some da tela**
> Como gestor, quando uma rota vazia é excluída pelo sistema (ou por outro usuário), quero que ela desapareça do meu painel de resumo sem precisar recarregar a página.

**US3 — Ícone de pendente some após salvar**
> Como gestor, depois de salvar rotas com sucesso, quero que o ícone de "editada" (lápis amarelo) desapareça das rotas que foram persistidas, para que eu saiba o que ainda precisa ser salvo.

**US4 — Mapa reflete estado atual**
> Como gestor, quando outro usuário aloca pedidos a uma rota, quero que os marcadores no mapa mudem de cor/ícone automaticamente, para evitar alocar o mesmo pedido duas vezes.

---

## Acceptance Criteria

### AC para US1 (P1 — confirmado)
- [ ] `normalizarDadosRota()` inclui `'confirmado'` no payload do socket
- [ ] `handleRouteUpdate()` processa `r.confirmado` e atualiza `rota.confirmado` no `rotasGeradas`
- [ ] `updateRotasSummaryTable()` é chamado após a atualização, refletindo o novo estado visualmente
- [ ] `forceSave()` não envia rotas com `confirmado=1` recebido via socket (ou o backend ignora re-confirmações idempotentes)

### AC para US2 (P2 — route_delete)
- [ ] `excluirRotaVazia()` emite evento socket `{ action: 'route_delete', data: { rota_id } }` para `galaxia_logistica_central`
- [ ] `CentralSocketHandler` processa `action === 'route_delete'` e remove a rota de `rotasGeradas` + `rotasState`
- [ ] O painel de resumo e os marcadores do mapa são atualizados após a remoção

### AC para US3 (P3 — reset alterada)
- [ ] Quando `handleRouteUpdate()` recebe um `route_update` com `romaneios` preenchido (indicando que a rota foi salva), remove a flag `alterada` da rota correspondente em `rotasGeradas`
- [ ] O ícone de lápis some do painel de resumo para essas rotas

### AC para US4 (P4 — markers)
- [ ] Após `handleRouteUpdate()` processar atualizações, `alterarImagemDosMarkers()` é chamada com a lista de pedidos das rotas afetadas
- [ ] Pedidos alocados a uma rota mudam de ícone/cor no mapa para todos os usuários conectados

---

## Fora de Escopo

- Sincronização do Board Logístico (tem infraestrutura própria)
- Sincronização do App Mobile (canal `galaxia_logistica_missao_*` separado)
- Resolução de conflito quando dois usuários editam a mesma rota simultaneamente (sem lock otimista por ora)
- Notificação de novo usuário conectando ao Central (presença)

---

## Dependências Técnicas

| Componente | Arquivo | Papel |
|---|---|---|
| `LogisticaSocketTrait::normalizarDadosRota()` | `Constelacoes/Logistica/Traits/LogisticaSocketTrait.php` | Payload do socket — adicionar `confirmado` |
| `Central::excluirRotaVazia()` | `Constelacoes/Logistica/Central/Satelites/Central.php` | Emitir `route_delete` |
| `CentralSocketHandler` | `controladores/_Src/maps.js` (topo do arquivo) | Processar `route_delete` + `confirmado` + reset `alterada` + chamar markers |
| `alterarImagemDosMarkers()` | `controladores/_Src/maps.js` | Já existe; precisa ser invocada pós-socket |

---

## Notas Técnicas

- `alterarImagemDosMarkers()` é `async` e recebe uma lista de markers; chamar com todos os pedidos das rotas atualizadas, não só uma rota por vez.
- Para US1, a proteção mais segura fica no **backend**: em `criarRota()`, se a rota já tem `confirmado=1` no banco, não sobrescrever (guard idempotente). Assim o frontend ser leniente não gera estrago.
- `route_delete` deve ser emitido **depois** que o banco confirma a exclusão, não antes.
- O campo `alterada` em `rotasGeradas` só deve ser removido quando `romaneios` chegar preenchido no socket (prova de persistência), não em qualquer `route_update`.
