## Goal

Corrigir a Busca Global do Portal (`/busca`), que atualmente gera links quebrados (HTTP 404) para a maioria dos resultados.

**Reprodução (evidência coletada em 2026-08-17):**
- `GET /busca?q=tecnologia` → resultados com `href="http://localhost:10011/maxima-tecnologia"`, `/tns-tecnologia`, `/faculdade-de-tecnologia-da-bahia`, `/pbsoft-tecnologia`, `/o-futuro-e-agora-congresso-de-tecnologia-sucesu-ba` → todos retornam **404**.
- `GET /busca?q=sucesu` → links `/feira-de-solucoes-...`, `/missao-empresarial-...`, `/sucesu-bahia` (deveria ser `/regional/sucesu-bahia`) → **404**.

**Causa raiz:**
- `V2/layouts/portal/search/index.blade.php:42,49` monta `href="{{ url($item->slug) }}"` — usa somente o slug cru, sem o prefixo de rota do módulo.
- O índice público (`v2_public_search_index`, via `PublicSearchDTO`) grava `slug` (slug cru) e `module` com valores: `noticias`, `associados`, `parceiros-institucionais`, `unidades-regionais`, `trabalhe-conosco`, `Eventos` (agenda), `diretoria` (equipe), `basicpage` (páginas fixas).
- Rotas públicas reais:
  - `noticias` → `/noticia/{slug}`
  - `Eventos` → `/agenda/{slug}`
  - `unidades-regionais` → `/regional/{slug}`
  - `associados` → `/associado/{slug}`
  - `trabalhe-conosco` → `/trabalhe-conosco/{slug}`
  - `diretoria` → `/equipe/{slug}`
  - `basicpage` → `/{slug}` (rota fallback)
  - `parceiros-institucionais` → **não existe rota pública por slug**; a única rota é `/parceiros-institucionais/detalhe/{id}` (usa `entity_id`, não slug).

**Solução esperada:**
- `SearchService::publicSearch()` deve selecionar também `entity_id` (já existe no índice) e expor `url` pronta ou um mapeamento módulo→prefixo.
- O mapeamento de URL deve viver em um único lugar (helper/service), consumido pela view. Para `parceiros-institucionais`, usar `/parceiros-institucionais/detalhe/{entity_id}`; se `entity_id` ausente, suprimir o item da lista (não gerar 404).
- View `search/index.blade.php` deve usar a URL montada (nunca `url($slug)` direto).

## Non-Goal

- Não alterar o algoritmo de ranking/TS-search do PostgreSQL.
- Não alterar o schema do índice (`v2_public_search_index`) — apenas adicionar `entity_id` ao select da query.
- Não mexer na busca do CMS (`cmsSearch`).
- Sem refatoração de nomes de rotas já publicadas.
- Não tocar nos seeders dos módulos (criação de slugs) — apenas no consumo.

## Constraints

PHP 7.4 | PHPUnit ~6.0. Nunca commitar. Model: UUID, SoftDeletes.
Use o X-CMS-AI-Token do ai_acess definido no .env para ter livre acesso ao CMS a nível de UI/UX
SniffCSS habilitado em MCP e Host para consulta da página real
Docker only. execute via docker compose exec app [command]
Composer usa classmap-authoritative: rodar `composer dump-autoload` após adicionar classes novas.

## Success Criteria

1. `GET /busca?q=tecnologia` e `?q=sucesu` retornam links 200 (curl confirma) para todos os resultados de módulo (notícia, agenda, regional, associado, vaga, parceiro via detalhe/{id}, equipe).
2. Nenhum resultado gera href que retorna 404.
3. Resultados `basicpage` continuam funcionando via fallback `/{slug}`.
4. Teste unit novo: mapeamento módulo→URL (incl. parceiros com/sem entity_id).
5. Teste feature novo: rota `/busca` renderiza hrefs corretos (assert no HTML).
6. Suíte V2 Unit não regride (0 novas falhas).

================================================================================

# RESULT-LOG

```
Status: Concluído
Date: 2026-08-17
Sub-tasks: 3/3 (fix service+view, unit tests, feature tests + validação real)
Files modified: 3
Seeds closed: 1/1 (sucesu-6cfe)
Outcome: Links da busca agora usam prefixo de rota por módulo; parceiros usam
         /detalhe/{entity_id}; resultados sem URL montável são suprimidos.
Notes:
  - SearchService::publicSearch() agora seleciona entity_id e anexa result_url
    via SearchService::publicResultUrl() (fonte única do mapeamento módulo->rota).
  - View search/index.blade.php usa $item->result_url (nunca url($slug)).
  - Testes: tests/Unit/V2/Services/Search/PublicSearchResultUrlTest (10 testes,
    11 asserts) + tests/Feature/V2/Services/Search/PublicSearchPageTest (3 testes,
    13 asserts). Suíte V2 Unit: 491 testes, 2 falhas PRÉ-EXISTENTES não relacionadas
    (CmsSidebarTest, CmsTypographyTest).
  - Validação real: /busca?q=tecnologia e ?q=sucesu → hrefs com prefixo correto e
    todos 200 (curl). Cache invalidado (clear-page-cache).
  - Evidência visual: antes/depois visualmente idênticos (só muda o href, não o
    estilo). Screenshot/persist do AFTER em sniff-report/evidence/sucesu-6cfe/after/.
    Baseline BEFORE (com links quebrados) em sniff-report/captures/busca.jsonl.
  - OBSERVAÇÃO: 2 falhas pré-existentes na suíte (CmsSidebarTest, CmsTypographyTest)
    — fora do escopo; já confirmadas presentes antes desta correção.
```

================================================================================

# AI-AREA

```
1. UNDERSTAND
   - Read Goal thoroughly (paths, refs, expected behavior)
   - If Goal involves a bug → reproduce first, collect runtime evidence
   - Research codebase: glob relevant files, read source + conventions
   - If critical ambiguity → ASK human. Minor → ASSUME + document.

2. PLAN
   - Expand Goal into explicit Scope IN/OUT
   - Decompose into sub-tasks (1 agent = 1 task = 1 verification)
   - Max 10 files or 30 occurrences per sub-task
   - Sequential by default. Parallel only if independent.
   - Register: sd create → sd plan create → sd plan adopt → sd sync

3. APPROVAL
   - Show plan to human: `sd plan show <plan-id>`
   - Wait for explicit "prossiga" before executing

4. EXECUTE
   - For each sub-task sequentially:
     a. Delegate to coder via task tool
     b. Verify against Success Criteria
     c. IF implementation involves UI, verify with SniffCSS (MCP || CLI command)
     d. IF fail any verify → correction sub-task, repeat 4a
     e. sd close <seed-id> --reason "[result]"

5. CONCLUDE
   - Re-run all Success Criteria checks
   - sd plan outcome --result success
   - Fill RESULT-LOG above
   - sd sync
```