# Spec: Salvar motorista padrão por veículo

**Data:** 2026-05-27  
**Feature:** Persistir telefone e e-mail do motorista no cadastro do veículo para pré-preenchimento automático no modal "Liberar rota para motorista"

---

## Contexto

O modal "Liberar rota para motorista" em `central.php` hoje exige que o operador preencha telefone e e-mail toda vez que libera uma rota. O checkbox "Salvar como padrão para esse motorista" existe no HTML mas a função `salvarPadraoLocalmente` nunca foi implementada — o guard `typeof salvarPadraoLocalmente === 'function'` sempre retorna `false`, então nada é salvo.

O `rotaId` no modal equivale a um `romaneios_veiculos.id`. Quando o modal abre, o `veiculo_id` do veículo vinculado está disponível em `rotasState[rotaIdEmEdicao].veiculo_id`. Os dados padrão do motorista serão atrelados ao veículo, pois um veículo normalmente é operado pelo mesmo motorista.

---

## Arquitetura

### Camada de dados

**Migration** — `componentes/Missoes/Logistica/sinais/Central/Migrations/001_veiculo_motorista_padrao.sql`

```sql
-- Migration 001: adiciona colunas de motorista padrão em veiculos.
ALTER TABLE veiculos
  ADD COLUMN motorista_telefone_padrao VARCHAR(30)  NULL,
  ADD COLUMN motorista_email_padrao    VARCHAR(255) NULL;
```

**Sonda V2** — `componentes/Constelacoes/Veiculos/VeiculoSonda.php`  
Nova Sonda (o `Veiculo.php` existente é V1/legado — não tocar).

Métodos públicos:
- `buscarMotoristaPadrao(int $veiculoId): ?object` — SELECT `id, motorista_telefone_padrao, motorista_email_padrao` WHERE `id = $veiculoId`; retorna `null` se não encontrado
- `salvarMotoristaPadrao(int $veiculoId, string $telefone, ?string $email): void` — UPDATE dos dois campos; se `$email` for `null` ou `''`, salva `NULL` na coluna

---

### API

**Rotas novas** em `componentes/Missoes/Plataforma/sinais/Api/Routes.php`:

```
GET   /api/v1/veiculo/{id}/motorista-padrao
PATCH /api/v1/veiculo/{id}/motorista-padrao
```

**Handlers** em `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/`:

`BuscarMotoristaPadraoHandler`
- Autentica JWT (padrão interno)
- Lê `{id}` da URL, valida que é inteiro positivo
- Chama `VeiculoSonda::buscarMotoristaPadrao($id)`
- Retorna `200 { data: { telefone: "...", email: "..." } }` — campos `null` quando não preenchidos
- Retorna `404` se veículo não encontrado

`SalvarMotoristaPadraoHandler`
- Autentica JWT
- Lê `{id}` da URL
- Valida body com `SalvarMotoristaPadraoValidator`
- Chama `VeiculoSonda::salvarMotoristaPadrao($id, $telefone, $email)`
- Retorna `200 { message: "Padrão salvo." }`

**Validator** — `componentes/Missoes/Plataforma/sinais/Api/Validators/SalvarMotoristaPadraoValidator.php`
- `telefone`: obrigatório, string, max 30 chars
- `email`: opcional; se presente, deve ser e-mail válido (`filter_var FILTER_VALIDATE_EMAIL`), max 255 chars

---

### Frontend (`central.php`)

**Ao abrir o modal** (handler `click .btn-liberar-motorista`), logo após `$('#liberar-motorista-modal').removeClass('hidden')`:

1. Obtém `veiculoId` de `rotasState[rotaIdEmEdicao]?.veiculo_id`
2. Se `veiculoId` é válido (existe, não é `99999`):
   - Dispara `GET /api/v1/veiculo/{veiculoId}/motorista-padrao` (sem await — não bloqueia abertura)
   - `.then(r => { if (r.data?.telefone) { iti.setNumber(r.data.telefone); } if (r.data?.email) { $('#liberar-motorista-email').val(r.data.email); } })`
   - `.catch(() => {})` — falha silenciosa
3. Se `veiculoId` não disponível: modal abre normalmente em branco

**Ao enviar** (após sucesso do `POST /api/v1/edicao-rota`), onde hoje há a chamada morta a `salvarPadraoLocalmente`:

```js
if (padrao && veiculoId && veiculoId !== '99999') {
    api('PATCH', `/api/v1/veiculo/${veiculoId}/motorista-padrao`, {
        telefone,
        email: email || null,
    }).catch(() => {}); // silencioso — rota já foi enviada
}
```

A variável `veiculoId` é capturada no início do handler de submit a partir de `rotasState[rotaIdEmEdicao]?.veiculo_id`.

A função `salvarPadraoLocalmente` **não** será criada — o guard `typeof` que a chama será substituído pela lógica inline acima.

---

## Mapa de arquivos

| Arquivo | Ação |
|---|---|
| `componentes/Missoes/Logistica/sinais/Central/Migrations/001_veiculo_motorista_padrao.sql` | **Criar** |
| `componentes/Constelacoes/Veiculos/VeiculoSonda.php` | **Criar** |
| `componentes/Missoes/Plataforma/sinais/Api/Routes.php` | **Editar** — 2 rotas novas |
| `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/BuscarMotoristaPadraoHandler.php` | **Criar** |
| `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/SalvarMotoristaPadraoHandler.php` | **Criar** |
| `componentes/Missoes/Plataforma/sinais/Api/Validators/SalvarMotoristaPadraoValidator.php` | **Criar** |
| `componentes/Missoes/Plataforma/sinais/Api/Dispatcher.php` | **Editar** — 2 novos cases |
| `componentes/Missoes/Logistica/sinais/Central/html/central.php` | **Editar** — JS: prefetch ao abrir + PATCH ao salvar |

---

## Tratamento de erros

| Cenário | Comportamento |
|---|---|
| GET falha ao abrir modal | Modal abre em branco — sem feedback ao operador |
| PATCH falha ao salvar padrão | Silencioso — a rota já foi enviada com sucesso |
| `veiculo_id` ausente ou 99999 | Não tenta GET nem PATCH |
| `telefone` inválido no validator | 422 com mensagem de erro |
| Veículo não encontrado no GET | 404 `{ error: "Veículo não encontrado." }` |

---

## Fora do escopo

- UI de feedback ao salvar padrão (ex: toast "Padrão salvo")
- Limpeza do padrão (botão "Remover padrão")
- Histórico de motoristas por veículo
- Cadastro de motoristas como entidade separada
