# Menus do Site — Resumo Executivo

> **Versão analisada:** `v6` (módulo também presente na `v5`, com diferenças — ver `08-GAPS-E-DIVIDAS.md`)
> **Slug do módulo:** `menus-do-site` (tabela `modulos`, id 31)
> **Natureza:** CMS (painel administrativo) + Portal (público)
> **Estado:** migrado v5 -> v6, com funcionalidade acrescentada (mega menu, ativação/desativação de itens, seletor de módulo no editor de layout)

---

## 1. Objetivo

O módulo é o construtor da navegação do portal municipal. Ele permite ao operador
criar "menus" (agrupadores de navegação, como *Principal*, *Rodapé*, *Acesso Rápido*
e *Atalhos*), cadastrar **itens de menu** aninhados em até 3 níveis, escolher o
destino de cada item (link personalizado, página estática, categoria de conteúdo ou
conteúdo), reordenar tudo por *drag and drop* e ativar/desativar itens individualmente
sem precisar tirá-los do banco.

É a camada que o cidadão enxerga: o cabeçalho, o rodapé, o menu de acesso rápido e a
"barra de atalhos" do portal são todos gerados a partir de `menu_items`.

---

## 2. Efeito / Impacto

| Faixa | Efeito |
|---|---|
| Cidadão | A navegação do portal (menu principal, rodapé, acesso rápido, atalhos) é definida pelo CMS; itens podem ser ocultados sem remoção definitiva |
| Prefeitura (CMS) | Tela "Menus do site" lista os menus; a "Ajustar itens" abre a árvore de itens com ordenação por arrasto, ícone, item pai e tipo de destino |
| Transparência e legalidade | Itens desativados somem do portal mas continuam no banco e no log de atividades (`activity()`), preservando rastreabilidade |
| Operação técnica | A navegação é reconstruída a cada requisição via *view composer* (`MenuServiceProvider`), sem cache — mudanças do CMS refletem imediatamente no portal |

---

## 3. Comportamento

- Um **Menu** (`menus`) é um agrupador nomeado, com `slug` gerado automaticamente a
  partir do nome (`str_slug`), `status_create` booleano e *soft delete*.
- Um **MenuItem** (`menu_items`) pertence a um menu (`menus_id`) e, opcionalmente,
  a um item pai (`menus_items_id`). `menus_items_id IS NULL` = item raiz.
- O **tipo** (`type`) define o destino renderizado pelo `MenuItemPresenter`:
  `0` = link personalizado (cria um registro em `links`), `1` = página estática,
  `2` = categoria de conteúdo (opcionalmente um conteúdo dentro dela).
- Itens do tipo `0` criam **automaticamente** uma linha em `links` (via
  `MenuItemRepository::structureUpInsert`).
- Itens do tipo `2` aceitam `sub_category_contents_id`, que sobrescreve
  `category_contents_id`.
- A ordenação é feita por *drag and drop* (jQuery UI Sortable) e gravada no campo
  `order`, com renumeração sequencial de 1 em 1.
- A ativação/desativação é um `POST` que inverte `is_active` (default `true`).
- O limite de **6 itens raiz por menu** é validado no `MenuItemRequest`: ao atingir
  6, `menus_items_id` passa a ser obrigatório (o item precisa ser filho de outro).
- A exclusão de um item **pai** é bloqueada se existirem subitens; a tentativa é
  registrada no log.
- A exclusão de um **Menu** faz *soft delete*; os `menu_items` órfãos permanecem no banco.

---

## 4. Como o Usuário Interage

**Operador (CMS, `/cms/menu`)**

1. DataTable com os menus existentes (fonte: view SQL `menus_site`), botões
   "Editar" e "Ajustar itens" (`/cms/menu-item/{id}`).
2. Tela de itens: formulário à esquerda (nome, sobrenome, ícone, tipo de link,
   item pai, "abrir em nova guia") e árvore arrastável à direita (3 níveis
   materializados por *foreach* aninhados no Blade).
3. Ao escolher "Conteúdo (Categorias)", um `POST` em
   `/cms/get/subcategory/by/category` devolve subcategorias ou conteúdos para o
   segundo select.
4. Ao escolher um item pai, um `POST` em `/cms/get/qtd-subitems/by/item` devolve a
   quantidade de filhos (usado apenas para feedback, não bloqueia a ação).
5. O interruptor liga/desliga cada item via `POST /menu-item/{id}/toggle`.

**Cidadão (portal)**

- Menu principal: `menus_id = 1` (itens raiz + até 2 subníveis), renderizado por
  cada layout (`modelo1`..`modelo6`), com filtro `is_active = true`.
- Menu de rodapé: `menus_id = 2` e, no modelo1..4, parte de `menus_id = 1`
  (`FooterServiceProvider`).
- Acesso rápido: `menus_id = 3`, apenas itens ativos.
- Atalhos do topo: `menus_id = 4`, somente `id`, `name`, `links_id` (usados por
  nome: "Telefones", "Ouvidoria", "Contato", "Acessibilidade").
- No layout `modelo5`, o editor permite escolher um menu para virar a grade
  "Serviços" da home (ver `09-TAGS-DE-MENU.md`).

---

## 5. Detalhes e Particularidades Técnicas

- Camadas: `Route` -> `Middleware (check.route.permission)` -> `Controller` ->
  `FormRequest` -> `Repository` (`upInsert`) -> `Model` -> `DB`; a listagem do CMS
  usa `DatatableController` sobre a view `menus_site`.
- A navegação do portal é montada por *view composer* em
  `v6/app/Providers/MenuServiceProvider.php`, que roda **a cada requisição** do
  portal e carrega `menu_items` com `subItens` aninhado.
- O *presenter* (`MenuItemPresenter`) decide a URL final; há `if` hardcoded por
  `category_contents_id` (2 = legislação, 3 = publicações, 7 e 32 = a-instituicao,
  12 = acesso-rapido) e por `static_pages_id = 4`.
- `Menu::menuItems()` está declarado como `belongsTo` — está errado conceitualmente
  (deveria ser `hasMany`); nenhum código do módulo usa essa relação.
- `MenuItem` tem a coluna `deleted_at` mas o `use SoftDeletes;` está comentado:
  a remoção é física.
- A rota `menu-item-by-menu` aponta para `MenuItemController@createByMenu`, método
  **inexistente** — 404/500 garantido.
- A rota `menu-item.toggle` está registrada em `v6/routes/web.php` (grupo público,
  apenas `check.site.manutention`), sem exigir login.

---

## 6. Estrutura de Dados

| Tabela | Papel | Colunas-chave |
|---|---|---|
| `menus` | Agrupadores de navegação | `id`, `name`, `slug`, `status_create`, `deleted_at` |
| `menu_items` | Itens da navegação | `id`, `order`, `name`, `menus_id`, `menus_items_id`, `type`, `links_id`, `static_pages_id`, `category_contents_id`, `contents_id`, `icon`, `second_name`, `is_active`, `is_mega_menu` |
| `menu_orders` | Ordem dos módulos no menu do CMS + contador de acessos | `id`, `slug`, `clicks`, `modulo_id` |
| `links` | Destino dos itens tipo 0 | `id`, `link`, `title`, `isBlank` |
| `modulos` | Catálogo de módulos do CMS | `id` = 31 (`menus-do-site`) |
| `resources` | Recurso do CMS | id 35, `slug = menus-do-site`, `modulo_id = 31` |

View SQL: `menus_site` (menu 31 = `menus_site`, criado por
`v6/database/migrations/2023_04_13_151009_create_view_to_menus.php`) — ordena por
`status_create IS TRUE DESC` e filtra `deleted_at IS NULL`.

Detalhe completo em `02-MODELAGEM.md` e `10-MIGRATIONS-MENU.md`.

---

## 7. Como Testar

Cenários mínimos para validar o módulo:

1. Criar menu, item raiz e subitem; conferir árvore no CMS e no portal.
2. Arrastar item e recarregar: a ordem persistiu.
3. Alternar o interruptor: item some/volta do portal.
4. Excluir item com filhos: operação negada com aviso.
5. Atingir 6 itens raiz: o próximo cadastro exige item pai.
6. Item tipo 0: o registro correspondente em `links` foi criado.
7. Menu com `status_create = false`: aparece por último na listagem.

Plano detalhado em `07-TESTES.md`.

---

## 8. Migração para Laravel Moderno

Reconstrução com Eloquent enxuto, `FormRequest` dedicado, `Policy` para
autorização, *enum* para `type`, `API Resource` para leitura dos itens e
componente Blade para a árvore arrastável. O `order` deve virar numeração
contínua por menu (índice composto), a árvore deve ser carregada em uma única
consulta recursiva e o *presenter* deve virar um `LinkResolver` puro e testável.
Riscos de equivalência funcional (limite de 6 itens, tipagem do destino, item
pai obrigatório, `is_active` como chave de exibição) estão em
`06-MIGRACAO-MODERNA.md`.

---

## 9. Resumo Geral

O módulo `menus-do-site` é a engrenagem de navegação do portal: define quais
menus existem, quais itens cada menu tem, em que ordem aparecem, para onde cada
item aponta e se ele está visível. No CMS, o operador trabalha em duas telas —
a lista de menus (DataTable sobre a view `menus_site`) e a tela de itens, onde a
a árvore é arrastável e os destinos são escolhidos por tipo (link, página estática,
categoria/conteúdo). No portal, a navegação é injetada em todas as páginas por
`MenuServiceProvider` (menu principal, rodapé, acesso rápido e atalhos), e o
layout `modelo5` permite transformar um menu arbitrário na grade "Serviços" da
home. A reconstrução em Laravel moderno precisa preservar exatamente o contrato
observável: a regra dos 6 itens raiz, a semântica de `type`, o
`is_active` como mecanismo de ocultação sem exclusão, a ordem persistida e a
semântica de `target=_blank` derivada de `isBlank`.

---

## Í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, presenters |
| `04-VIEWS-E-UX.md` | Telas, componentes, JS, assets |
| `05-REGRAS-E-PORTABILIDADE.md` | Particularidades e armadilhas |
| `06-MIGRACAO-MODERNA.md` | Plano de reconstrucao: schema, modelos, resolucao de URL, Form Requests |
| `07-TESTES.md` | Estrategia e casos de teste |
| `08-GAPS-E-DIVIDAS.md` | Pendencias, riscos, comparativo v5 vs v6 |
| `09-TAGS-DE-MENU.md` | Menu "Tags", seletor de modulo e integracao com o editor de layout |
| `10-MIGRATIONS-MENU.md` | Inventario das migrations que afetam as tabelas do modulo |
| `11-MIGRACAO-MODERNA-PARTE-2.md` | Complemento do plano: Policies, API, views, cache, riscos e checklist |
