# Justificativa do Motorista no Modal Acompanhamento — Edicaorota

> **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:** Salvar a justificativa opcional do motorista (`justificativa_motorista`) no banco e exibi-la no modal "Acompanhamento da rota do motorista" no `central.php`, abaixo do campo "Código do Motorista", apenas quando preenchida.

**Architecture:** 4 camadas independentes — migration SQL, dois laboratórios PHP, HTML + JS no central.php. A sonda `EdicaoRotaSonda` usa `ModelInteligencia` que lê colunas diretamente da tabela, logo apenas adicionar a coluna e repassar o campo no `make()` basta no backend. No frontend, o polling já traz o estado completo via `/api/v1/edicao-rota?ids=...`; basta expor o campo no retorno de `ConsultarEdicaoRotaLaboratorio`, mapear no `executarTick` e renderizar condicionalmente em `renderizarAcompanhamento`.

**Tech Stack:** SQL migration, PHP (Laboratorios + Sonda V2), jQuery + JS inline em `central.php`

---

### Task 1: Migration — adicionar coluna `justificativa_motorista`

**Files:**
- Create: `componentes/Missoes/Logistica/sinais/Edicaorota/Migrations/006_justificativa_motorista.sql`

- [ ] **Step 1: Criar o arquivo de migration**

Conteúdo exato:

```sql
ALTER TABLE edicoes_rota
  ADD COLUMN justificativa_motorista TEXT NULL;
```

- [ ] **Step 2: Rodar a migration no banco**

```bash
mysql -u root genesis < componentes/Missoes/Logistica/sinais/Edicaorota/Migrations/006_justificativa_motorista.sql
```

Saída esperada: nenhum erro.

- [ ] **Step 3: Confirmar que a coluna existe**

```bash
mysql -u root genesis -e "DESCRIBE edicoes_rota;" | grep justificativa
```

Saída esperada:
```
justificativa_motorista | text | YES | | NULL |
```

- [ ] **Step 4: Commit**

```bash
git add componentes/Missoes/Logistica/sinais/Edicaorota/Migrations/006_justificativa_motorista.sql
git commit -m "feat(edicaorota): migration coluna justificativa_motorista"
```

---

### Task 2: Backend — salvar justificativa no SubmeterRotaPropostaLaboratorio

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Edicaorota/Laboratorios/SubmeterRotaPropostaLaboratorio.php:57-61`
- Test: `componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/SubmeterRotaPropostaValidatorTddTest.php`

- [ ] **Step 1: Escrever o TDD test para o Validator (confirma que justificativa é opcional)**

Criar arquivo `componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/SubmeterRotaPropostaValidatorTddTest.php`:

```php
<?php

require_once __DIR__ . '/../../Validators/SubmeterRotaPropostaValidator.php';

use GalaxiaMissoes\Logistica\sinais\Edicaorota\Validators\SubmeterRotaPropostaValidator;

class AssertSubmeter
{
    public static int $passou = 0;
    public static int $falhas = 0;

    public static function true(bool $cond, string $msg): void
    {
        if ($cond) {
            self::$passou++;
            echo "✅ [PASS] {$msg}\n";
        } else {
            self::$falhas++;
            echo "❌ [FAIL] {$msg}\n";
        }
    }
}

echo "====================================================\n";
echo "TDD — SubmeterRotaPropostaValidator\n";
echo "====================================================\n\n";

$v       = new SubmeterRotaPropostaValidator();
$rota    = [['id' => 1], ['id' => 2]];
$payload = ['token' => 'abc', 'rota_proposta' => [['id' => 2], ['id' => 1]]];

// Sem justificativa — deve passar
$erros = $v->validar($payload, $rota);
AssertSubmeter::true(empty($erros), 'Validator passa sem justificativa_motorista');

// Com justificativa preenchida — deve passar
$erros = $v->validar(array_merge($payload, ['justificativa_motorista' => 'Cliente pediu']), $rota);
AssertSubmeter::true(empty($erros), 'Validator passa com justificativa_motorista preenchida');

// Com justificativa vazia — deve passar (opcional)
$erros = $v->validar(array_merge($payload, ['justificativa_motorista' => '']), $rota);
AssertSubmeter::true(empty($erros), 'Validator passa com justificativa_motorista vazia');

echo "\n====================================================\n";
echo "RESULTADO: ✅ " . AssertSubmeter::$passou . "  ❌ " . AssertSubmeter::$falhas . "\n";
if (AssertSubmeter::$falhas > 0) {
    exit(1);
}
echo "🏆 TODOS OS TESTES PASSARAM\n";
```

- [ ] **Step 2: Rodar o teste para confirmar que passa (sem alterações no Validator)**

```bash
php componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/SubmeterRotaPropostaValidatorTddTest.php
```

Saída esperada:
```
====================================================
TDD — SubmeterRotaPropostaValidator
====================================================

✅ [PASS] Validator passa sem justificativa_motorista
✅ [PASS] Validator passa com justificativa_motorista preenchida
✅ [PASS] Validator passa com justificativa_motorista vazia

====================================================
RESULTADO: ✅ 3  ❌ 0
🏆 TODOS OS TESTES PASSARAM
```

- [ ] **Step 3: Adicionar `justificativa_motorista` ao `make()` em `SubmeterRotaPropostaLaboratorio`**

Localizar o bloco `$sonda->make([` (linha ~57 do arquivo):

```php
        $sonda->make([
            'id'             => (int) $edicao->id,
            'rota_proposta'  => json_encode($proposta),
            'status'         => EdicaoRotaStatus::PENDENTE_APROVACAO->value,
        ]);
```

Substituir por:

```php
        $sonda->make([
            'id'                      => (int) $edicao->id,
            'rota_proposta'           => json_encode($proposta),
            'justificativa_motorista' => trim($entrada['justificativa_motorista'] ?? '') ?: null,
            'status'                  => EdicaoRotaStatus::PENDENTE_APROVACAO->value,
        ]);
```

**Nota:** `$entrada` é o array passado ao construtor (vindos do `$_POST` via `App.php`). String vazia ou ausente → `null`.

- [ ] **Step 4: Rodar os testes novamente para confirmar que nada quebrou**

```bash
php componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/SubmeterRotaPropostaValidatorTddTest.php
```

Saída esperada: igual ao Step 2.

- [ ] **Step 5: Commit**

```bash
git add componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/SubmeterRotaPropostaValidatorTddTest.php
git add componentes/Missoes/Logistica/sinais/Edicaorota/Laboratorios/SubmeterRotaPropostaLaboratorio.php
git commit -m "feat(edicaorota): salvar justificativa_motorista no submit da rota"
```

---

### Task 3: Backend — expor justificativa no ConsultarEdicaoRotaLaboratorio

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Edicaorota/Laboratorios/ConsultarEdicaoRotaLaboratorio.php:83-86`

- [ ] **Step 1: Adicionar `justificativa_motorista` ao array de retorno**

Localizar (linha ~83-86):

```php
                'cancelado_por'            => isset($edicao->cancelado_por) ? (int) $edicao->cancelado_por : null,
                'cancelado_em'             => $edicao->cancelado_em ?? null,
                'motivo_cancelamento'      => $edicao->motivo_cancelamento ?? null,
```

Substituir por:

```php
                'cancelado_por'            => isset($edicao->cancelado_por) ? (int) $edicao->cancelado_por : null,
                'cancelado_em'             => $edicao->cancelado_em ?? null,
                'motivo_cancelamento'      => $edicao->motivo_cancelamento ?? null,
                'justificativa_motorista'  => $edicao->justificativa_motorista ?? null,
```

- [ ] **Step 2: Confirmar que os testes existentes ainda passam**

```bash
php componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/SubmeterRotaPropostaValidatorTddTest.php
php componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/CriarEdicaoRotaLaboratorioTddTest.php
php componentes/Missoes/Logistica/sinais/Edicaorota/Testes/Laboratorios/AprovarEdicaoRotaLaboratorioTddTest.php
```

Saída esperada: todos com `🏆 TODOS OS TESTES PASSARAM`.

- [ ] **Step 3: Commit**

```bash
git add componentes/Missoes/Logistica/sinais/Edicaorota/Laboratorios/ConsultarEdicaoRotaLaboratorio.php
git commit -m "feat(edicaorota): expor justificativa_motorista na consulta de edicao"
```

---

### Task 4: Frontend — HTML e JS no central.php

**Files:**
- Modify: `componentes/Missoes/Logistica/sinais/Central/html/central.php` (linhas ~3072, ~5583, ~5735, ~5799, ~5848)

- [ ] **Step 1: Adicionar o bloco HTML `#acompanhar-justificativa-bloco` após `#acompanhar-codigo-bloco`**

Localizar (linha ~3072-3074):

```html
            </div>

            <!-- Tabela de pedidos -->
```

Substituir por:

```html
            </div>

            <!-- Observação deixada pelo motorista no modal de confirmação de envio -->
            <div id="acompanhar-justificativa-bloco" class="hidden bg-black/30 border border-white/5 rounded-lg p-3">
                <div class="text-[11px] uppercase tracking-wider font-semibold acompanhar-label mb-1">
                    <i class="fas fa-comment-alt mr-1"></i>Observação do motorista
                </div>
                <div id="acompanhar-justificativa-texto" class="text-sm text-white/80 break-words"></div>
            </div>

            <!-- Tabela de pedidos -->
```

- [ ] **Step 2: Incluir `justificativa_motorista` no `fingerprintAcompanhamento`**

Localizar (linha ~5799-5805):

```js
        return [
            estado.status || '',
            estado.expirado ? '1' : '0',
            estado.expira_em || '',
            ids,
            estado.codigo || '',
        ].join('::');
```

Substituir por:

```js
        return [
            estado.status || '',
            estado.expirado ? '1' : '0',
            estado.expira_em || '',
            ids,
            estado.codigo || '',
            estado.justificativa_motorista || '',
        ].join('::');
```

Isso garante que quando o servidor retornar a justificativa pela primeira vez, o fingerprint muda e `renderizarAcompanhamento` redesenha o modal.

- [ ] **Step 3: Mapear `justificativa_motorista` no `executarTick`**

Localizar (linha ~5583-5589):

```js
            const novo = {
                status:    ed.status,
                expirado:  !!ed.expirado,
                expira_em: ed.expira_em,
                proposta_em_andamento: ed.rota_em_andamento,
                rota_proposta: ed.rota_proposta,
            };
```

Substituir por:

```js
            const novo = {
                status:    ed.status,
                expirado:  !!ed.expirado,
                expira_em: ed.expira_em,
                proposta_em_andamento: ed.rota_em_andamento,
                rota_proposta: ed.rota_proposta,
                justificativa_motorista: ed.justificativa_motorista || null,
            };
```

- [ ] **Step 4: Mapear `justificativa_motorista` em `abrirAcompanhamentoPorEdicaoId`**

Localizar (linha ~5735-5745) o bloco onde `edicoesPorRota[rotaId]` é populado quando não está em memória:

```js
                    edicoesPorRota[rotaId] = {
                        edicaoId:              ed.id,
                        token:                 ed.token,
                        status:                ed.status,
                        expira_em:             ed.expira_em,
                        expirado:              !!ed.expirado,
                        enviado_em:            Date.now(),
                        codigo:                null,
                        proposta_em_andamento: ed.rota_em_andamento,
                        rota_proposta:         ed.rota_proposta,
                    };
```

Substituir por:

```js
                    edicoesPorRota[rotaId] = {
                        edicaoId:                ed.id,
                        token:                   ed.token,
                        status:                  ed.status,
                        expira_em:               ed.expira_em,
                        expirado:                !!ed.expirado,
                        enviado_em:              Date.now(),
                        codigo:                  null,
                        proposta_em_andamento:   ed.rota_em_andamento,
                        rota_proposta:           ed.rota_proposta,
                        justificativa_motorista: ed.justificativa_motorista || null,
                    };
```

- [ ] **Step 5: Adicionar render do bloco de justificativa em `renderizarAcompanhamento`**

Localizar (linha ~5843-5848) o trecho logo após o `} else {` que esconde `#acompanhar-link-bloco` e `#acompanhar-codigo-bloco`, antes de `const atual = montarRotaAtual(rotaId)`:

```js
        } else {
            $('#acompanhar-link-bloco').addClass('hidden');
            $('#acompanhar-codigo-bloco').addClass('hidden');
        }

        const atual    = montarRotaAtual(rotaId);
```

Substituir por:

```js
        } else {
            $('#acompanhar-link-bloco').addClass('hidden');
            $('#acompanhar-codigo-bloco').addClass('hidden');
        }

        // Observação do motorista — visível em todos os estados quando preenchida
        var just = estado.justificativa_motorista;
        if (just) {
            $('#acompanhar-justificativa-texto').text(just);
            $('#acompanhar-justificativa-bloco').removeClass('hidden');
        } else {
            $('#acompanhar-justificativa-bloco').addClass('hidden');
        }

        const atual    = montarRotaAtual(rotaId);
```

- [ ] **Step 6: Commit**

```bash
git add componentes/Missoes/Logistica/sinais/Central/html/central.php
git commit -m "feat(edicaorota): exibir justificativa do motorista no modal Acompanhamento"
```

---

## Verificação manual

Após todos os tasks:

1. Abrir a tela do motorista (`/edicao-rota/<token>`)
2. Reordenar as paradas, preencher a justificativa ("Teste de justificativa") e clicar "Confirmar envio"
3. No `central.php`, abrir o modal Acompanhamento para essa rota
4. Verificar que o bloco "Observação do motorista" aparece abaixo do "Código do Motorista" com o texto "Teste de justificativa"
5. Abrir o modal novamente para uma rota sem justificativa — verificar que o bloco **não** aparece
