# A Instituição — Resumo Executivo

> **Versão analisada:** `v6` (Laravel 5.5.50) e `v5` (versão anterior, mesmo código com nomenclatura `a-prefeitura`)
> **Slug do módulo:** `a-instituicao` (tabela `modulos`, id 12; `resources.slug` e `menu_orders.slug` apontam para ele)
> **Categoria de conteúdo:** `category_contents.id = 6`, `name = 'A Instituição'`, `slug = 'a-instituicao'`, `category_contents_id = NULL`
> **Natureza:** CMS (painel administrativo) + Portal (público)
> **Estado:** migrado v5 → v6 (renomeado de "A Prefeitura" para "A Instituição")

---

## 1. Objetivo

O módulo **A Instituição** é a página institucional do município: o lugar onde a
prefeitura publica quem é o prefeito, o vice-prefeito, a localização, o texto
"sobre" e demais informações sobre a própria administração. Ele existe para que
o cidadão encontre, em um único endereço estável, as informações básicas sobre o
governo municipal, sem precisar procurar emambe, em folders ou em documentos
avulsos. O mesmo conteúdo é publicado em dois lugares: a listagem administrada
pelo CMS (que o operador mantém) e a página pública do portal (que o cidadão lê).

## 2. Efeito / Impacto

| Faixa | Efeito |
|---|---|
| Cidadão | Acessa `https://<dominio>/a-instituicao/<slug>` e lê título, texto rico, imagem de destaque, galeria de fotos, vídeo do YouTube e as últimas notícias vinculadas. O contador de cliques do conteúdo é incrementado a cada visita. |
| Prefeitura (CMS) | Mantém, no menu **Conteúdos → A Instituição**, uma lista de páginas institucionais; o operador cria/edita/exclui, define galeria e vídeo, e o botão "Acessar Instituto" abre a página pública correspondente. |
| Transparência e legalidade | É o canal oficial de identificação dos agentes e de exposição institucional; erros de URL (ver seção 8) expõem o município a link quebrado e a erro 500 no roteamento. |
| Operação técnica | O módulo depende de view SQL `a_instituicao`, da categoria `category_contents` id 6 e do nome de rota `a-instituicao.index` — todos com acoplamiento frágil (IDs e nomes de rota). |

## 3. Comportamento

- O CMS resolve a tela pelo **slug do módulo**, não por id: `ContentController@genericIndex`
  mapeia `'a-instituicao'` para a view `prefecture.contents.a-instituicao.index`
  (`v6/app/Http/Controllers/Prefecture/ContentController.php:91`).
- A grade do CMS é alimentada pela **view SQL `a_instituicao`** (`value, titulo, id, galeria, slug`),
  não pela tabela `contents` diretamente (`v6/app/Http/Controllers/Prefecture/DatatableController.php:252-256`).
- O formulário de criação/edição é o mesmo componente Blade `form.blade.php` compartilhado
  por create/edit; o campo "Link Permanente" é o `slug` do conteúdo.
- A validação do formulário é feita por `ContentRequest`, no `case 'a-instituicao'`
  (`v6/app/Http/Requests/ContentRequest.php:230-237`).
- O portal resolve a página por `slug` do conteúdo: `GET /a-instituicao/{slug}` →
  `Portal\PrefectureController@getIndex` (`v6/app/Http/Controllers/Portal/PrefectureController.php:29`).
- O controller decide a view a partir da **categoria do conteúdo**:
  `secretarias` → view de secretaria; `orgaos` → view institucional com `sidenews`;
  demais casos (incluindo `a-instituicao`) → view institucional com `news_secretary`.
- O breadcrumb é registrado por **slug da categoria** (`v6/routes/breadcrumbs.php:200-204`).
- O menu do portal, quando o item aponta para um conteúdo, tem a URL calculada por
  `MenuItemPresenter::getLink()`, que decide por **id de categoria**
  (`v6/app/Http/Presenters/MenuItemPresenter.php:22-45`).

## 4. Como o Usuário Interage

### Operador (CMS)

| Ação | Tela | Resultado |
|---|---|---|
| Abrir listagem | `GET /cms/conteudos/a-instituicao` | Tabela "Lista de conteudos da Instituição" com colunas `#`, `ID`, `Título`, `Ações`. |
| Filtrar/buscar | campo de busca do DataTable | Filtro **no cliente** (o servidor devolve a view inteira). |
| Exportar | botões Excel / PDF do DataTable | Exporta as colunas visíveis, exceto "Ações". |
| Acessar Instituto | botão de link na coluna Ações | Abre `/a-instituicao/<slug>` em nova aba. |
| Editar | botão de lápis | `GET /cms/conteudos/editar/a-instituicao/<id>` (rota genérica `editar-conteudo`). |
| Galeria | botão de galeria | `editar/a-instituicao/<id>#galeria` — abre a aba de galeria do formulário. |
| Excluir | botão de lixeira | `DELETE /cms/conteudo/<id>`; o controller remove também os `menu_items` apontando para o conteúdo. |
| Excluir em lote | "Excluir selecionados" | `POST /cms/ajax/generic/content/deleteAll`. |
| Cadastrar | botão "Cadastrar Conteúdo" | `GET /cms/conteudos/cadastrar/a-instituicao`. |

### Cidadão (portal)

1. Acessa `https://<dominio>/a-instituicao/<slug>`.
2. Vê o breadcrumb `Home > A Instituição > <título>`.
3. Vê a imagem de destaque, o texto rico, o bloco de compartilhamento (WhatsApp, Facebook,
   copiar link, e-mail, imprimir), a galeria (lightgallery) se `galery = 1`, o vídeo do
   YouTube se houver `link`, e as "Últimas notícias" (6 por página, paginadas).
4. Na coluna lateral: transmissão, banners, clima, enquetes, mais populares, VLibras,
   newsletter e o bloco "Notícias de <título>".

## 5. Detalhes e Particularidades Técnicas

- **Camadas:** `Route` → middleware (`check.route.permission` no CMS) → `Controller`
  → `ContentRequest` → `Content`/`CategoryContent` (Eloquent direto, sem repository
  no caminho de leitura do portal) → view Blade.
- **Nome de rota duplicado:** `v6/routes/web.php:79-80` registra `a-instituicao/{slug}` e
  `a-instituicao/secretarias/{slug}` **com o mesmo nome** `a-instituicao.index`.
- **Rota inexistente:** `v6/app/Http/Controllers/Portal/PortalController.php:332` chama
  `route('a-instituicao-secretarias.index', ...)`, nome que **não existe** na v6.
- **Bug do formulário:** `v6/resources/views/prefecture/contents/a-instituicao/form.blade.php:21`
  e `:30` usam `url('a-cidade')` e `route('a-cidade.index', ...)` — cópia do formulário
  de A Cidade.
- **Acoplamento por ID:** `MenuItemPresenter` decide a URL do menu por
  `category_contents.id` (7 = Secretarias, 32 = Órgãos, 12 = Perguntas Frequentes).
- **Relação invertida:** `Content::secretarias()` usa `localKey = 'slug'`
  (`v6/app/Http/Model/Prefecture/Content.php:72-75`), ou seja, liga a notícia ao
  **slug** da secretaria, não ao id.
- **Autorização duplicada:** `ContentRequest::authorize()` devolve `true`
  (`v6/app/Http/Requests/ContentRequest.php:19-22`); quem protege é o middleware
  `check.route.permission` e o `has_access()` das views.
- **Layout ativo:** `getTemplateActived()` (`v6/app/Http/Traits/GetInformationsPrefectureTrait.php:92-102`)
  lê `configurations.key = 'layout'` e faz `abort(404)` se
  `portal.layouts.<layout>.home.index` não existir — na prática só `modelo1..modelo6`
  funcionam; `default` e `newsbit` são inalcançáveis.

## 6. Estrutura de Dados

| Objeto | Tipo | Papel |
|---|---|---|
| `contents` | tabela | Armazena os textos institucionais (título, texto, slug, galery, clicks, `category_contents_id`). |
| `category_contents` | tabela | Categoria id 6 = "A Instituição" (`slug = a-instituicao`, pai `NULL`). |
| `archives` | tabela | Imagem de destaque (`highlight = 1`), galeria (`highlight IS NULL`) e demais anexos. |
| `links` | tabela | Link do vídeo (relação 1:1 `Content::linksUnique()`). |
| `menu_items` | tabela | Itens de menu do portal que podem apontar para um conteúdo. |
| `menu_orders` | tabela | Slug `a-instituicao` (id 11, `modulo_id = 12`) — contador de cliques do menu. |
| `resources` | tabela | Slug `a-instituicao` (id 13, `modulo_id = 12`) — entrada do menu do CMS. |
| `modulos` | tabela | id 12, `name = 'A Instituição'`, `status = true` — habilita a entrada do menu lateral. |
| `a_instituicao` | **view SQL** | `value, titulo, id, galeria, slug` — fonte da grade do CMS. |

Estado atual do banco (consulta de leitura): **5 conteúdos** na categoria 6 —
`Prefeito`, `Vice-prefeito`, `Aspectos Gerais`, `Localização`, `Sobre`.

## 7. Como Testar

| Cenário | Como verificar |
|---|---|
| Listagem do CMS | `GET /cms/conteudos/a-instituicao` como `administrador` → tabela com 5 linhas. |
| Grade | `GET /cms/datatable/a_instituicao` → JSON com `value, titulo, id, galeria, slug, edit, delete, active, inactivate`. |
| Criação | `POST /cms/conteudo` com `title`, `text`, `category_contents_id = 6` → slug gerado por `Str::slug`; colisão vira `slug-<maxid+1>`. |
| Validação | Título vazio → "Por favor, informe um título."; texto vazio → "Por favor, digite algum texto."; imagem > 20 MB → erro de `archive_highlight`. |
| Página pública | `GET /a-instituicao/sobre` → 200 com título e texto; `contents.clicks` incrementa em 1. |
| Roteamento legado | `GET /portal/a-instituicao/sobre` → 302 para `/a-instituicao/secretarias/sobre` (efeito do nome duplicado). |
| Bootstrap inexistente | `GET /a-instituicao/nao-existe` → 404 / view "conteúdo não encontrado". |

Detalhe dos casos em `07-TESTES.md`.

## 8. Migração para Laravel Moderno

Reconstruir como um recurso REST dedicado (`InstituicaoContent`) em vez de um
`ContentController` genérico dirigido por slug: model `Instituicao` com
`HasFactory`, Form Request dedicada, Policy `InstituicaoPolicy` ligando
`a-instituicao.index/.create/.edit/.delete` aos papéis, route model binding por
`{conteudo:slug}`, API Resource JSON (o módulo hoje **não tem** endpoint de dados
abertos) e Blade em componentes `<x-*>`. O item de menu deve ser resolvido por
**chave de negócio** (`category_contents.slug`), nunca por id. Detalhes em
`06-MIGRACAO-MODERNA.md`.

## 9. Resumo Geral

"A Instituição" é o módulo institucional do portal municipal: um conjunto de
páginas curtas (prefeito, vice-prefeito, sobre, localização) mantidas pelo CMS e
publicadas no endereço `/a-instituicao/{slug}`. Na v6 ele nasceu como "A Prefeitura"
(v5) e foi renomeado por seeds, e não por migration — a view SQL `a_prefeitura`
(v5) virou `a_instituicao` (v6) e a coluna `slug` foi acrescentada à view em
migration posterior. O módulo é tecnicamente simples (uma tabela `contents`, uma
view SQL, um controller genérico), mas carrega quatro acoplamentos frágeis que
precisam ser resolvidos na reconstrução: nome de rota duplicado, rota de
secretarias inexistente, formulário apontando para `a-cidade` e decisão de URL de
menu por id de categoria. Não há API pública para o módulo. A lista de
notícias exibida ao lado é paginada no servidor e renderizada duas vezes, e a
grade do CMS carrega a view inteira em memória — ambos são riscos de
performance a tratar na v7.

---

## Índice do dossiê

| Arquivo | Conteúdo |
|---|---|
| `00-RESUMO.md` | Este documento |
| `01-ARQUITETURA.md` | Camadas, classes e o diagrama de fluxo |
| `02-MODELAGEM.md` | Estrutura de dados detalhada |
| `03-ROTAS-E-CONTROLADORES.md` | Rotas, controllers, requests, permissões |
| `04-VIEWS-E-UX.md` | Telas, componentes, JS, assets |
| `05-REGRAS-E-PORTABILIDADE.md` | Regras, riscos de performance e armadilhas |
| `06-MIGRACAO-MODERNA.md` | Plano de reconstrução em Laravel moderno |
| `07-TESTES.md` | Estratégia e casos de teste |
| `08-GAPS-E-DIVIDAS.md` | Pendências, bugs, mapa v5 → v6 e riscos de dados |
