# Dashboard Operacional — Spec

## Contexto e problema

O dashboard atual em `/missao/logistica/dashboard` é um kanban de missões/veículos/rotas que mostra **estado em tempo real**, mas não responde às perguntas do gestor sobre **performance operacional** (quem separa melhor, onde estão os erros, qual o fluxo do dia, quanto sobra overnight). Existe um protótipo React documentado em `componentes/Missoes/Logistica/sinais/Dashboard/frontend-documentacao.md` que define a UI rica desejada: 6 KPIs com sparklines, 3 abas (Visão Geral / Separação / Carregamento), rankings ponderados, séries temporais e detalhamento de erros tipados. Esta feature **substitui** o kanban atual pela nova UI operacional, mantendo a stack Genesis (PHP + vanilla JS + chart lib client-side) e consumindo `/api/v1/dashboard/*`.

## Escopo

- ✅ Faz parte:
  - Substituir a view do sinal `Logistica/sinais/Dashboard/` (rota `/missao/logistica/dashboard`) pela nova UI operacional.
  - 6 KPIs no topo, fixos em todas as abas, com sparkline diário.
  - 3 abas client-side: Visão Geral, Separação, Carregamento.
  - Filtro de período global (DateRange `from..to`) que propaga para todas as queries.
  - Rankings de separadores e conferentes com scores ponderados, paginação e cor semafórica.
  - Detalhamento de erros tipados (separação: trocado/falta/sobra; carregamento: item_faltando/item_trocado/avaria_transporte/endereco_errado).
  - Gráficos de séries temporais (fluxo diário, overnight, retrabalho) e comparativos mensais.
  - i18n nas 3 línguas (pt-br/en/es) para todos os labels novos.
  - Persistência do período + aba selecionada na URL (querystring) ou sessão.
  - Testes de integração em `dev_gx_goldie` validando agregações contra dados reais.
  - Auditoria/poda dos 12 handlers `/api/v1/dashboard/*` da feature anterior — remover o que não couber na nova UI.
- ❌ Fora de escopo:
  - React/Vite/Tailwind/shadcn/Recharts no repo Genesis (a documentação React é apenas referência de design e fórmulas).
  - Criar um novo sinal — reusa o sinal `Logistica/sinais/Dashboard/` existente.
  - Mexer em outros sinais de Logística (Edicaorota, Board, Central, Armazem, Expedicao).
  - Abrir `/api/v1` publicamente (segue interna, JWT/sessão Galaxia).
  - Exportações CSV/PDF.
  - Autenticação/autorização nova (herda de `/api/v1`).
  - Alterar schema do banco (dados existem; só Sondas/agregações novas).
  - Mock determinístico (PRNG) — só existia no protótipo React.
  - Migrar/manter o kanban antigo em paralelo (substituição in-place).

## User stories

### US1 — Ver KPIs operacionais do período
**Como** gestor logístico **eu quero** ver 6 KPIs (Separações, Carregamentos, Itens Separados, Cubagem, Eficiência de Fluxo, Pendências Overnight) no topo do dashboard **para** ter leitura imediata do desempenho operacional do período escolhido.

**Critérios de aceite:**
- AC1.1: Os 6 KPIs aparecem fixos no topo em todas as 3 abas.
- AC1.2: Cada KPI exibe o valor agregado do período corrente do filtro DateRange.
- AC1.3: Cada KPI exibe um sparkline com a série diária do período (uma barra/ponto por dia útil dentro do range).
- AC1.4: Eficiência de Fluxo aplica cor semafórica: ≥95% verde, ≥85% amarelo, <85% vermelho.
- AC1.5: Pendências Overnight aplica cor semafórica: 0 verde, 1–3 amarelo, ≥4 vermelho.
- AC1.6: Demais cards aparecem com borda azul (info) neutra.
- AC1.7: Alterar o filtro de período recalcula todos os 6 KPIs e seus sparklines.

### US2 — Filtrar por período
**Como** gestor **eu quero** escolher um intervalo de datas (DateRange) **para** analisar o desempenho de qualquer janela de tempo (dia, semana, mês, trimestre, ano).

**Critérios de aceite:**
- AC2.1: O dashboard apresenta um seletor DateRange `from..to` no topo.
- AC2.2: Default ao abrir = últimos 30 dias úteis.
- AC2.3: Alterar o range dispara re-fetch coordenado de KPIs, séries e rankings exibidos.
- AC2.4: Durante o re-fetch, blocos exibem skeleton/loading visível.
- AC2.5: O range escolhido persiste ao recarregar a página (via querystring ou sessão).
- AC2.6: Range inválido (`from > to` ou intervalo > 365 dias) é rejeitado com mensagem ao usuário.

### US3 — Navegar entre abas
**Como** usuário **eu quero** alternar entre Visão Geral, Separação e Carregamento **para** focar no recorte de informação que me interessa.

**Critérios de aceite:**
- AC3.1: Existem 3 abas client-side: Visão Geral, Separação, Carregamento.
- AC3.2: Trocar de aba não recarrega a página inteira; só os blocos da aba ativa são montados/atualizados.
- AC3.3: A aba selecionada persiste ao recarregar (querystring ou sessão).
- AC3.4: Os 6 KPIs do topo permanecem visíveis em todas as abas.
- AC3.5: O filtro de período permanece visível e ativo em todas as abas.

### US4 — Acompanhar fluxo macro (Visão Geral)
**Como** gestor **eu quero** ver o fluxo diário de Separações vs Carregamentos e a série de Pendências Overnight **para** identificar gargalos no encadeamento separação→carregamento.

**Critérios de aceite:**
- AC4.1: A aba Visão Geral exibe um gráfico de área/linha "Separações vs Carregamentos" com 2 séries diárias.
- AC4.2: Quando o período tem >60 pontos, a série é agregada por semana (formato `ww/yy`).
- AC4.3: A aba exibe um gráfico de barras com a série diária de Pendências Overnight.
- AC4.4: A aba exibe Top 3 Separadores e Top 3 Conferentes com badge de score colorido (≥70 verde, ≥45 amarelo, <45 vermelho).

### US5 — Avaliar separadores (Aba Separação)
**Como** coordenador de separação **eu quero** ver o ranking de separadores com assertividade, tempo, itens, cubagem e score ponderado **para** premiar/treinar com base em dado objetivo.

**Critérios de aceite:**
- AC5.1: Aba Separação exibe cards superiores: Tempo Médio (seg/item), Pie de Tipos de Erro, Itens Separados (líder), Maior Cubagem, Maior Assertividade, Menor Tempo.
- AC5.2: O card "Maior Assertividade" usa cor semafórica do valor: ≥95 verde, ≥88 amarelo, <88 vermelho.
- AC5.3: O Pie de erros separa em 3 fatias: trocado ("Separado errado"), falta ("Quantidade a Menos"), sobra ("Quantidade a Mais").
- AC5.4: A aba exibe Ranking Geral de Separadores ordenado por score desc, com paginação client-side.
- AC5.5: Cada linha do ranking mostra: posição, nome, itens, cubagem, tempo médio/item (seg), assertividade (%), rotas participadas, vezes líder, score.
- AC5.6: A cor da linha do ranking segue cor da assertividade (≥95 verde, ≥88 amarelo, <88 vermelho).
- AC5.7: O score é calculado por `0.5·assertividade + 0.3·tempo⁻¹ + 0.12·itens + 0.08·cubagem` (todos normalizados 0–100).
- AC5.8: A aba exibe "Erros de Separação por Mês" (barras), "Comparativo Mensal" (atual vs N meses atrás, com %) e "Separadores com Mais Erros" (tabela paginada com breakdown por tipo).

### US6 — Avaliar conferentes (Aba Carregamento)
**Como** coordenador de expedição **eu quero** ver o ranking de conferentes com retrabalho, assertividade e erros tipados do motorista **para** identificar quem gera devolução/reclamação.

**Critérios de aceite:**
- AC6.1: Aba Carregamento exibe cards superiores: Tempo Médio (min/carga), Índice de Retrabalho, Mais Rápido, Maior Cubagem, Maior Assertividade.
- AC6.2: O card Retrabalho usa borda vermelha (danger).
- AC6.3: A aba exibe Ranking Geral de Conferentes ordenado por score desc, paginado.
- AC6.4: Cada linha mostra: posição, nome, carregamentos, cubagem, tempo médio (min/carga), assertividade (%), retrabalhos, score.
- AC6.5: O score é calculado por `0.35·tempo⁻¹ + 0.25·cubagem + 0.40·assertividade` (todos normalizados 0–100).
- AC6.6: A aba exibe gráfico de "Índice de Retrabalho" diário e "Comparativo de Erros (Carregamento)" mensal.
- AC6.7: A aba exibe "Erros por Conferente" — lista detalhada de cargas com erros do motorista, classificadas em Item Faltando, Item Trocado, Avaria no Transporte, Endereço Errado.

### US7 — Ler em pt-br, en e es
**Como** usuário de qualquer idioma suportado pelo Genesis **eu quero** ver todos os labels traduzidos **para** usar o dashboard na minha língua.

**Critérios de aceite:**
- AC7.1: Todos os labels novos (KPIs, abas, colunas de tabela, tipos de erro, tooltips) têm chave em `linguagens/pt-br.json`, `en.json`, `es.json`.
- AC7.2: Trocar idioma no Galaxia troca os labels do dashboard sem quebrar layout.
- AC7.3: Não há string PT hardcoded no JS/PHP do sinal.

### US8 — Receber dados rapidamente
**Como** usuário **eu quero** que a página carregue rápido **para** não esperar de braços cruzados.

**Critérios de aceite:**
- AC8.1: Em `dev_gx_goldie` com período de 30 dias, cada handler de KPI/série responde em <500ms (p95, smoke).
- AC8.2: Handlers de ranking respondem em <800ms para período de 30 dias (smoke).
- AC8.3: Skeleton/loading aparece em <100ms após troca de período/aba.
- AC8.4: 100% das chamadas do `dashboard.js` passam por `fetch('/api/v1/dashboard/...')` (zero `sendToGalaxia`).
- AC8.5: Zero HTML inline no controller PHP do sinal (a view PHP é shell; conteúdo dinâmico vem do JS).

## Personas envolvidas

| Persona | Papel | Ponto de contato com a feature |
|---|---|---|
| Gestor logístico / supervisor | Decisor operacional | Abre o dashboard diariamente, observa KPIs, ajusta período, identifica gargalos |
| Coordenador de separação | Gestor de equipe de separação | Usa aba Separação para acompanhar ranking, erros e treinamento |
| Coordenador de expedição | Gestor de equipe de carregamento | Usa aba Carregamento para retrabalho e erros do motorista |
| Time de devs Genesis | Mantenedor | Implementa/mantém handlers e Sondas seguindo padrão V2 |

## Dados / entidades-chave (alto nível)

- **Pessoa** (separador / conferente / motorista) — operador identificável que executa rotas, cargas ou aparece em ocorrências.
- **RotaSeparacao** — rota de separação executada num dia, com itens, cubagem, tempo, líder e participantes.
- **ParticipacaoSeparacao** — fatia de uma rota atribuída a um separador específico (itens, cubagem, tempo/item, erros tipados).
- **Carregamento** — embarque de um conferente (tempo, retrabalho sim/não, erros do motorista atrelados).
- **ErrosMotorista** — ocorrências pós-entrega ligadas a um carregamento, classificadas por tipo.
- **DiaOperacional** — agregado lógico `{ data, rotas[], carregamentos[] }` usado pelas séries temporais.
- **Tipos de erro de separação** — enum: trocado, falta, sobra.
- **Tipos de erro de carregamento (motorista)** — enum: item_faltando, item_trocado, avaria_transporte, endereco_errado.

## Regras de negócio

1. Toda agregação respeita o filtro DateRange `from..to` (inclusivos).
2. Toda query é multi-tenant: filtra por `customerControl`/`companyControl` ativo na sessão; colunas `block_*` aplicáveis seguem padrão Genesis (sem `DEFAULT 1` na migration).
3. Eficiência de Fluxo = `(totalCarregamentos / totalSeparacoes) × 100`. Se separações = 0, o KPI exibe "—" (não divide por zero).
4. Pendências Overnight = rotas com `pendenteOvernight = true` no período + cubagem associada.
5. Assertividade do separador = `((itens − erros) / itens) × 100`. Se itens = 0, exibe "—".
6. Assertividade do conferente = `((carregamentos − cargasComErro) / carregamentos) × 100`. Se carregamentos = 0, exibe "—".
7. Tempo médio por item (separação) = `Σ(tempoPorItemSeg × itens) / Σ itens`.
8. Índice de retrabalho = `(carregamentos com retrabalho / total) × 100`.
9. Variação comparativa = `(atual − anterior) / anterior × 100`. Se anterior = 0, exibe "—" ou "novo".
10. Score do separador = `0.5·assertividade + 0.3·tempo⁻¹ + 0.12·itens + 0.08·cubagem`, todos normalizados 0–100; tempo é invertido (menor é melhor).
11. Score do conferente = `0.35·tempo⁻¹ + 0.25·cubagem + 0.40·assertividade`, normalizados 0–100.
12. Cor por score (badge de ranking): ≥70 verde, ≥45 amarelo, <45 vermelho.
13. Cor por assertividade (cards/linhas): ≥95 verde, ≥88 amarelo, <88 vermelho.
14. Cor por eficiência de fluxo: ≥95 verde, ≥85 amarelo, <85 vermelho.
15. Cor por pendências overnight: 0 verde, 1–3 amarelo, ≥4 vermelho.
16. Período > 60 dias agrega séries por semana (`ww/yy`); ≤ 60 dias agrega por dia.
17. Período máximo permitido = 365 dias.
18. Ranking não exibe pessoas sem nenhuma participação no período (zero linhas vazias).
19. Em caso de empate de score, ordena por nome asc.
20. Toda label visível ao usuário é traduzível via `linguagens/*.json`.

## Métricas de sucesso

- Substituição completa do kanban antigo: rota `/missao/logistica/dashboard` serve a nova UI sem regressão de acesso/permissão.
- 6 KPIs + 3 abas funcionando com paridade visual ao protótipo React (validação por screenshots lado-a-lado).
- p95 dos handlers de KPI/série diária <500ms para período de 30 dias em `dev_gx_goldie`.
- Adoção: ≥80% dos coordenadores de separação/expedição abrem o dashboard pelo menos 1×/semana após o lançamento (medir via log de acesso à rota).
- Zero `sendToGalaxia` no `dashboard.js`; zero HTML dinâmico inline no controller PHP.
- Testes de integração em `dev_gx_goldie` validando que cada agregação bate com SELECT cru de referência.
- Redução do tempo gasto pelo gestor para responder "quem foram os 5 melhores separadores este mês?" — antes (kanban antigo) impossível; depois <10s.

## Dúvidas em aberto

- [ ] Persistência do estado (período + aba): querystring na URL ou `sessionStorage`? PO sugere querystring (compartilhável por link), mas TL valida viabilidade dentro do roteador Genesis.
- [ ] Biblioteca de chart: Genesis já tem Chart.js ou ApexCharts em uso em outro sinal? TL sonda e decide para evitar trazer dependência nova.
- [ ] DateRange picker: Litepicker, Flatpickr ou Bootstrap datepicker já presentes no projeto? TL escolhe o que minimize footprint.
- [ ] Cache de handlers de séries diárias (5–15 min por `customer + range + tipo`): vale na rodada 1 ou fica para iteração seguinte? Decidir junto à medição de baseline.
- [ ] Lista exata dos 12 handlers da feature anterior a podar/manter — TL faz auditoria e propõe na fase de tech plan (PO antecipa que provavelmente só `TiposMissaoHandler` e metadados pontuais sobrevivem).
- [ ] Mapeamento Sondas ↔ tabelas reais (`RotaSeparacao`, `ParticipacaoSeparacao`, `Carregamento`, `ErrosMotorista`, `Pessoa`): dados confirmados como existentes pelo usuário; TL precisa sondar schema em `dev_gx_goldie` e nas Constelações para confirmar nomes de colunas e relacionamentos.
- [ ] Destino final de `frontend-documentacao.md` (hoje untracked): mover para `PRD/dashboard-operacional/`, manter no diretório do sinal como referência viva, ou remover ao final? Decidir no fechamento da feature.
- [ ] Definição de "carga com erro" para assertividade do conferente: qualquer `errosMotorista[]` não-vazio conta, ou só tipos específicos (ex.: avaria_transporte não conta porque não é culpa do conferente)? Validar com coordenador de expedição.
