# 11 - Guia de Manutenção

> Como localizar funcionalidades, depurar problemas e testar alterações com segurança no Genesis. Este guia assume que você leu [01 - Arquitetura Geral](01-arquitetura-geral.md).
>
> Relacionados: [12 - Armadilhas Conhecidas](12-armadilhas-conhecidas.md) (leia antes de depurar qualquer coisa), [10 - Guia de Desenvolvimento](10-guia-de-desenvolvimento.md).

## 1. Como localizar uma funcionalidade

### Partindo da URL

A URL entrega o caminho do código:

```
/missao/<Constelacao>/<Sinal>/<Lua?>
         │             │        └── $data['sinalGxData'] no start() do controller
         │             └── componentes/Missoes/<Constelacao>/sinais/<Sinal>/<Sinal>.php
         └── componentes/Missoes/<Constelacao>/
```

**Antes de concluir "é este arquivo", verifique a cascata de override**: pode existir uma versão específica em `de/<setor>/<cliente>/<nivel>/<usuario>/` que substitui o Sinal base para certos usuários ([01 §3.5](01-arquitetura-geral.md#3-ciclo-de-vida-de-uma-request-web)). Busque:

```bash
find componentes/Missoes/<Constelacao> -name "<Sinal>.php" | sort
```

### Partindo de um texto de tela

O texto que o usuário vê passa por `show()` (i18n). Procure o texto **em português literal**:

```bash
grep -rn "texto exato da tela" componentes/ --include="*.php" --include="*.js"
# se não achar, pode estar traduzido — busque no JSON:
grep -n "texto exato" linguagens/pt-br.json
```

### Partindo de uma ação (botão que "faz algo")

Inspecione o elemento no browser: os atributos `data-sinalroute`/`data-sinalrocket` carregam a rota `constelacao/estrela/satelite/opcao`. O `satelite` é geralmente o nome do Laboratório, e a `opcao` é o case do switch dentro dele.

### Partindo de uma tabela do banco

```bash
grep -rn "entity = ['\"]nome_da_tabela" componentes/ controladores/
```

Isso encontra a(s) Sonda(s)/Inteligência(s) donas da tabela. Pelo namespace da Sonda você chega ao Sinal.

### Partindo de um endpoint REST

`componentes/Missoes/Plataforma/sinais/Api/Routes.php` é o índice: rota → método de `Api.php` → Handler → Laboratório de domínio ([06 - APIs](06-apis.md)).

## 2. Como depurar

### 2.1 Sintomas clássicos e onde olhar primeiro

| Sintoma | Primeira hipótese | Onde verificar |
|---|---|---|
| Query "não retorna nada" que deveria | Filtro multi-tenant (block/empresa errados na sessão) ou soft delete (`block=0`) | Rode a query no psql **sem** filtros; compare com o que a Sonda gera |
| Registro "sumiu" | Soft delete (`block = 0`) | `SELECT ... WHERE id = X` direto no banco — a linha está lá |
| Dado gravado no cliente/empresa errada | Fallback hardcoded do tenant (`block_empresa_id='3'`) por sessão incompleta | [01 §7](01-arquitetura-geral.md#7-multi-tenant-o-mecanismo-mais-importante-do-sistema) |
| `if ($sonda->find(...))` sempre verdadeiro | `find()` é fluente (retorna `$this`) | [Armadilha 1](12-armadilhas-conhecidas.md) |
| JS antigo mesmo após editar | Regime de cache-bust (automático vs `?v=N` manual) | [Armadilha 12](12-armadilhas-conhecidas.md) |
| `Fatal: undefined method ::Html()` | Sinal linkado do SPA sem `__call` → `start()` | [Armadilha 18](12-armadilhas-conhecidas.md) |
| Horário com 3h de diferença | Timestamp do ERP legado em UTC | [Armadilha 10](12-armadilhas-conhecidas.md) |
| View não renderiza, sem erro | Nome da view "index" ≠ nome do controller em minúsculo | [Armadilha 19](12-armadilhas-conhecidas.md) |
| Comportamento diferente entre dois usuários no mesmo endpoint | Override por pasta (`de/<setor>/...`) ou permissão de nível | §1 acima |
| Erro 500 na API `/api/v1` | Exceção no Laboratório engolida pelo Dispatcher | Tabela `api_audit_log` (tem request, duração, status) + `error_log` do PHP |

### 2.2 Ferramentas de inspeção

- **Banco direto (dev):** `psql -d dev_gx_goldie` — o time trabalha assim; é seguro porque é o banco de dev. Nunca rodar writes manuais em produção.
- **Auditoria de queries:** toda escrita via Sonda é registrada (`QueriesRequestApi`); toda chamada REST fica em `api_audit_log` (payload redactado, 64 KB máx).
- **Logs:** `logs/*.log` (crons de dashboard), `/home/goldie/arquivos/logs/crons/log.txt` (todos os crons), `error_log` do PHP do servidor. Não há agregador.
- **Scripts one-off:** para investigar dados, crie um script PHP no padrão dos testes de integração (bootstrap com host `dev-`, sessão dupla, `Connect` para `dev_gx_goldie`) — e **apague depois** (a raiz do repo está cheia de `debug_*.php` que ninguém limpou; não aumente a pilha).

### 2.3 Depurando o fluxo Galaxia (request web)

Quando um clique "não faz nada" ou faz a coisa errada:

1. **Network tab**: a request vai para `/missao/...`? O payload contém `sinalroute`/`sinalrocket` esperados?
2. **A resposta JSON** contém `galaxiaMissaoUpdate` (Luz), `closeModal`, `chamarFuncao`...? Se sim, o backend respondeu — o problema é o JS do front interpretando.
3. **Hooks rodando 2×**: `Observatorio`/`GalaxiaAutoLoad` executam before **e** after — um efeito colateral duplicado (e-mail duplo, contador 2×) quase sempre vem daí.
4. **`dadosG` retornando erro**: cheque com `is_error($resultado)` — falhas de Laboratório interno não estouram exceção.

## 3. Como testar alterações

### 3.1 Regras de ouro

1. **Testes de integração SÓ no `dev_gx_goldie`.** Todo teste tem um sanity gate que aborta se `current_database()` ≠ `dev_gx_goldie` — nunca remova esse guard.
2. **Sem PHPUnit.** Todo teste é um script standalone: `php caminho/do/Teste.php`. Saída `[PASS]/[FAIL]`.
3. Dados de teste usam prefixo `__test_` e cleanup em `finally`.

### 3.2 Bootstrap canônico de teste de integração

```php
if (php_sapi_name() !== 'cli') die;
$_SERVER['HTTP_HOST'] = 'dev-genesis.goldieapp.com.br';
$_SERVER['REQUEST_METHOD'] = 'GET';
require_once '/home/goldie/www/genesis/autoload.php';
session_start();

$info = new stdClass; // userData, customerData(id=23), principalEmpresa(empresa_id=3), sectorData(inteligencia='dev_gx_goldie')
$_SESSION['galaxiaUserInfo'] = $info;                 // raiz
$_SESSION['dashboard']['galaxiaUserInfo'] = $info;    // E no grupo dashboard — os DOIS são obrigatórios

$pdo = (new \Galaxia\_Controladores\Connect)->getInstance(null, null, 'dev_gx_goldie');
$db = $pdo->query('SELECT current_database()')->fetchColumn();
if ($db !== 'dev_gx_goldie') { fwrite(STDERR, "banco errado: $db\n"); exit(1); }
```

Por que a sessão dupla: `SessionGalaxia` particiona `$_SESSION` em grupos e o `customerControl` das Sondas lê do grupo `dashboard`; sem ele, as queries filtram com customer NULL e voltam vazias.

### 3.3 Onde ficam os testes

- `tests/unit/` — unit de framework/strategies (mock-then-require).
- `tests/integration/<Area>/` — integração ponta-a-ponta por área.
- `componentes/.../<Sinal>/Testes/<espelho>/*TddTest.php` — padrão V2, espelhando a estrutura do Sinal. Referência canônica: `Mensageria/sinais/Otp/Testes/`.

### 3.4 Verificação mínima antes de dar por pronto

1. `php -l` em cada arquivo PHP alterado (o pipeline faz isso; faça também manualmente).
2. Rodar os testes do Sinal afetado + os de integração da área.
3. **Exercitar o fluxo real no browser (dev)** — muitos bugs deste sistema só aparecem com sessão real (tenant, permissões, Luz). i18n em especial: `show()` depende de harvest em runtime, só se valida no browser.
4. Se mexeu em migration: rodar contra `dev_gx_goldie` e testar um `create()` via Sonda (colunas de auditoria/block faltando só quebram aí).

## 4. Como investigar um bug de dados (checklist)

1. Reproduza a leitura exata: qual Sonda, quais `$propeties`, o que o multi-tenant injeta.
2. Rode a query crua no psql com e sem os filtros de tenant — a diferença geralmente é a resposta.
3. Cheque `block`, `block_empresa_id` do registro: foi soft-deletado? Gravado com fallback errado?
4. Se envolve ERP legado: confirme o cruzamento por `importacao_id`/`codigomd5` (nunca `numero_pedido`) e timezone.
5. Se envolve JSON (`configuracoes` etc.): lembre que a Sonda devolve **string** — o bug pode ser um `json_decode` faltando.
6. Se envolve concorrência (missões, itens): procure `FOR UPDATE SKIP LOCKED` e guards CAS (`update()` rowCount) — a ausência deles em código novo é a causa provável.

## 5. Manutenção de crons

- Cron novo: arquivo `MM-HH-nome.php` em `crons/` + rodar `auto.sh` (confira o `CRON_DIR` — aponta para path histórico `galaxia/crons`).
- Cron "não rodou": `crontab -l` (root) para ver o agendamento real; log central em `/home/goldie/arquivos/logs/crons/log.txt`.
- Todo cron de produção deve ter o guard de host (`abortar se dev-`); todo cron deve ser idempotente — o padrão do dashboard (`delete janela + insert`) é a referência.

## 6. O que NUNCA fazer em manutenção

- Raw SQL de escrita via `Connect::getInstance` (pula tenant, auditoria e soft delete).
- Remover o guard `dev_gx_goldie` de um teste.
- `DELETE` físico em tabela de domínio (o sistema inteiro assume soft delete).
- Commit/push sem pedido explícito.
- Confiar em `git diff main...HEAD` (main está congelada — o diff traz meses de ruído).
- Editar código em `antigo/` para "consertar" um problema do Genesis — a correção é sempre no lado Genesis ou na fronteira de integração.
