# Mais Conteúdos — Resumo Executivo

> **Versão analisada:** `v6` (com evolução relevante em relação à `v5`)
> **Slug do módulo:** `mais-conteudos` (tabela `modulos`, `id = 54`, `status = 1`)
> **Natureza:** CMS (painel administrativo) + Portal (público)
> **Estado:** migrado v5 -> v6 (funcionalidade estendida com API interna, `display_type`, `custom_icon` e `description`)

---

## 1. Objetivo

"Mais Conteúdos" é o nome que o **CMS** dá a um conjunto de categorias de conteúdo
criadas pelo próprio operador, fora da árvore padrão do portal (Notícias,
Legislação, Publicações, …). Ele permite que a prefeitura crie **seções novas**
(com subseções) e publique conteúdos dentro delas, sem que cada seção precise de um
módulo de software dedicated.

O módulo **não tem tabela própria**: "Mais Conteúdos" é um *recorte* da tabela
`category_contents` — as categorias de topo com `status_create = 0` (criadas pelo
usuário), por oposto às categorias de sistema (`status_create = 1`).

## 2. Efeito / Impacto

| Faixa | Efeito |
|---|---|
| Cidadão | Acessa as seções novas por `/portal/<slug-da-categoria>` (e subníveis), com listagem paginada, filtro por ano e página de conteúdo — renderizadas pelas views genéricas do portal. |
| Prefeitura (CMS) | Menu lateral "Mais Conteúdos" lista as categorias criadas; cada uma abre a gestão de subcategorias e conteúdos; o operador cria categorias pelo CRUD "Categorias de Conteúdo" e publica conteúdo pelo CRUD "Conteúdos". |
| Transparência e legalidade | As seções novas têm o mesmo tratamento das seções de sistema (data de publicação, ordem, status, anexos). |
| Operação técnica | Depende do registry de módulos (`modulos`, `menu_orders`, `resources`), do provider de menu do AdminLTE e do CRUD genérico de conteúdos. |

## 3. Comportamento

- **Definição de "Mais Conteúdos"**: `CategoryContent::where('status_create', 0)->whereNull('category_contents_id')->get()`
  (`v6/app/Providers/MenuServiceProvider.php:31`).
- Ao criar uma categoria pelo CMS, o controller grava **`status_create = 0`**
  (`v6/app/Http/Controllers/Prefecture/CategoryContentController.php:456`): a categoria
  nasce como "Mais Conteúdo".
- O **slug** é gerado com `str_slug($name)`; se já existir para o mesmo pai, recebe o
  prefixo `cat<maxId+1>_`.
- A posição (`order`) é rebalanceada: todas as categorias com `order >= position`
  recebem `+1` (exceto quando o slug é `super-banners`).
- A exclusão só é permitida para categorias com `status_create != 1` e **sem conteúdos**
  vinculados; os itens de menu (`menu_items`) vinculados são removidos antes.
- No portal, as categorias novas são renderizadas pelo `PortalController@contentList`:
  - `/portal/{slug}` → `generic.index` (lista as subcategorias)
  - `/portal/{slug}/{slug2}` → `generic.show` (lista os conteúdos, paginado, com filtro de ano)
  - `/portal/{slug}/{slug2}/{slug3}` → `generic.view` (página do conteúdo)
- Conteúdos de categorias "Mais Conteúdos" são **também** selecionáveis no CRUD
  genérico de conteúdos (`ContentController@create`/`@edit` listam exatamente essas
  categorias).

### Dependência dura

```
Mais Conteúdos  =  menu (MenuServiceProvider)
                +  CategoryContentController (criar/editar/excluir categorias)
                +  ContentController        (publicar conteúdos)
                +  PortalController@contentList (exibir no portal)
```

## 4. Como o Usuário Interage

**Operador (CMS):**

- Menu lateral "Mais Conteúdos" (`plus-square`) → submenu com "Adicionar" e uma entrada
  por categoria criada.
- `/cms/categoria-conteudo` → lista (pills) das categorias de topo criadas.
- `/cms/categoria-conteudo/create` → formulário com Nome e "Categoria Pai" (hierarquia).
- `/cms/categoria-conteudo/{id}` → detalhe da categoria com os conteúdos vinculados.
- `/cms/conteudo/create` → formulário de conteúdo, com o select de categoria preenchido
  apenas com as categorias "Mais Conteúdos" e suas subcategorias.

**Cidadão (portal):** navega até `/portal/<slug>` a partir de menus/breadcrumbs; a
página lista as subcategorias e, ao entrar nelas, os conteúdos paginados (12 por
página) com filtro por ano de publicação.

## 5. Detalhes e Particularidades Técnicas

- Não existe model, controller, view, rota ou tabela **exclusiva** do módulo: tudo é
  reaproveitado de `CategoryContent` + `ContentController` + `CategoryContentController`.
- A exclusão do item de menu do AdminLTE é feita com `has_access("$menu->slug.index")`
  **e** `modulos.status` — o submenu "Mais Conteúdos" depende do item
  `menu_orders.slug = 'categoria-conteudo'`.
- A API interna (`/cms/categories`) usa `Sentinel::check()` como autorização e devolve
  `422` com `{"errors": {...}}` em caso de validação.
- O portal usa a variável `$null` para controlar a exibição do breadcrumb; ela é
  inicializada no controller (documentada em `v6/.agents/docs/mais-conteudos.md`).
- Existe uma view do portal com o bloco "mais-conteudos" **desativado** por
  `@if(false)` (`v6/resources/views/portal/layouts/modelo5/home/transparencia/transparencia-fiscal-grid.blade.php:117`).

## 6. Estrutura de Dados

| Objeto | Descrição |
|---|---|
| `category_contents` | Tabela onde "Mais Conteúdos" vive (recorte `status_create = 0` + `category_contents_id IS NULL`) |
| `contents` | Os conteúdos publicados dentro dessas categorias |
| `archives` / `links` | Anexos e URL dos conteúdos |
| `menu_items` | Itens de menu do portal ligados por `category_contents_id` |
| `modulos` | `id = 54`, `slug = 'mais-conteudos'`, `status = 1` |
| `menu_orders` | `id = 42`, `slug = 'categoria-conteudo'`, `modulo_id = 54` |
| `resources` | `id = 73` (`categoria-conteudo`) e `id = 74` (`conteudo`), `modulo_id = 54` |

## 7. Como Testar

1. Criar uma categoria em `/cms/categoria-conteudo/create` → ela aparece no submenu
   "Mais Conteúdos" e na lista de categorias.
2. Criar uma subcategoria → aparece na listagem do portal.
3. Publicar um conteúdo nessa categoria → visível em `/portal/<slug>/<subslug>`.
4. Reordenar as categorias (drag & drop) → a ordem persiste.
5. Excluir uma categoria com conteúdos → mensagem "não pode ser excluída".
6. `GET /cms/categories/{slug}` → JSON da categoria.

## 8. Migração para Laravel Moderno

`Category` como model dedicado com `parent_id` (auto-relação), `is_system` (substitui
`status_create`), `slug` único por pai, `Policy` para autorização, `FormRequest` com
regras condicionais por tipo de pai, `JsonResource` para a API, `Livewire` para a
ordenação por drag & drop e componentes Blade `<x-admin.category-tree>` e
`<x-portal.generic-section>`.

## 9. Resumo Geral

"Mais Conteúdos" é um rótulo de negócio aplicado a um **recorte de dados**, não um
módulo de software. As categorias que o compõem são as linhas de `category_contents`
com `status_create = 0` e sem categoria pai — exatamente aquelas que o operador cria
pelo CRUD "Categorias de Conteúdo" (`CategoryContentController`) e que, por isso,
aparecem no submenu "Mais Conteúdos" do AdminLTE (`MenuServiceProvider`). Os conteúdos
dessas seções são publicados pelo CRUD genérico de conteúdos e exibidos no portal pelo
`PortalController@contentList`, que resolve as views genéricas `generic.index`,
`generic.show` e `generic.view` conforme a profundidade do slug. A v6 ampliou o módulo
com uma API interna (`/cms/categories`), com os campos `display_type`, `custom_icon` e
`description` na tabela `category_contents` e com regras de validação condicionais por
categoria pai. A dependência com o módulo de menus é **dura**: sem o item
`menu_orders.slug = 'categoria-conteudo'` (ligado ao módulo `mais-conteudos`), o
submenu não aparece.

---

## Í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, resources |
| `04-VIEWS-E-UX.md` | Telas, componentes, JS, assets |
| `05-REGRAS-E-PORTABILIDADE.md` | Particularidades 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, riscos, comparativo v5 vs v6 |
