# Publicações — Gaps, Bugs e Dívidas

## 1. Bugs e erros conhecidos

| # | Severidade | Descrição | Evidência |
|---|---|---|---|
| P-B01 | **Alta** | `viewPublication` busca o documento só por `slug`, **sem** filtrar `category_contents_id` nem `status`. Um rascunho é acessível por URL e uma slug repetida abre o documento da categoria errada. | `v6/app/Http/Controllers/Portal/PublicationController.php:157-160` |
| P-B02 | **Alta** | `viewPublication` faz `Content::where('slug', $slug2)->first()` e acessa `$content->publication_date` sem checar `null` -> erro 500 para slug inexistente. | `v6/app/Http/Controllers/Portal/PublicationController.php:157-158` |
| P-B03 | **Alta** | SQL montado por concatenação com `whereRaw` e `$_GET['ano']` embutido na string. Não há injeção direta (o `clean_slug` remove aspas), mas o padrão é frágil e não permite bindings. | `v6/app/Http/Controllers/Portal/PublicationController.php:46` e `:60-61`, `:129-137` |
| P-B04 | Média | O filtro de **mês** sem **ano** não restringe nada; e o filtro de data (`publication_date <= now`) só é aplicado quando **não** há mês — documentos futuros podem aparecer. | `v6/app/Http/Controllers/Portal/PublicationController.php:66-75` |
| P-B05 | Média | `getIndex()` usa `->first()` sem verificar `null` -> erro 500 em `/publicacoes` quando não há subcategorias. | `v6/app/Http/Controllers/Portal/PublicationController.php:19-27` |
| P-B06 | Média | A datatable do CMS carrega **todos** os documentos das subcategorias em memória e pagina no cliente; a view SQL `publicacoes` (equivalente e pronta) não é usada. | `v6/app/Http/Controllers/Prefecture/DatatableController.php:80-99` |
| P-B07 | Média | `getAllDescendants()` é recursivo em PHP, com N+1 e mistura de tipos (`Model` e array) na coleção. | `v6/app/Http/Model/Prefecture/CategoryContent.php:56-77` |
| P-B08 | Média | `viewPublication` incrementa `clicks` com read-modify-write -> lost update. | `v6/app/Http/Controllers/Portal/PublicationController.php:164-165` |
| P-B09 | Média | A listagem inicial (sem filtros) não usa `with('categoryContents')` — só a versão filtrada usa -> N+1 na view. | `v6/app/Http/Controllers/Portal/PublicationController.php:41-47` vs `:85` |
| P-B10 | Baixa | `select(...)` da listagem não inclui `id`; as views que dependem de `$content->id` recebem `null`. | `v6/app/Http/Controllers/Portal/PublicationController.php:41` |
| P-B11 | Baixa | `clean_slug()` remove `%`, `_`, `-` e `/`: buscas por "100%" ou por identificadores com hífen falham. | `v6/app/Helpers/functions.php:823-847` |
| P-B12 | Baixa | A breadcrumb `view-publicacoes` aponta para `conteudo.portal.view`, que redireciona para a **lista** da categoria: o documento não é alcançado pelo breadcrumb. | `v6/routes/breadcrumbs.php:127-130` + `v6/app/Http/Controllers/Portal/PortalController.php:327` |
| P-B13 | Baixa | A variável local de `get_publicacoes` chama-se `$legislacaoContent` (cópia do método irmão) — indica código copiado. | `v6/app/Http/Controllers/Prefecture/DatatableController.php:83` |
| P-B14 | Baixa | `Route::get` (não `Route::any`) nas rotas do portal: `POST /publicacoes/...` devolve 405. | `v6/routes/web.php:38-41` |
| P-B15 | Baixa | O módulo `publicacoes` está com `status = 0` na tabela `modulos`, embora exista e tenha conteúdo — inconsistência de configuração. | `v6/database/migrations/2024_11_01_150206_create_modulos_table.php:114-118` |

## 2. Funcionalidades incompletas ou mortas

| Item | Situação |
|---|---|
| View SQL `publicacoes` | Existe e é mantida por 3 migrations, mas **não é usada** pela datatable do CMS nem pelo portal — só por consumidores externos |
| `CategoryContent::scopeByCategoryHasContent` | Usado por Notícias; sem efeito em Publicações |
| `Content::scopeByHighlights` / `scopeByOrderClicks` | Disponíveis mas não usados por Publicações |
| `link` (Link) | O modelo `Content` tem `linksUnique()` e o CMS aceita `link`, mas o caso `publicacoes` do `ContentRequest` **não** valida nem grava `link` — a relação fica sempre vazia para Publicações |
| `modulos.status` | Não é lido pelo portal; Publicações aparece mesmo com `status = 0` |
| `quantidade_itens` das subcategorias | NULL em todas — não há "destaque" de subcategoria na home |
| `order` das subcategorias | NULL em todas — a ordem em `/publicacoes` é indefinida |
| Filtro de mês | Funcional, mas sem efeito prático sem o ano |
| `newsbit/publicacoes/index.blade.php` | Existe apenas no layout `newsbit`; os demais layouts não têm `index` próprio (usam `show`) |

## 3. Itens da v5 que mudaram na v6

| Item | v5 | v6 | Efeito |
|---|---|---|---|
| Exportação | **Inexistente** | `GET /publicacoes/export` com XLS/PDF/CSV/TXT | Nova capacidade (feature principal da v6) |
| `ExportsContentTrait` | Inexistente | `v6/app/Http/Traits/ExportsContentTrait.php` | Trait nova, reaproveitada por outros módulos |
| `ContentsExport` | Inexistente | `v6/app/Exports/ContentsExport.php` | Exportador genérico de conteúdos |
| Lista de categorias no portal | `$publication_root->rightWayToGetCategoryContents` (filhos diretos) | `CategoryContent::allDescendants()` | Passa a listar descendentes (nível 2+) |
| Colunas da listagem | `title, text, publication_date, slug, category_contents_id` | `+ updated_at, created_at` | Mais dados na view |
| `ContentController` (CMS) | — | + ~1400 linhas | `sanitizeLink()`, `linha_fina`, `view_pdf`, `pathUpdate`, auditoria enrichecida |
| `StaticPageController` | link cru | `sanitizeLink()` | Idem (módulo Páginas Estáticas) |
| `DatatableController` | — | + ~266 linhas | `get_publicacoes` praticamente inalterado (a v5 já montava o array em PHP) |

> Verificação: `v5/app/Http/Controllers/Prefecture/DatatableController.php:52-64`
> já usava `getAllDescendants()` + array em PHP — a view SQL `publicacoes`
> **nunca** foi usada pela datatable, nem na v5.

Nenhum item de Publicações foi **removido** na v6.

## 4. Mapa v5 -> v6

| Camada | v5 | v6 | Observação |
|---|---|---|---|
| Controller portal | `v5/app/Http/Controllers/Portal/PublicationController.php` | `v6/app/Http/Controllers/Portal/PublicationController.php` | v6 = v5 + `export()` (+46 linhas) |
| Controller CMS conteúdo | `v5/app/Http/Controllers/Prefecture/ContentController.php` | `v6/app/Http/Controllers/Prefecture/ContentController.php` | ~1400 linhas de diferença |
| Controller CMS datatable | `v5/app/Http/Controllers/Prefecture/DatatableController.php` | `v6/app/Http/Controllers/Prefecture/DatatableController.php` | ~266 linhas de diferença |
| Modelo conteúdo | `v5/app/Http/Model/Prefecture/Content.php` | `v6/app/Http/Model/Prefecture/Content.php` | 10 linhas (acréscimos) |
| Modelo categoria | `v5/app/Http/Model/Prefecture/CategoryContent.php` | `v6/app/Http/Model/Prefecture/CategoryContent.php` | — |
| Trait de exportação | **inexistente** | `v6/app/Http/Traits/ExportsContentTrait.php` | Novo |
| Exportador | **inexistente** | `v6/app/Exports/ContentsExport.php` | Novo |
| View de PDF | **inexistente** | `v6/resources/views/exports/contents.blade.php` | Novo |
| Rotas portal | `v5/routes/web.php:47-49` | `v6/routes/web.php:38-41` | + `publicacoes.export` |
| Rotas CMS | `v5/routes/basepro.php:159-162`, `:207-209` | `v6/routes/basepro.php:173-176`, `:235-237` | mesmas URIs e nomes |
| Views CMS | `v5/resources/views/prefecture/contents/publicacoes/` | `v6/resources/views/prefecture/contents/publicacoes/` | mesma estrutura (`index`, `create`, `edit`, `form`) |
| Views portal | `v5/resources/views/portal/layouts/*/publicacoes/` | `v6/resources/views/portal/layouts/*/publicacoes/` | mesmos layouts; a v6 acrescenta os botões de exportação nos `list.blade.php` |
| JS do CMS | `v5/public/assets/js/custom/contents/publicacoes/datatable.js` | `v6/public/assets/js/custom/contents/publicacoes/datatable.js` | — |
| Seeds | `v5/database/seeds/CategoryContentTableSeeder.php` | `v6/database/seeds/CategoryContentTableSeeder.php` | mesma estrutura |

### Rotas do módulo: comparação

| Rota | v5 | v6 |
|---|---|---|
| `GET /publicacoes` | `v5/routes/web.php:47` | `v6/routes/web.php:38` |
| `GET /publicacoes/{slug1}` | `v5/routes/web.php:48` | `v6/routes/web.php:40` |
| `GET /publicacoes/{slug1}/{slug2}` | `v5/routes/web.php:49` | `v6/routes/web.php:41` |
| `GET /publicacoes/export` | **ausente** | `v6/routes/web.php:39` |

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

| Risco | Detalhe | Mitigação |
|---|---|---|
| `order` e `quantidade_itens` nulos nas 9 subcategorias | A ordenação de `/publicacoes` é indefinida | Migrar para `order = id - 13` e `quantidade_itens = 6` |
| Slug duplicado entre subcategorias | `viewPublication` não filtra por categoria | Backfill de slugs únicos por prefixo de categoria |
| `publication_date` NULL | Publicações exige data; o schema permite NULL | Backfill ou validação de backlog antes de migrar |
| `contents` compartilhada com Notícias/Legislação | Separar os dados exige uma migração cuidadosa | Migrar por `category_contents_id IN (13..21)` e validar contagens antes/depois |
| `archives.view_pdf` NULL vs `true` | `NULL` significa "não é o PDF inline" | Backfill para `false` |
| `layout` NULL | Significa "com barra lateral" | Migrar para `2` apenas se o negócio concordar (a mudança é visível) |
| Links externos para documentos | URLs antigas `/publicacoes/{cat}/{slug}` | Manter as URLs ou criar tabela de redirecionamentos |
| `modulos.status = 0` | Configuração inconsistente | Corrigir para `1` se o módulo deve aparecer no menu do CMS |

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

1. Qual deve ser a subcategoria padrão de `/publicacoes` (a de menor `order`)?
2. O filtro de mês sem ano deve filtrar algo? Hoje não filtra.
3. Documentos futuros podem ser vistos ao filtrar por mês?
4. Rascunhos devem ser acessíveis por URL direta?
5. O `layout` (barra lateral) deve ser padrão "com" ou "sem"?
6. A view SQL `publicacoes` ainda é consumida por algum sistema externo?
   Se não, pode ser removida.
7. Os 4 formatos de exportação são todos necessários? (PDF é o mais caro)
8. O limite de 12 documentos por página é adequado?
9. `modulos.status = 0` é intencional?
10. Publicações e Legislação devem ser unificados em um só repositório
    (com uma raiz "Documentos")?

## 7. Checklist de pendências

- [ ] Corrigir `viewPublication`: filtrar `status`, `category_contents_id`
      e tratar `null`.
- [ ] Substituir `whereRaw` por bindings e `$_GET['ano']` por
      `$request->ano`.
- [ ] Definir a semântica do filtro de mês e do filtro de data futura.
- [ ] Migrar a datatable do CMS para a view SQL `publicacoes` (ou para
      paginação server-side).
- [ ] Trocar `getAllDescendants()` por CTE recursiva.
- [ ] Usar `increment('clicks')`.
- [ ] Normalizar `order`/`quantidade_itens` das subcategorias.
- [ ] Corrigir a breadcrumb `view-publicacoes` para apontar para a rota do
      documento.
- [ ] Tratar `getIndex()` sem subcategorias.
- [ ] Consolidar `PublicationController` e `LegislationController`.
