# Implementação frontend — dashboard-logistica-api-v2

## Views alteradas

- `componentes/Missoes/Logistica/sinais/Dashboard/html/dashboard.js` — reescrito: todo `sendToGalaxia` removido (0 ocorrências); helpers `DashboardApi.get/post` via `fetch` same-origin; `DashboardTemplates` com funções JS para kanban card, linha de veículo, card de rota, item de alerta, item de timeline; `DashboardController` com `filtrar/executarAcaoMissao/abrirDetalhesMissao/atualizarDashboardComJson`; `DashboardToast` para feedback de erro/sucesso; skeleton de carregamento.

- `componentes/Missoes/Logistica/sinais/Dashboard/html/dashboard.php` — removidos os 3 `<div id="acao-filtrar/acao-missao/acao-detalhes">` hidden (dependência do canal `sendToGalaxia`); adicionados atributos `data-dash-alertas-lista`, `data-dash-alerta-count` e `data-dash-extrato-count` para que o JS encontre os pontos de re-render após filtrar.

## Forms

Nenhum form criado (feature é refatoração de JS, sem novos formulários).

## i18n

Chaves adicionadas em pt-br / en / es (4 chaves novas):

- `3b93b2b48e0af8cf1524c429e80efbb7` → "Erro ao carregar dados do dashboard." / "Error loading dashboard data." / "Error al cargar los datos del tablero."
- `6f1c298dd78ed0353f599cd241900f3d` → "Sessão expirada. Redirecionando..." / "Session expired. Redirecting..." / "Sesión expirada. Redirigiendo..."
- `40d3d17d43835123a14b4bbf58275baa` → "Sem permissão para realizar esta ação." / "You do not have permission to perform this action." / "No tienes permiso para realizar esta acción."
- `9c02619c2c5ac12897deb62093e61cc5` → "Missão não encontrada." / "Mission not found." / "Misión no encontrada."

Nota: estas strings estão diretamente no JS (sem `show()` — JS não tem acesso ao helper PHP); as chaves foram registradas nos 3 JSONs de linguagem como documentação e para futura externalização.

## Endpoints consumidos

| Método | Rota | Uso no JS | Payload / Resposta |
|---|---|---|---|
| GET | `/api/v1/dashboard/filtrar` | `DashboardController.filtrar()` — chamado em click de KPI/chip/datepicker | Query: `status`, `tipo_missao_id`, `dia_efetivo`; Resposta: `{missoes, resumo, visao_geral, veiculos, rotas_dia, alertas, extrato}` |
| POST | `/api/v1/dashboard/missoes/{id}/acao` | `DashboardController.executarAcaoMissao()` | Body: `{"acao":"pausar"}`;  Resposta: `{missao_id, nova_acao, message}` |
| GET | `/api/v1/dashboard/missoes/{id}` | `DashboardController.abrirDetalhesMissao()` | Resposta: objeto de missão individual |

Os demais endpoints (resumo, desempenho, alertas, tipos-missao, extrato, visao-geral, veiculos, rotas-dia) estão disponíveis para chamadas granulares futuras; na interação pós-load, o `filtrar` agrega tudo em 1 request.

## Decisões de implementação

1. **Auth same-origin sem header**: `AuthJwtMiddleware` aceita sessão Galaxia como fallback; `fetch` usa `credentials: 'same-origin'` — nenhum token explícito necessário na view.
2. **SSR mantido**: `renderShell` do `Dashboard.php` continua passando os 9 blocos de dados para o PHP view no carregamento inicial (TTI preservado). O JS só recorre a `/api/v1/dashboard/filtrar` em interações pós-load.
3. **Paridade visual 1:1**: constantes `DASH_CORES_STATUS_VEICULO`, `DASH_CORES_STATUS_MISSAO`, `DASH_CORES_NIVEL_ALERTA` portadas diretamente dos blocos `match` e arrays PHP que foram removidos do `Dashboard.php` (linhas 202-213, 248-250 do arquivo original).
4. **Skeleton de carregamento**: durante fetch, as colunas kanban recebem barras animadas para feedback visual.
5. **Detalhes de missão**: renderizado como painel deslizante lateral (sem modal de framework) para não depender do `$galaxia->abrirModal`.

## Gates de qualidade verificados

```
grep -c sendToGalaxia .../dashboard.js          → 0  (AC2.1)
grep -E "'<tr|'<div|'<td|'<li" Dashboard.php    → 0  (AC3.1)
grep -c "acao-filtrar\|acao-missao\|acao-detalhes" dashboard.php → 0
```

## Smoke test sugerido

1. Abrir `/missao/logistica/dashboard` — página deve renderizar com SSR (kanban + veículos + rotas visíveis sem nenhum fetch extra).
2. DevTools → Network → filtrar por `/api/v1/` — ao carregar a page NÃO deve aparecer nenhuma chamada de dashboard (SSR puro).
3. Clicar em um chip de tipo de missão ou KPI de status → deve aparecer `GET /api/v1/dashboard/filtrar?...` com status 200; kanban/veículos/rotas devem atualizar sem reload.
4. Mudar a data no datepicker → mesmo comportamento do passo 3.
5. Clicar no botão de ação (Iniciar/Pausar/Retomar/Cancelar) em um card → confirm dialog; após confirmar, `POST /api/v1/dashboard/missoes/{id}/acao`; toast de sucesso aparece; kanban atualiza.
6. Clicar no botão de três pontos (detalhes) em um card → `GET /api/v1/dashboard/missoes/{id}`; painel lateral desliza para dentro.
7. Fechar painel lateral clicando no overlay ou no X → painel some.
8. Simular 403 (usuário sem permissão): toast "Sem permissão para realizar esta ação." deve aparecer.
9. `grep -c sendToGalaxia componentes/Missoes/Logistica/sinais/Dashboard/html/dashboard.js` → deve retornar `0`.
