# Mais Conteúdos — Gaps, Dívidas e Mapa v5 → v6

## 1. Bugs e erros conhecidos

| # | Severidade | Descrição | Evidência |
|---|---|---|---|
| G1 | **Alta** | As rotas do `Route::resource('categoria-conteudo', ...)` **não** têm o middleware `check.logged`; o `RouteServiceProvider` só aplica o grupo `web`. Diferente de `configuracoes`, que usa `->middleware('check.logged')`. O controller não valida a sessão (apenas a API interna o faz, via `Sentinel::check()`). | `v6/routes/basepro.php:173` × `v6/app/Providers/RouteServiceProvider.php:84-89` |
| G2 | **Alta** | `catch (\Throwable $th) {}` em `PortalController@contentList` engole qualquer erro e devolve resposta vazia com HTTP 200 — mascarou inclusive o bug da variável `$null`. | `v6/app/Http/Controllers/Portal/PortalController.php:366` |
| G3 | Média | Colisão de nomes de rota: `POST /cms/ajust-categorias` usa o nome `categoria-conteudo.edit`, o mesmo gerado pelo `Route::resource` (registrado depois) — a rota POST fica sem nome no registry. | `v6/routes/basepro.php:138` × `:173` |
| G4 | Média | Recursão de `getAllDescendants()` sem proteção contra ciclos: uma categoria apontando para si (permitida pelo formulário) causa recursão infinita. | `v6/app/Http/Model/Prefecture/CategoryContent.php` |
| G5 | Média | `redirect()->route('login')` dentro do listener `BuildingMenu` não redireciona (o `RedirectResponse` é descartado). | `v6/app/Providers/MenuServiceProvider.php:33-34` |
| G6 | Média | A API interna devolve a mensagem do PostgreSQL ao cliente (`'message' => $th->getMessage()`). | `v6/app/Http/Controllers/Prefecture/CategoryContentController.php:884-895` |
| G7 | Média | `CategoryContentRequest` faz `CategoryContent::find($request->get('category_contents_id'))->slug`; se o pai não existir, o acesso a propriedade de `null` gera erro 500. | `v6/app/Http/Requests/CategoryContentRequest.php` |
| G8 | Média | Desambiguação de slug por `CategoryContent::max('id') + 1` — frágil sob concorrência (duas criações simultâneas podem gerar o mesmo slug). | `v6/app/Http/Controllers/Prefecture/CategoryContentController.php:467-471` |
| G9 | Média | `custom_icon` é gravado direto em `public/uploads/icons` (sem `Storage`, sem validação de tipo/tamanho, sem limpeza). | `v6/app/Http/Controllers/Prefecture/CategoryContentController.php:487-497` |
| G10 | Baixa | SQL com interpolação de variáveis no controller do portal (`{$category->id}`). | `v6/app/Http/Controllers/Portal/PortalController.php:361` |
| G11 | Baixa | O bloco do grid de transparência fiscal está morto por `@if(false)`. | `v6/resources/views/portal/layouts/modelo5/home/transparencia/transparencia-fiscal-grid.blade.php:117` |
| G12 | Baixa | O nome do módulo no registry é "Mais Conteudos" (sem acento) e o do menu é "Mais Conteúdos" (com acento). | `v6/database/migrations/2024_11_01_150206_create_modulos_table.php:348` × `v6/app/Providers/MenuServiceProvider.php:314` |
| G13 | Baixa | `getAllDescendants(true)` prefixa o nome do pai, exceto para `publicacoes` e `legislacao` — regra não documentada em lugar nenhum. | `v6/app/Http/Model/Prefecture/CategoryContent.php` |
| G14 | Baixa | `CategoryContent` não tem `$casts`: `status`, `status_create` e `display_type` chegam como `1`/`null`/string do PostgreSQL. | `v6/app/Http/Model/Prefecture/CategoryContent.php` |

## 2. Funcionalidades incompletas ou mortas

| Item | Situação |
|---|---|
| "Mais Conteúdos" como módulo | Não existe: é um rótulo sobre um recorte de `category_contents` |
| Base `prefeituras_v5` | Nenhuma categoria com `status_create = false` → o submenu do CMS está **vazio** no ambiente analisado |
| Bloco `@if(false)` do modelo 5 | Código morto (grid de transparência) |
| `description` | Aplicada apenas a `transparencia-fiscal`; inútil para as demais categorias |
| `custom_icon` | Gravado, mas o consumo no portal não foi located em nenhum provider/Blade do módulo |
| `display_type` | Só consumido pela Transparência (`grouped`/`direct`) |
| API de categorias | Interna (`/cms/categories`), sem documentação nem consumidor identificado no front |
| `quantidade_itens` / `layout` | Só fazem sentido para a família "noticias" |

## 3. Acoplamentos frágeis

| Acoplamento | Risco |
|---|---|
| `MenuServiceProvider` ← `modulos` + `menu_orders` | Sem o item `categoria-conteudo` (módulo 54) o submenu desaparece |
| `ContentController` ← recorte `status_create` | Alterar o recorte muda o select de categoria de **todos** os conteúdos genéricos |
| `PortalController@contentList` ← `switch ($slug)` | Uma categoria nova com o mesmo slug de uma de sistema é redirecionada para o controller dela |
| `functions.php` (`getResultSearch`) | Agrupa a busca por **ids fixos** de categoria (1, 2, 3, 4, 6, 7, 11, 12, 32) — categorias "Mais Conteúdos" não são agrupadas |
| Views genéricas por modelo de layout | 7 conjuntos de views (`default`, `modelo1`..`modelo6`, `newsbit`) para a mesma functionality |
| Variável `$null` | Contrato implícito entre controller e view |

## 4. Riscos de dados (migração de schema)

| Risco | Detalhe | Mitigação |
|---|---|---|
| Inversão de `status_create` | Migrar para `is_system` exige cuidado: `0` = criada pelo usuário | Migrar com `UPDATE ... CASE` e validar contagens |
| Slugs `cat<id>_` | URLs antigas podem quebrar se o formato mudar | Manter os slugs existentes; só os novos usam o novo formato |
| Auto-FK `category_contents_id` | Categoria pai deletada deixa órfãos (FK sem `ON DELETE`) | Definir `nullOnDelete` na v7 |
| Ausência de unicidade de `(parent_id, slug)` | Slugs duplicados são possíveis (o código só desambigua no create) | Índice único + rotina de verificação |
| Soft delete sem filtro em algumas queries | `CategoryContent::all()` e `->get()` incluem deletadas quando não há `SoftDeletes` no escopo | Auditar consultas |
| `menu_items` órfãos | A remoção em cascata é manual e só ocorre na exclusão pela tela | FK `cascadeOnDelete` na v7 |

## 5. Perguntas em aberto para o negócio

1. "Mais Conteúdos" deve continuar sendo um rótulo do CMS, ou virar um módulo com
   tela própria (listagem em tabela, ordenação, busca)?
2. As categorias criadas devem aparecer automaticamente no **portal** (menu/rodapé),
   ou apenas no CMS? Hoje elas só aparecem se o operador criar manualmente um
   `menu_item`.
3. Qual a diferença de comportamento entre `status_create = 0` e `NULL`? As 12
   categorias com `NULL` (subcategorias de sistema) ficam fora do menu — é o
   comportamento desejado?
4. Deve ser permitido criar uma categoria de topo dentro de outra categoria de topo
   (hierarquia de mais de 2 níveis)? O portal só trata 3 níveis de URL.
5. `display_type`, `custom_icon` e `description` devem ser gerais ou restritos à
   Transparência?
6. O item do menu deve listar também as subcategorias, ou apenas as de topo?

## 6. Mapa v5 → v6

| Aspecto | v5 | v6 | Impacto |
|---|---|---|---|
| Tabela `modulos` | **Não existe** na v5 | `mais-conteudos` (id 54, status 1) | Novo: registry de módulos |
| `menu_orders` | Sem item `categoria-conteudo` | `id = 42`, `slug = 'categoria-conteudo'`, `modulo_id = 54` | Novo |
| `resources` | `conteudo` e `categoria-conteudo` | `id = 73` (`categoria-conteudo`) e `id = 74` (`conteudo`), `modulo_id = 54` | Equivalente |
| Seed do módulo | A v5 **não tem** o arquivo `AjustesMigracao.php` nem registra o módulo | `v6/database/seeds/AjustesMigracao.php:203-207` garante o registro em `modulos` | Novo |
| Menu do AdminLTE | `if (has_access("$menu->slug.index"))` — sem gate de módulo | `MenuOrder::with('modulo')` + `modulos.status` | **Mudança**: o submenu passa a depender do registry |
| API de categorias | Inexistente | `POST/PUT/DELETE /cms/categories` + `GET /cms/categories/{slug}` | **Novo** |
| `ApiStoreRequest` / `ApiUpdateRequest` / `ApiDestroyRequest` | Inexistentes | Criados em `v6/app/Http/Requests/CategoryContent/` | **Novo** |
| `ShowResource` | Inexistente | `v6/app/Http/Resources/CategoryContents/ShowResource.php` | **Novo** |
| Coluna `display_type` | Já presente (`2026_06_01_100000`) | Presente | Sem mudança |
| Coluna `custom_icon` | Já presente (`2026_06_01_100000`) | Presente | Sem mudança |
| Coluna `description` | **Ausente** | `2026_06_04_100000_add_description_to_category_contents_table.php` | **Novo na v6** |
| Regra de validação da descrição | Ausente | `nullable|max:500` quando o pai é `transparencia-fiscal` | **Novo na v6** |
| Upload de `custom_icon` | Ausente | `public/uploads/icons/` | **Novo na v6** |
| `CategoryContentController` | Versão anterior | Versão nova com API, `display_type`, `custom_icon`, `description` | Evolução |
| `CategoryContent` (model) | Sem os campos novos no `$fillable` | Com `description`, `display_type`, `custom_icon` | Evolução |
| Manual do usuário | "Manual de Mais Conteúdos" (seed `UpdateManualAreas.php`) | Presente | Sem mudança |

**Resumo do mapa**: o "Mais Conteúdos" da v5 já existia como o conjunto de categorias
criadas pelo operador (o `MenuServiceProvider` da v5 já tinha o case
`categoria-conteudo` com o rótulo "Mais Conteúdos"), mas **sem** o registry de
módulos: o item de menu aparecia apenas por `has_access`. A v6connected o item ao
módulo `mais-conteudos` (`id = 54`), adicionou a API interna de categorias, os campos
`display_type`, `custom_icon` e `description` e a migration da `description`. O
comportamento funcional do recorte (`status_create = 0` + topo) **não mudou**.

## 7. Checklist de correção rápida

- [ ] Aplicar `check.logged` (ou Policy) às rotas `categoria-conteudo`
- [ ] Substituir `catch (\Throwable $th) {}` por tratamento explícito no
      `PortalController@contentList`
- [ ] Renomear a rota POST `ajust-categorias` (remover o nome conflitante)
- [ ] Proteger `getAllDescendants()` contra ciclos
- [ ] Validar que o pai não é a própria categoria nem um descendente
- [ ] Usar índice único `(parent_id, slug)` e desambiguação sem `max(id)+1`
- [ ] Mover `custom_icon` para `Storage::disk('public')` com validação
- [ ] Não vazar `$th->getMessage()` nas respostas da API
- [ ] Decidir o destino do bloco `@if(false)` do modelo 5
- [ ] Criar factory de `CategoryContent` e escrever testes (ver `07-TESTES.md`)

## 8. Verificação realizada

| Item | Resultado |
|---|---|
| `ls dossie_modules/mais-conteudos/` | 9 arquivos presentes |
| Caminhos citados (`grep -ohE '(v5\|v6)/...'`) | 0 inexistentes |
| Marcadores de placeholder | 0 ocorrências |
| Dados no banco | 45 categorias; 33 com `status_create = true`, 12 com `NULL`, **0** com `false` → submenu "Mais Conteúdos" vazio no ambiente |
| Registry | `modulos` id 54 (`mais-conteudos`, status 1); `menu_orders` id 42 (`categoria-conteudo`); `resources` id 73 e 74 |
