# Implementação backend — Dashboard Operacional

## Sondagem do schema real (Tarefa #0)

Banco: `dev_gx_goldie` em `147.93.9.197` (postgres).

### tipos_missao_logistica — mapeamento confirmado

| id | codigo             | descricao |
|----|--------------------|-----------|
| 2  | SEPARACAO          | Separação — Picking de produtos para pedidos |
| 3  | CARREGAMENTO       | Carregamento — Carregamento de produtos em veículos |

As Sondas existentes usam `tipo_missao_id = 2` (SEPARACAO) e `tipo_missao_id = 3` (CARREGAMENTO) — confirmado correto.

### erros_motorista — EXISTE (Risco 1 resolvido)

A tabela **já existe** em produção com exatamente o schema previsto na migration:
- Colunas: `id, missao_logistica_id, conferente_usuario_id, motorista_usuario_id, tipo VARCHAR(40), descricao, pedido_id, romaneio_id, block_empresa_id, block_filial_id, block_usuario_id, data_cadastro, data_atualizacao, usuario_cadastro, usuario_atualizacao`
- Índices já criados: `idx_erros_motorista_missao`, `idx_erros_motorista_conferente_data`, `idx_erros_motorista_tipo_data`, `idx_erros_motorista_empresa`
- FK existente: `erros_motorista_missao_logistica_id_fkey → missao_logistica(id) ON DELETE CASCADE`

**Consequência**: migration `2026_05_05_create_erros_motorista.sql` NÃO deve ser executada (tabela já existe com índices). A migration de índices `2026_05_05_add_dashboard_operacional_indexes.sql` usa `IF NOT EXISTS` — seguro aplicar.

**`ErrosMotoristaSonda` foi criada** (sem condicionamento), pois a tabela existe. O campo `disponivel: false` listado como fallback no plano não é mais necessário — `disponivel: true` sempre.

### missao_logistica_itens — campos relevantes confirmados

- `solicitou_recomeco` (integer, default 0) — campo para `RetrabalhoLaboratorio`
- `conferido` (boolean, default false) — usado em `ErrosSeparacaoLaboratorio::classificarTipo()`
- `quantidade_bipada`, `quantidade_esperada` — numeric(15,4) — campos para divergência
- `concluido_por`, `concluido_em`, `iniciado_em` — para tempo médio e rankings

### missao_logistica_usuarios — confirmado

- Coluna `papel` VARCHAR(30) default `'OPERADOR'` — `RankingSeparadoresLaboratorio` filtra por `papel = 'LIDER'`
- Coluna `andar_designado` VARCHAR(1) — ignorada nesta feature

### Classificação de erros de separação (Risco 2 resolvido)

Regra implementada em `ErrosSeparacaoLaboratorio::classificarTipo()`:
- `bipada < esperada` → `'falta'` (inclui `bipada = 0`)
- `bipada > esperada` → `'sobra'`
- `bipada == esperada AND conferido = false` → `'trocado'` (produto errado, quantidade certa)

---

## Arquivos criados

### Laboratórios (novos)

- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Laboratorios/KpisLaboratorio.php` — agrega 6 KPIs + sparklines; consome `MissaoLogisticaSonda` e `MissaoLogisticaItemSonda`
- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Laboratorios/FluxoLaboratorio.php` — série diária/semanal de fluxo + overnight agrupado por data
- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Laboratorios/RankingSeparadoresLaboratorio.php` — ranking paginado de separadores com score, assertividade, tempo médio; JOIN ad-hoc com `missao_logistica_usuarios`
- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Laboratorios/RankingConferentesLaboratorio.php` — ranking paginado de conferentes; cruza com `erros_motorista` via subquery
- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Laboratorios/ErrosSeparacaoLaboratorio.php` — classifica e agrega erros trocado/falta/sobra; breakdown paginado por pessoa
- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Laboratorios/ErrosCarregamentoLaboratorio.php` — agrega 4 tipos de erro via `ErrosMotoristaSonda`; breakdown paginado por conferente
- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Laboratorios/RetrabalhoLaboratorio.php` — índice de retrabalho + série diária/semanal via `solicitou_recomeco`
- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Laboratorios/ComparativoMensalLaboratorio.php` — comparativo MoM genérico para separação e carregamento

### Sondas (nova)

- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Sondas/ErrosMotoristaSonda.php` — Sonda V2 fina para tabela `erros_motorista`; métodos: `contarPorTipo`, `agruparPorConferente`, `listarPorJanela`; `customerControl: true`, `db: gx_goldie`

### Handlers (novos — 14 no total + TiposMissaoHandler reescrito)

- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/KpisHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/FluxoDiarioHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/OvernightSerieHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/RankingSeparadoresHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/RankingConferentesHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/ErrosSeparacaoHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/ErrosSeparacaoComparativoHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/ErrosSeparacaoPorPessoaHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/ErrosCarregamentoHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/ErrosCarregamentoComparativoHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/ErrosPorConferenteHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/TempoMedioItemHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/TempoMedioCarregamentoHandler.php`
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/RetrabalhoHandler.php`

---

## Arquivos alterados

- `/home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Dashboard/Dashboard.php` — `renderShell()` refatorado: removidas 10 chamadas ao `DashboardLaboratorio`; agora passa apenas `boot.from`, `boot.to`, `boot.tab` à view (AC8.5 — sem Lab no boot)
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Routes.php` — 11 rotas obsoletas removidas; 15 rotas novas adicionadas (14 + tipos-missao mantido)
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Api.php` — 11 métodos podados; 15 métodos novos adicionados; imports atualizados
- `/home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Dashboard/TiposMissaoHandler.php` — reescrito: saiu da dependência do `DashboardLaboratorio` legado; agora consulta `tipos_missao_logistica` diretamente via `MissaoLogisticaSonda::conn()`

---

## Arquivos deletados

### Sondas movidas para Laboratórios

- `Sondas/KpisSonda.php` — conteúdo migrado para `KpisLaboratorio.php`
- `Sondas/FluxoDiarioSonda.php` — conteúdo migrado para `FluxoLaboratorio.php`

### Laboratório legado

- `Laboratorios/DashboardLaboratorio.php` — substituído pelos 8 Labs temáticos

### Handlers podados (sem rota ativa)

- `Handlers/Dashboard/AcaoMissaoHandler.php`
- `Handlers/Dashboard/AlertasHandler.php`
- `Handlers/Dashboard/DesempenhoHandler.php`
- `Handlers/Dashboard/DetalhesMissaoHandler.php`
- `Handlers/Dashboard/ExtratoHandler.php`
- `Handlers/Dashboard/FiltrarHandler.php`
- `Handlers/Dashboard/ListarMissoesHandler.php`
- `Handlers/Dashboard/ResumoOperacionalHandler.php`
- `Handlers/Dashboard/RotasDoDiaHandler.php`
- `Handlers/Dashboard/VeiculosStatusHandler.php`
- `Handlers/Dashboard/VisaoGeralDiaHandler.php`

### Validators obsoletos

- `Validators/AcaoMissaoValidator.php`
- `Validators/DetalhesMissaoValidator.php`
- `Validators/FiltroDashboardValidator.php`

---

## Desvios do techplan

1. **`erros_motorista` já existe** — o techplan a tratava como "condicional se tabela inexistente" (Risco 1). A sondagem confirmou que a tabela existe com o schema exato previsto e índices já criados. `ErrosMotoristaSonda` foi criada sem condicionamento; a migration `2026_05_05_create_erros_motorista.sql` NÃO deve ser executada.

2. **`TiposMissaoHandler` reescrito** — o handler existente dependia do `DashboardLaboratorio` legado (que foi removido). Foi reescrito para chamar `tipos_missao_logistica` diretamente via `MissaoLogisticaSonda::conn()`. Desvio justificado pela remoção do Lab legado.

3. **Testes legados não removidos** — os arquivos em `Testes/Handlers/` (AcaoMissaoHandlerTddTest, FiltrarHandlerTddTest, DetalhesMissaoHandlerTddTest) e `Testes/Laboratorios/DashboardLaboratorioB2TddTest.php` ainda existem em disco. Eles referenciam classes deletadas, então falharão se executados. Remoção fica para o Tester (fora do escopo do Dev Backend).

4. **`DashboardLaboratorio.php` removido imediatamente** — o techplan dizia "substituído pelos Labs temáticos". Feito. Os testes legados que dependem dele são efeito colateral do item 3.

---

## Comandos de verificação executados

Todos os arquivos PHP novos e alterados passaram em `php -l`:

- `php -l Laboratorios/KpisLaboratorio.php` → OK
- `php -l Laboratorios/FluxoLaboratorio.php` → OK
- `php -l Laboratorios/RankingSeparadoresLaboratorio.php` → OK
- `php -l Laboratorios/RankingConferentesLaboratorio.php` → OK
- `php -l Laboratorios/ErrosSeparacaoLaboratorio.php` → OK
- `php -l Laboratorios/ErrosCarregamentoLaboratorio.php` → OK
- `php -l Laboratorios/RetrabalhoLaboratorio.php` → OK
- `php -l Laboratorios/ComparativoMensalLaboratorio.php` → OK
- `php -l Sondas/ErrosMotoristaSonda.php` → OK
- `php -l Dashboard.php` → OK
- `php -l Api/Api.php` → OK
- `php -l Api/Routes.php` → OK
- Todos os 15 Handlers/Dashboard/*.php → OK

---

## Próximos passos para o frontend

### Endpoints disponíveis

Base: `GET /api/v1/dashboard/<rota>` — autenticação via sessão Galaxia same-origin.

| Endpoint | Parâmetros obrigatórios | Parâmetros opcionais | Resposta `data` |
|----------|------------------------|---------------------|-----------------|
| `/dashboard/tipos-missao` | — | — | `[{id, codigo, descricao}]` |
| `/dashboard/kpis` | `from`, `to` | — | `{separacoes, carregamentos, itens_separados, cubagem_total, eficiencia_fluxo_pct, overnight, sparklines}` |
| `/dashboard/fluxo-diario` | `from`, `to` | — | `[{data, separacoes, carregamentos, overnight}]` |
| `/dashboard/overnight-serie` | `from`, `to` | — | `{serie: [{data, total}], total}` |
| `/dashboard/ranking-separadores` | `from`, `to` | `page` (default 1), `perPage` (default 20, max 100) | `{total, page, perPage, tempo_ref_seg, itens: [{usuario_id, rotas, itens, cubagem, tempo_seg_medio, vezes_lider, assertividade_pct, score, semaforo_score, semaforo_assert}]}` |
| `/dashboard/ranking-conferentes` | `from`, `to` | `page`, `perPage` | `{total, page, perPage, itens: [{usuario_id, cargas, erros, retrabalhos, retrabalho_pct, tempo_seg_medio, score, semaforo_score, semaforo_retrab}]}` |
| `/dashboard/erros-separacao` | `from`, `to` | — | `{total, trocado, falta, sobra, por_tipo: [{tipo, total}]}` |
| `/dashboard/erros-separacao/comparativo` | `from`, `to` | `mesesAtras` (default 1, max 12) | `{periodo_atual, periodo_anterior, variacao: {total_atual, total_anterior, diff_abs, diff_pct, tendencia}}` |
| `/dashboard/erros-separacao/por-pessoa` | `from`, `to` | `page`, `perPage` | `{total, page, perPage, itens: [{usuario_id, total, trocado, falta, sobra}]}` |
| `/dashboard/erros-carregamento` | `from`, `to` | — | `{disponivel: true, total, por_tipo: {ITEM_FALTANDO, ITEM_TROCADO, AVARIA_TRANSPORTE, ENDERECO_ERRADO}}` |
| `/dashboard/erros-carregamento/comparativo` | `from`, `to` | `mesesAtras` | `{periodo_atual, periodo_anterior, variacao}` |
| `/dashboard/erros-por-conferente` | `from`, `to` | `page`, `perPage` | `{total, page, perPage, itens: [{usuario_id, total, por_tipo}]}` |
| `/dashboard/tempo-medio-item` | `from`, `to` | — | `{tempo_seg_medio, total_itens}` |
| `/dashboard/tempo-medio-carregamento` | `from`, `to` | — | `{tempo_seg_medio, total_cargas}` |
| `/dashboard/retrabalho` | `from`, `to` | — | `{total_itens, itens_retrabalho, indice_pct, semaforo, serie: [{data, total_itens, itens_retrabalho, indice_pct}]}` |

### Envelope padrão

Sucesso:
```json
{ "data": <payload acima>, "request_id": "uuid" }
```

Erro de validação (422):
```json
{ "error": { "code": "invalid_input", "message": "..." }, "request_id": "uuid" }
```

### Boot do Dashboard.php

O controller PHP injeta na view `$dados['boot']`:
```json
{ "from": "YYYY-MM-DD", "to": "YYYY-MM-DD", "tab": "visao-geral|separacao|carregamento" }
```
O JS deve ler `DashboardBoot` (ou equivalente) para inicializar o filtro sem recarregar a página.

### Semáforos (CSS classes)

- `success` / `warning` / `danger` — aplicar conforme resposta dos campos `semaforo_*`

### Paginação de rankings

Campos `total`, `page`, `perPage` no envelope `data` permitem calcular número de páginas: `Math.ceil(total / perPage)`. Passar `page` e `perPage` na querystring.

### Fluxo agregado por semana

Quando `to - from > 60 dias`, as séries retornam pontos semanais (truncate para início da semana ISO). O campo `data` nesses casos é a segunda-feira da semana. O frontend deve detectar isso e usar label de semana no eixo X.

### Execução de testes de integração

Rodam apenas em `dev_gx_goldie` (banco remoto):

```bash
# A partir do diretório genesis/
php componentes/Missoes/Logistica/sinais/Dashboard/Testes/Integracao/KpisIntegrationTest.php
php componentes/Missoes/Logistica/sinais/Dashboard/Testes/Integracao/FluxoDiarioIntegrationTest.php
php componentes/Missoes/Logistica/sinais/Dashboard/Testes/Integracao/RankingSeparadoresIntegrationTest.php
php componentes/Missoes/Logistica/sinais/Dashboard/Testes/Integracao/ErrosCarregamentoIntegrationTest.php
```

Os testes de integração listados acima ainda precisam ser criados pelo Tester (não existem em disco — apenas os testes legados da feature anterior).
