# P14 — Módulos institucionais e identidade local

| Campo | Valor |
|---|---|
| Programa | F7+ — operação, estrutura e conteúdo |
| Status | `planejado` |
| Depende de | P5, P9, P10, P12 |
| Habilita | P15, P18, P19 |
| Tamanho | **G** (5–7 sessões) |
| ADRs | ADR-012, ADR-014, ADR-016/017, ADR-019, ADR-026/027, ADR-033, ADR-035 |

## 1. Objetivo

Implementar os módulos **institucionais** que dão rosto ao município — A Instituição, A Cidade,
Secretarias, Órgãos, Unidades de Atendimento, Telefones Úteis, Redes Sociais, Glossário, FAQ e
Feriados — reusando páginas/blocos (P5), Media (ADR-026), AST (ADR-028), busca (P9) e SEO (ADR-027).

**Resultado observável:** o cidadão encontra a estrutura administrativa, os contatos e as
informações institucionais no portal; o operador mantém tudo pelo CMS sem deploy; cada item aparece
na busca e no sitemap; nenhum dado sensível é exposto.

## 2. Escopo fechado

### S1 — A Instituição + A Cidade

- Não há um módulo `Portal/Institucional` único: são dois módulos separados, como no corpus, com
  tokens `a_instituicao` e `a_cidade` (grep-friendly, ADR-004). Cada um usa `<x-layout::portal>` e
  só o `<main>`.
- `a_instituicao`:
  - tabela `institution_authorities`: `id`, `name`, `role` (jsonb i18n), `photo_id` (Media),
    `bio` (AST jsonb), `position`, `active`, timestamps; autoridades (prefeito, vice, secretários)
    sem partido/CPF.
  - **PNTP 2.1:** página de estrutura com organograma em HTML (lista aninhada) + **norma que
    institui/altera** (Media/PDF pesquisável) + `estrutura_atualizada_em`; settings
    `institution.estrutura_norma_media_id`, `institution.estrutura_norma_url`. A norma também é
    linkada ao ato no P10; não duplicar o repositório.
  - seções institucionais (história, missão, competências) como **páginas/blocos** do P5; o módulo
    registra um `SearchSource`/`SitemapSource` para o que for conteúdo próprio.
  - portal `/a-instituicao` e `/a-instituicao/{slug}`; CMS `/cms/a-instituicao`.
  - **PNTP 2.6:** atos normativos são uma visão filtrada de P10 (`/legislacao?tipo=...`); P14 linka,
    não cria segundo repositório.
  - **PNTP 2.9:** `institution.radar_url` (default oficial) e link visível no header/footer; P26
    entrega o componente.
- `a_cidade`:
  - tabela `city_facts`: `id`, `label` (jsonb), `value` (texto/JSON validado), `position`, `active`
    (população, área, fundação, gentílico — dado, não HTML).
  - seções (história, mapa, hino, aspectos gerais) via páginas/blocos; galeria via Media.
  - portal `/a-cidade`; CMS `/cms/a-cidade`.
- Permissões `a_instituicao.ver/editar`, `a_cidade.ver/editar`; conteúdo traduzível (LocaleCast).

### S2 — Secretarias + Órgãos

- Módulo `Institucional/Secretarias` (token `secretarias`):
  - `secretarias`: `id`, `slug` único, `nome` jsonb, `sigla`, `responsavel`, `email`, `telefone`,
    `endereco`, `expediente`, `competencias` (AST), `position`, `active`, timestamps.
  - `secretaria_departamentos`: `id`, `secretaria_id` FK cascade, `nome` jsonb, `responsavel`,
    `contato`, `position`, `active`; até 2 níveis (secretaria → departamento), sem árvore livre.
  - portal `/secretarias` e `/secretarias/{slug}`; CMS CRUD; busca/sitemap.
- Módulo `Institucional/Orgaos` (token `orgaos`):
  - `orgaos`: `id`, `slug`, `nome` jsonb, `sigla`, `tipo` enum (`prefeitura|secretaria|autarquia|
    fundacao|conselho|outro`), `responsavel`, `email`, `telefone`, `endereco`, `expediente`,
    `competencias` (AST), `position`, `active`.
  - portal `/orgaos` e `/orgaos/{slug}`; CMS; busca/sitemap.
- Regra de não duplicação: Órgãos é o cadastro institucional; Secretarias é o organograma
  administrativo. Se um órgão for uma secretaria, referencie o slug (sem copiar contato em dois
  lugares) — decisão de campo `secretaria_id` nullable em `orgaos` ou um `orgao_id` em
  `secretarias`. Implementar **uma** direção: `secretarias.orgao_id` nullable, FK; a tela mostra o
  vínculo, não duplica contato.
- Ambas as listas com filtro por tipo/ativo, ordenação `position, nome`, paginação; sem N+1.

### S3 — Unidades de Atendimento + Telefones Úteis + Redes Sociais

- `Institucional/UnidadesAtendimento` (token `unidades_atendimento`):
  - `unidades_atendimento`: `id`, `slug`, `nome` jsonb, `tipo` enum, `endereco`, `telefone`,
    `email`, `expediente`, `servicos` (lista de ids/slugs de Carta de Serviços, quando existir),
    `acessibilidade` (lista fechada: rampa, elevador, libras, braille…), `latitude`/`longitude`
    nullable (apenas link “ver no mapa”, **sem** iframe de terceiro), `position`, `active`.
  - portal lista/filtro por tipo/serviço; detalhe; CMS CRUD; sitemap.
- `Institucional/TelefonesUteis` (token `telefones_uteis`):
  - `telefones_uteis`: `id`, `nome` jsonb, `setor`, `telefone`, `whatsapp` (link `https://wa.me/...`
    validado), `position`, `active`; portal em lista/tabela; CMS.
- `Institucional/RedesSociais` (token `redes_sociais`):
  - `redes_sociais`: `id`, `rede` enum (Instagram, Facebook, YouTube, X, TikTok, LinkedIn, outra),
    `url` (https validado), `rotulo` jsonb, `position`, `active`; render no header/footer via
    componente do layout; CMS.
  - Nenhum ícone de terceiro: usar Lucide/Simple Icons vendorizados (ADR-010); link externo com
    `rel="noopener noreferrer"` e rótulo acessível.
- Todas as telas com estado vazio, confirmação de desativação e auditoria.

### S4 — Glossário + Perguntas Frequentes + Feriados

- `Institucional/Glossario` (token `glossario`):
  - `glossario_termos`: `id`, `slug` único, `termo` jsonb, `definicao` (AST), `letra` gerada/derivada,
    `active`, timestamps; portal A–Z com filtro por letra; CMS; busca/sitemap.
- `Institucional/PerguntasFrequentes` (token `perguntas_frequentes`):
  - `faq_categorias` + `faq_perguntas`: pergunta/resposta (AST), `position`, `active`; portal com
    `<details>/<summary>` (funciona sem JS), busca; CMS.
- `Institucional/Feriados` (token `feriados`):
  - `feriados`: `id`, `data` (date), `nome` jsonb, `tipo` enum (`nacional|estadual|municipal|ponto_facultativo`),
    `recorrente` bool (mês/dia), `active`; seed idempotente dos feriados de referência (ADR-041/017);
    portal lista por ano; CMS; **consumido por P11/P16** para prazos (porta Core ou consulta
    explícita; não acoplar módulo a módulo).
- Nenhuma view usa HTML/CSS do banco; respostas em AST.

### S5 — Integração, busca, sitemap e fechamento

- Cada módulo registra `SitemapSource` (se tiver URL pública) e `SearchSource` (P9) para indexar
  título/resumo/texto derivado do AST; nenhum índice paralelo.
- Cross-links: Órgãos ↔ Secretarias; Unidades ↔ Carta de Serviços (P15); Telefones ↔ Órgãos.
  Links internos com `route()`/`localized_url()` (ADR-012).
- Menu do portal: itens institucionais vêm do módulo `Menus` (P1); nada hardcoded.
- E2E: criar/editar cada tipo, conferir portal, busca, sitemap, 4 locales, axe.
- `make check` 2× + `E2E=1`; cobertura ≥90%; PHPStan max 0.

## 3. Fora de escopo

- Portal da transparência (P12), publicações (P15), pessoas (P16), obras (P17).
- Mapas embutidos/iframes de terceiros; geocoding externo.
- Estrutura organizacional ilimitada/árvore arbitrária (máx. 2 níveis).
- Conteúdo editorial longo: usar páginas/blocos (P5).
- Integração com RH/folha.

## 4. Fatias de sessão

| Sessão | Entrega | Prova | Depende |
|---|---|---|---|
| **P14.S1** | A Instituição + A Cidade | portal/CMS; autoridades; fatos; 4 locales | P5/P9 |
| **P14.S2** | Secretarias + Órgãos | vínculo sem duplicar contato; listas/detalhes | S1 |
| **P14.S3** | Unidades + Telefones + Redes | filtros; link de mapa sem iframe; ícones vendorizados | S2 |
| **P14.S4** | Glossário + FAQ + Feriados | A–Z; `<details>`; seed idempotente | S2 |
| **P14.S5** | busca/sitemap/cross-links + E2E | índice único; sem link morto; axe; 2× check | S1–S4 |

## 5. DoD

- [ ] Todos os módulos com portal + CMS, permissões e auditoria.
- [ ] Conteúdo em AST/jsonb; nenhum HTML/CSS no banco; imagens via Media.
- [ ] Busca/sitemap integrados; nenhum índice paralelo.
- [ ] Sem iframe/asset de terceiro; mapas apenas por link.
- [ ] 4 locales; acessibilidade (axe zero A/AA); teclado; alvos ≥2.75rem.
- [ ] `make check` 2× + `E2E=1`; cobertura ≥90%; PHPStan max 0.
- [ ] PNTP 2.1: organograma + norma + data; 2.6: atos via P10; 2.9: Radar; 1.3: link visível.
- [ ] 2.2–2.5, 2.7–2.8 com página/CMS; sem link morto.

## Fechamento — ficha de revisão

> **Obrigatório antes de fechar:** criar `_to_revision/P14-institucional.md` e seguir
> `_to_revision/README.md` + `_to_revision/PROTOCOLO.md` (v2.0). A ficha não é gate de build; é a
> entrada da fila de revisão profunda.

- Cabeçalho: fase, `kd` épico/tasks/slices, âncoras (este arquivo, ADRs e código) e status
  `⬜ pendente` → `🟡 em revisão` → `✅ revisado` / `🔧 com correções`.
- Conteúdo: o que foi implementado, arquivos/superfícies a revisar, checklist D1–D14 aplicável,
  riscos e observações.
- Fechamento: preencher “Notas da revisão” com data/revisor/resultado e achados (`kd write
  --anchor`), atualizar a fila em `_to_revision/README.md` e `_to_revision/_inventario.md`.
- Achado com correção exige teste vermelho→verde; a fase só é `closed` no `kd` com a ficha
  registrada.

## 6. Riscos

| Risco | Mitigação |
|---|---|
| Duplicar contato em Órgãos/Secretarias | FK/vínculo único; teste de não duplicação |
| Conteúdo institucional virar HTML | AST + schema; teste que rejeita HTML |
| Mapa/iframe de terceiro | link externo; sem embed (ADR-002) |
| Dado pessoal exposto (responsável) | campo público mínimo; auditoria; LGPD |
| N+1 em listas | eager loading/`whereIn`; teste de query count |
| Feriados divergentes | seed idempotente + fonte única; teste de ano |

## 7. Retomada

```bash
kd prime
kd ask "a-instituicao a-cidade secretarias orgaos unidades telefones glossario faq feriados"
kd task list --ready
```

Ler: `dossie_modules/{a-instituicao,a-cidade,secretarias,orgaos,unidades-de-atendimento,telefones-uteis,redes-sociais,glossario,perguntas-frequentes,feriados-municipais}/**`
→ `MODULOS.md` §1/P14 → P5 (páginas/blocos) → P9 (search/sitemap).
