# Veículo — Motorista Padrão (pré-preenchimento modal liberação)

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Persistir telefone e e-mail do motorista no cadastro do veículo para que o modal "Liberar rota para motorista" preencha automaticamente esses dados na próxima vez.

**Architecture:** Nova migration adiciona `motorista_telefone_padrao` e `motorista_email_padrao` na tabela `veiculos`. Uma `VeiculoSonda` V2 faz o read/update. Dois handlers V2 (`BuscarMotoristaPadraoHandler` e `SalvarMotoristaPadraoHandler`) expõem `GET` e `PATCH /api/v1/veiculo/{id}/motorista-padrao`. O JS do `central.php` faz GET ao abrir o modal (pré-preenche) e PATCH ao enviar com checkbox marcado (persiste).

**Tech Stack:** PHP 8 (Sonda V2 / ModelInteligencia), MySQL, CoffeeCode Router, jQuery + Fetch API

---

## Mapa de arquivos

| Arquivo | Ação |
|---|---|
| `componentes/Missoes/Logistica/sinais/Central/Migrations/001_veiculo_motorista_padrao.sql` | **Criar** — DDL das 2 novas colunas |
| `componentes/Constelacoes/Veiculos/VeiculoSonda.php` | **Criar** — Sonda V2 para tabela veiculos |
| `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/SalvarMotoristaPadraoValidator.php` | **Criar** — valida body do PATCH |
| `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/BuscarMotoristaPadraoHandler.php` | **Criar** — GET handler |
| `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/SalvarMotoristaPadraoHandler.php` | **Criar** — PATCH handler |
| `componentes/Missoes/Plataforma/sinais/Api/Routes.php` | **Editar** — 2 rotas novas |
| `componentes/Missoes/Plataforma/sinais/Api/Api.php` | **Editar** — 2 use statements + 2 métodos |
| `componentes/Missoes/Logistica/sinais/Central/html/central.php` | **Editar** — JS prefetch + PATCH + remover código morto |

Todos os caminhos são relativos a `/home/goldie/www/genesis/`.

---

### Task 1: Migration — adicionar colunas `motorista_telefone_padrao` e `motorista_email_padrao`

**Files:**
- Create: `componentes/Missoes/Logistica/sinais/Central/Migrations/001_veiculo_motorista_padrao.sql`

- [ ] **Criar o diretório de migrations do sinal Central**

```bash
mkdir -p /home/goldie/www/genesis/componentes/Missoes/Logistica/sinais/Central/Migrations
```

- [ ] **Criar o arquivo de migration**

```sql
-- Migration 001: adiciona colunas de motorista padrão em veiculos.
-- Campos nullable — preenchimento é opcional (nem todo veículo tem motorista fixo).
ALTER TABLE veiculos
  ADD COLUMN motorista_telefone_padrao VARCHAR(30)  NULL,
  ADD COLUMN motorista_email_padrao    VARCHAR(255) NULL;
```

Salvar em `componentes/Missoes/Logistica/sinais/Central/Migrations/001_veiculo_motorista_padrao.sql`.

- [ ] **Aplicar no banco de desenvolvimento**

```bash
cd /home/goldie/www/genesis
sudo mysql dev_gx_goldie < componentes/Missoes/Logistica/sinais/Central/Migrations/001_veiculo_motorista_padrao.sql
```

- [ ] **Verificar**

```bash
sudo mysql dev_gx_goldie -e "SHOW COLUMNS FROM veiculos LIKE 'motorista_%';"
```

Esperado: duas linhas — `motorista_telefone_padrao | varchar(30) | YES` e `motorista_email_padrao | varchar(255) | YES`.

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Central/Migrations/001_veiculo_motorista_padrao.sql
git commit -m "feat(veiculo): add motorista_telefone_padrao and motorista_email_padrao columns"
```

---

### Task 2: VeiculoSonda — Sonda V2 para tabela `veiculos`

**Files:**
- Create: `componentes/Constelacoes/Veiculos/VeiculoSonda.php`

- [ ] **Criar o arquivo**

```php
<?php

namespace GalaxiaConstelacoes\Veiculos;

use Galaxia\_Controladores\ModelInteligencia;

/**
 * VeiculoSonda — acesso V2 à tabela veiculos.
 *
 * Expõe apenas os métodos necessários para leitura e atualização do
 * motorista padrão. Para operações legadas, o Veiculo.php (V1) ainda existe
 * mas não deve ser estendido em código novo.
 */
class VeiculoSonda extends ModelInteligencia
{
    public static $entity;
    public static $protected;
    public static $required;
    public static $fields;
    public static $propeties;

    public function __construct()
    {
        $this->init();
    }

    private function init(): void
    {
        self::$entity     = 'veiculos';
        self::$protected  = ['id'];
        self::$required   = [];
        self::$fields     = [];
        self::$propeties  = [
            'customerControl' => true,
            'companyControl'  => false,
            'userControl'     => false,
            'db'              => 'gx_goldie',
        ];
        parent::__construct(
            self::$entity,
            self::$protected,
            self::$required,
            self::$fields,
            self::$propeties
        );
    }

    /**
     * Retorna o telefone e e-mail padrão do motorista vinculado ao veículo.
     * Retorna null se o veículo não existir ou não tiver dados preenchidos.
     */
    public function buscarMotoristaPadrao(int $veiculoId): ?object
    {
        $resultado = $this->find(
            'id = :id',
            "id={$veiculoId}",
            'id, motorista_telefone_padrao, motorista_email_padrao'
        )->fetch(false);

        return $resultado ?: null;
    }

    /**
     * Persiste telefone e e-mail padrão do motorista no veículo.
     * Passa string vazia como $email para gravar NULL na coluna.
     */
    public function salvarMotoristaPadrao(int $veiculoId, string $telefone, ?string $email): void
    {
        $this->update(
            [
                'motorista_telefone_padrao' => $telefone ?: null,
                'motorista_email_padrao'    => ($email !== null && $email !== '') ? $email : null,
            ],
            'id = :id',
            "id={$veiculoId}"
        );
    }
}
```

- [ ] **Verificar sintaxe**

```bash
php -l /home/goldie/www/genesis/componentes/Constelacoes/Veiculos/VeiculoSonda.php
```

Esperado: `No syntax errors detected`

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Constelacoes/Veiculos/VeiculoSonda.php
git commit -m "feat(veiculo): add VeiculoSonda V2 with buscarMotoristaPadrao and salvarMotoristaPadrao"
```

---

### Task 3: Validator + Handlers da API

**Files:**
- Create: `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/SalvarMotoristaPadraoValidator.php`
- Create: `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/BuscarMotoristaPadraoHandler.php`
- Create: `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/SalvarMotoristaPadraoHandler.php`

- [ ] **Criar o diretório**

```bash
mkdir -p /home/goldie/www/genesis/componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo
```

- [ ] **Criar o Validator**

```php
<?php

namespace GalaxiaMissoes\Plataforma\sinais\Api\Handlers\Veiculo;

/**
 * Valida o body do PATCH /api/v1/veiculo/{id}/motorista-padrao.
 */
class SalvarMotoristaPadraoValidator
{
    public function validar(array $entrada): array
    {
        $erros = [];

        if (empty($entrada['telefone'])) {
            $erros[] = 'telefone é obrigatório.';
        } elseif (mb_strlen((string) $entrada['telefone']) > 30) {
            $erros[] = 'telefone não pode ultrapassar 30 caracteres.';
        }

        if (!empty($entrada['email'])) {
            if (!filter_var($entrada['email'], FILTER_VALIDATE_EMAIL)) {
                $erros[] = 'email deve ser um endereço válido.';
            } elseif (mb_strlen((string) $entrada['email']) > 255) {
                $erros[] = 'email não pode ultrapassar 255 caracteres.';
            }
        }

        return $erros;
    }
}
```

Salvar em `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/SalvarMotoristaPadraoValidator.php`.

- [ ] **Criar o BuscarMotoristaPadraoHandler (GET)**

```php
<?php

namespace GalaxiaMissoes\Plataforma\sinais\Api\Handlers\Veiculo;

use GalaxiaConstelacoes\Veiculos\VeiculoSonda;
use GalaxiaMissoes\Plataforma\sinais\Api\Handlers\BaseHandler;
use GalaxiaMissoes\Plataforma\sinais\Api\Request;
use GalaxiaMissoes\Plataforma\sinais\Api\Response;

class BuscarMotoristaPadraoHandler extends BaseHandler
{
    public function handle(Request $req, Response $res): void
    {
        $veiculoId = (int) ($req->routeParams['id'] ?? 0);

        if ($veiculoId <= 0) {
            [$body, $status] = $this->erro($req, 'invalid_input', 'ID de veículo inválido.', 400);
            $res->json($body, $status);
            return;
        }

        $sonda     = new VeiculoSonda();
        $veiculo   = $sonda->buscarMotoristaPadrao($veiculoId);

        if ($veiculo === null) {
            [$body, $status] = $this->erro($req, 'not_found', 'Veículo não encontrado.', 404);
            $res->json($body, $status);
            return;
        }

        [$body, $status] = $this->ok($req, [
            'telefone' => $veiculo->motorista_telefone_padrao ?? null,
            'email'    => $veiculo->motorista_email_padrao    ?? null,
        ]);
        $res->json($body, $status);
    }
}
```

Salvar em `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/BuscarMotoristaPadraoHandler.php`.

- [ ] **Criar o SalvarMotoristaPadraoHandler (PATCH)**

```php
<?php

namespace GalaxiaMissoes\Plataforma\sinais\Api\Handlers\Veiculo;

use GalaxiaConstelacoes\Veiculos\VeiculoSonda;
use GalaxiaMissoes\Plataforma\sinais\Api\Handlers\BaseHandler;
use GalaxiaMissoes\Plataforma\sinais\Api\Request;
use GalaxiaMissoes\Plataforma\sinais\Api\Response;

class SalvarMotoristaPadraoHandler extends BaseHandler
{
    public function handle(Request $req, Response $res): void
    {
        $veiculoId = (int) ($req->routeParams['id'] ?? 0);

        if ($veiculoId <= 0) {
            [$body, $status] = $this->erro($req, 'invalid_input', 'ID de veículo inválido.', 400);
            $res->json($body, $status);
            return;
        }

        $erros = (new SalvarMotoristaPadraoValidator())->validar($req->body);
        if (!empty($erros)) {
            [$body, $status] = $this->erro($req, 'invalid_input', implode(' ', $erros), 422);
            $res->json($body, $status);
            return;
        }

        $telefone = trim((string) ($req->body['telefone'] ?? ''));
        $email    = isset($req->body['email']) ? trim((string) $req->body['email']) : null;

        $sonda = new VeiculoSonda();

        // Verifica se o veículo existe antes de tentar atualizar
        if ($sonda->buscarMotoristaPadrao($veiculoId) === null) {
            [$body, $status] = $this->erro($req, 'not_found', 'Veículo não encontrado.', 404);
            $res->json($body, $status);
            return;
        }

        $sonda->salvarMotoristaPadrao($veiculoId, $telefone, $email);

        [$body, $status] = $this->ok($req, ['message' => 'Padrão salvo.']);
        $res->json($body, $status);
    }
}
```

Salvar em `componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/SalvarMotoristaPadraoHandler.php`.

- [ ] **Verificar sintaxe dos 3 arquivos**

```bash
cd /home/goldie/www/genesis
php -l componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/SalvarMotoristaPadraoValidator.php
php -l componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/BuscarMotoristaPadraoHandler.php
php -l componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/SalvarMotoristaPadraoHandler.php
```

Esperado: `No syntax errors detected` nos 3.

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Plataforma/sinais/Api/Handlers/Veiculo/
git commit -m "feat(api): add BuscarMotoristaPadrao and SalvarMotoristaPadrao handlers for veiculo"
```

---

### Task 4: Routes + Api.php — registrar as rotas

**Files:**
- Modify: `componentes/Missoes/Plataforma/sinais/Api/Routes.php`
- Modify: `componentes/Missoes/Plataforma/sinais/Api/Api.php`

- [ ] **Adicionar as 2 rotas em `Routes.php`**

Localizar o bloco que termina com `$route->delete('/regras/{id}', 'Api:regrasRemover');` e inserir logo após:

```php
// -------- Veiculo --------
$route->get  ('/veiculo/{id}/motorista-padrao', 'Api:veiculoBuscarMotoristaPadrao');
$route->patch('/veiculo/{id}/motorista-padrao', 'Api:veiculoSalvarMotoristaPadrao');
```

- [ ] **Adicionar os 2 `use` statements em `Api.php`**

Localizar a linha:
```php
use GalaxiaMissoes\Plataforma\sinais\Api\Handlers\Webhooks\InboundHandler;
```

Inserir imediatamente após:
```php
use GalaxiaMissoes\Plataforma\sinais\Api\Handlers\Veiculo\BuscarMotoristaPadraoHandler;
use GalaxiaMissoes\Plataforma\sinais\Api\Handlers\Veiculo\SalvarMotoristaPadraoHandler;
```

- [ ] **Adicionar os 2 métodos no final da classe `Api` em `Api.php`**

Localizar o último método público da classe (antes do fechamento `}` da classe) e adicionar após ele:

```php
    // -------- Veiculo --------

    public function veiculoBuscarMotoristaPadrao(?array $data = []): void
    {
        $this->dispatcher()->run(
            'GET', '/api/v1/veiculo/{id}/motorista-padrao',
            BuscarMotoristaPadraoHandler::class, $data ?? [],
            ['skipValidacaoConteudo' => true]
        );
    }

    public function veiculoSalvarMotoristaPadrao(?array $data = []): void
    {
        $this->dispatcher()->run(
            'PATCH', '/api/v1/veiculo/{id}/motorista-padrao',
            SalvarMotoristaPadraoHandler::class, $data ?? []
        );
    }
```

- [ ] **Verificar sintaxe dos 2 arquivos editados**

```bash
cd /home/goldie/www/genesis
php -l componentes/Missoes/Plataforma/sinais/Api/Routes.php
php -l componentes/Missoes/Plataforma/sinais/Api/Api.php
```

Esperado: `No syntax errors detected` nos 2.

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Plataforma/sinais/Api/Routes.php \
        componentes/Missoes/Plataforma/sinais/Api/Api.php
git commit -m "feat(api): register GET and PATCH routes for veiculo/motorista-padrao"
```

---

### Task 5: JS em `central.php` — prefetch ao abrir + PATCH ao salvar

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Central/html/central.php`

**Parte A — pré-preencher ao abrir o modal**

- [ ] **Localizar o handler de abertura do modal e adicionar o prefetch**

Localizar (≈linha 5185):
```js
        $('#liberar-motorista-modal').removeClass('hidden');
        ensureItiInit();
    });
```

Substituir por:
```js
        $('#liberar-motorista-modal').removeClass('hidden');
        ensureItiInit();

        // Pré-preenche telefone/email com o padrão salvo para este veículo
        const stateRota = (typeof getRotasState === 'function') ? getRotasState() : null;
        const veiculoIdPadrao = stateRota && stateRota[rotaIdEmEdicao]
            ? stateRota[rotaIdEmEdicao].veiculo_id
            : null;
        if (veiculoIdPadrao && String(veiculoIdPadrao) !== '99999') {
            api('GET', `/api/v1/veiculo/${veiculoIdPadrao}/motorista-padrao`)
                .then(r => {
                    if (r.data?.telefone) {
                        if (liberarMotoristaIti && typeof liberarMotoristaIti.setNumber === 'function') {
                            liberarMotoristaIti.setNumber(r.data.telefone);
                        } else {
                            $('#liberar-motorista-telefone').val(r.data.telefone);
                        }
                    }
                    if (r.data?.email) {
                        $('#liberar-motorista-email').val(r.data.email);
                    }
                })
                .catch(() => {}); // falha silenciosa — modal abre normalmente em branco
        }
    });
```

**Parte B — salvar padrão ao enviar (substituir código morto)**

- [ ] **Localizar e substituir a chamada morta a `salvarPadraoLocalmente`**

Localizar (≈linha 5437):
```js
            if (padrao && typeof salvarPadraoLocalmente === 'function') {
                salvarPadraoLocalmente(rotaIdEmEdicao, { telefone, email, canal, tempo });
            }
```

Substituir por:
```js
            if (padrao) {
                const stateParaSalvar = (typeof getRotasState === 'function') ? getRotasState() : null;
                const veiculoIdSalvar = stateParaSalvar && stateParaSalvar[rotaIdEmEdicao]
                    ? stateParaSalvar[rotaIdEmEdicao].veiculo_id
                    : null;
                if (veiculoIdSalvar && String(veiculoIdSalvar) !== '99999') {
                    api('PATCH', `/api/v1/veiculo/${veiculoIdSalvar}/motorista-padrao`, {
                        telefone,
                        email: email || null,
                    }).catch(() => {}); // silencioso — rota já foi enviada com sucesso
                }
            }
```

- [ ] **Verificar sintaxe PHP**

```bash
cd /home/goldie/www/genesis
php -l componentes/Missoes/Logistica/sinais/Central/html/central.php
```

Esperado: `No syntax errors detected`

- [ ] **Commit**

```bash
cd /home/goldie/www/genesis
git add componentes/Missoes/Logistica/sinais/Central/html/central.php
git commit -m "feat(central): prefetch and persist motorista padrao in liberation modal"
```

---

## Self-Review

### Cobertura da spec

| Requisito | Task |
|---|---|
| Migration `motorista_telefone_padrao` e `motorista_email_padrao` em `veiculos` | Task 1 |
| `VeiculoSonda` V2 com `buscarMotoristaPadrao` e `salvarMotoristaPadrao` | Task 2 |
| Validator: `telefone` obrigatório max 30, `email` opcional válido max 255 | Task 3 |
| Handler GET — 404 se veículo não encontrado, retorna `{ telefone, email }` | Task 3 |
| Handler PATCH — valida, verifica existência, persiste | Task 3 |
| Rotas registradas em Routes.php | Task 4 |
| Métodos registrados em Api.php | Task 4 |
| Prefetch ao abrir modal (preenche telefone via `iti.setNumber` e e-mail) | Task 5A |
| Falha silenciosa no GET | Task 5A |
| PATCH ao enviar com checkbox marcado | Task 5B |
| Remoção do código morto `salvarPadraoLocalmente` | Task 5B |
| Falha silenciosa no PATCH | Task 5B |
| Não tenta request se `veiculo_id` ausente ou 99999 | Task 5A + 5B |

### Consistência de nomes

- `VeiculoSonda` → namespace `GalaxiaConstelacoes\Veiculos` → importado nos handlers ✅
- `buscarMotoristaPadrao(int $veiculoId): ?object` → usado nos dois handlers ✅
- `salvarMotoristaPadrao(int $veiculoId, string $telefone, ?string $email): void` → usado em SalvarHandler ✅
- `SalvarMotoristaPadraoValidator::validar(array $entrada): array` → campos `telefone` e `email` ✅
- Rotas `veiculoBuscarMotoristaPadrao` / `veiculoSalvarMotoristaPadrao` → métodos em Api.php ✅
- `r.data?.telefone` e `r.data?.email` → shape retornado por BuscarHandler ✅
