# INT-027-01 — BlogController e BlogPresenter

| Campo | Valor |
|---|---|
| **status** | feita |
| **spec** | [`docs/specs/integracao/027-blog.md`](../specs/integracao/027-blog.md) §§2–3, §5 |
| **depende de** | [INT-003-02](INT-003-02-shell-reads-site-layout.md) (feita) |
| **primo** | controller fino + presenter de lista/show |

## Objetivo

`GET /blog` e `GET /blog/{slug}` passam a devolver props Inertia do CMS. O React ainda pode ignorar nesta task.

## Fazer

1. `BlogController@index` / `show` no lugar das closures. Nomes de rota iguais.
2. `BlogPresenter::index()` / `show(Article $article)` — DTO da spec; `PublicMedia`; `CmsHtml::ensureHtml` no `body`.
3. Show só com `published()`. 404 se rascunho ou slug morto.
4. Testes em `tests/Feature/Integracao/`.

## Testes (PHPUnit)

- Seeder: hero `Blog Omni`; destaque `grupo-omni-lanca-i9-auto`; 3 mais lidas; últimas **sem** o slug do destaque; imprensa com os 2 e-mails.
- Show do score: `body` contém `<h2>Por que o score importa?</h2>`; lead e tags do seeder.
- Artigo sem corpo: 200, `body` `''`.
- Draft / inexistente: 404.
- Sem seed: `GET /blog` 200, `ultimas.articles` `[]`.
- `image` `blog/x.webp` → `/storage/blog/x.webp`.

## Fora

Ligar as seções React (task 02). Filament. Home/landings.
