# Legislação — Resumo Executivo

> **Versão analisada:** `v6` (Laravel 5.5.50) com comparação `v5`
> **Slug do módulo:** `legislacao` (tabela `modulos`, id=19, `status = true`)
> **Natureza:** CMS (painel administrativo) + Portal (público) + API (dados abertos)
> **Estado:** migrado v5 -> v6 (módulo já existia na v5; a v6 acrescenta exportação)

---

## 1. Objetivo

O módulo **Legislação** publica no portal o conjunto de normas do município —
Constituição Federal, Código Tributário, Decretos e demais categorias
hierárquicas — e permite ao operador do CMS cadastrar, categorizar, reordenar e
publicar esses documentos. Serve ao cidadão que precisa consultar o ordenamento
jurídico local e ao servidor público responsável por manter a legislação
vigente disponível e datada. É também a fonte de dados do endpoint de dados
abertos `/api/v1/legislacoes`.

## 2. Efeito / Impacto

| Faixa | Efeito |
|---|---|
| Cidadão | Lista de normas por categoria, com filtro por período e por texto; abre o documento (texto + arquivos anexos) e exporta o resultado em CSV/XLS/TXT/PDF. |
| Prefeitura (CMS) | CRUD de legislação com ordem automática de publicação, categorias hierárquicas reordenáveis por arrastar-e-soltar, upload de anexos, log de auditoria e controle por permissões. |
| Transparência e legalidade | Publica normas com data de publicação e contagem de acessos (`contents.clicks`), que alimenta o índice de transparência e a API aberta. |
| Operação técnica | Reimplementação em PHP da listagem que antes vivia na view SQL `legislacao`; a view ficou órfã. Dupla paginação (servidor + cliente) e consultas sem `LIMIT` na maior parte dos caminhos. |

## 3. Comportamento

- A **categoria raiz** é `category_contents` id=2, `name = 'Legislação'`,
  `slug = 'legislacao'`, `category_contents_id = NULL`. As subcategorias do banco
  atual são id=22 "Constituição Federal" (`constituicao-federal`), id=23 "Código
  Tributario" (`codigo-tributario`) e id=24 "Decretos" (`decretos`), todas com
  `category_contents_id = 2`.
- A árvore pode ter **qualquer profundidade**: a navegação lateral do portal
  renderiza recursivamente via `rightWayToGetCategoryContents`.
- `/legislacao` (rota `legislacao.index`) **redireciona** para a primeira
  subcategoria por `order` — não existe uma página de índice própria.
- Conteúdos **futuros** (`publication_date > now`) não são listados; ao acessar
  um deles, o portal redireciona de volta para o índice da primeira categoria.
- A ordenação padrão é `publication_date DESC, id DESC`.
- O filtro de texto usa `translate(lower(...))` para ignorar acentos e caixa;
  o filtro de período usa `data_inicial`/`data_final`.
- O contador de acessos é incrementado **manualmente** em `contentView`
  (`$content->update(['clicks' => $clicks])`).
- No CMS, o slug do conteúdo é gerado a partir do título e a colisão é resolvida
  com sufixo numérico; a edição aceita slug manual validado por regex.
- Permissões exigidas no CMS: `legislacao.index`, `.create`, `.edit`,
  `.delete`, `.restore`, `.inactivate` (via `has_access()` e
  `check.route.permission`).

## 4. Como o Usuário Interage

### Cidadão (portal)

1. Entra por "Legislação" no menu do portal → cai em `/legislacao/{subcategoria}`.
2. Escolhe a categoria na lateral (modelos 1, 2, 5, 6: lista recursiva; modelos
   3 e 4: abas com submenu) e vê a lista de normas.
3. Filtra por data inicial, data final e texto — o filtro **roda no cliente**:
   o JS faz `POST /legislacao/filtro` e pagina o resultado em blocos de 10.
4. Exporta o resultado filtrado (xls, pdf, csv, txt) via `GET /legislacao/export`.
5. Abre a norma em `/legislacao/{categoria}/{slug}`: título, data/hora de
   publicação, texto HTML, botões de compartilhamento e lista de arquivos.

### Operador (CMS)

1. Menu lateral do AdminLTE → **Legislação** (`/cms/conteudos/legislacao`).
2. Grade DataTables com colunas `Título`, `Categoria`, `Data de publicação` e
   ações (link "Acessar legislação", editar, excluir, exclusão em lote).
3. Botão **Categorias de Legislação** → tela de categorias com
   arrastar-e-soltar (`POST /cms/ajax/ajust-categorias`) e CRUD via API JSON
   (`/cms/categories`).
4. Botão **Cadastrar Legislação** → formulário com Categoria, Título, Data de
   publicação (datetimepicker `d/m/Y H:i`), Texto (Summernote) e Anexos.

## 5. Detalhes e Particularidades Técnicas

- **Fluxo**: `routes/web.php` (portal) / `routes/basepro.php` (CMS) / `routes/api.php`
  (dados abertos) → `Portal\LegislationController` /
  `Prefecture\ContentController` / `Prefecture\CategoryContentController` /
  `Prefecture\DatatableController` / `Swagger\V1\Portal\LegislationController` →
  models `App\Prefecture\Content` e `App\Prefecture\CategoryContent` →
  tabelas `contents` e `category_contents`.
- **View SQL `legislacao` é resíduo**: nenhum PHP da v6 a consulta
  (`grep` em `v6/app/` e `v6/resources/` não retorna resultado). A grade do CMS
  reconstrói as mesmas colunas em PHP.
- **Dupla paginação**: o controller pagina em 5 (`paginate(5)`), mas as views de
  `modelo1..modelo6` ignoram `$contents`; quem pagina é o JS, no cliente, em
  blocos de 10.
- **Risco de SQL injection**: `v6/app/Http/Controllers/Portal/LegislationController.php:56`
  concatena `$_GET['ano']` direto no SQL; as linhas 75-76 e 127-128 concatenam
  `clean_slug()` e `$request->termo` em `whereRaw`.
- **Filtros sobrescritos**: em `filtroGET`, os `if` de `data_inicial` e
  `data_final` **substituem** `$result` em vez de compor filtros.
- **`texto` ignorado no filtro**: `filtroGET` só lê `$request->termo`.
- **Não existe `pub-nav.blade.php` para legislação**: a lateral do portal usa
  componentes próprios (`categories-contents/legislacoes/nav.blade.php` ou
  `modeloN/legislacao/elements/leg-nav.blade.php`).
- **Dependências de terceiros**: `yajra/laravel-datatables`, `maatwebsite/excel`,
  `barryvdh/laravel-dompdf`, `laracasts/presenter`, `cartalyst/sentinel`.

## 6. Estrutura de Dados

| Objeto | Natureza | Observação |
|---|---|---|
| `contents` | tabela | Armazena as normas (`title`, `text`, `publication_date`, `slug`, `clicks`, `galery`, `category_contents_id`); `SoftDeletes`. |
| `category_contents` | tabela | Árvore de categorias (`name`, `slug`, `order`, `category_contents_id`); auto-referência `category_contents_id -> category_contents.id`. |
| `legislacao` | **view SQL** | `value, titulo, data_publicacao, categoria, categoria_slug, slug, id` — **órfã**, ninguém consulta. |
| `archives` | tabela | Anexos dos documentos (`contents_id`, `view_pdf`, `highlight`). |
| `modulos` | tabela | Registro do módulo (`id=19`, `slug='legislacao'`, `status=true`). |

**Estado do banco atual** (`prefeituras_v5`, migrations v6 aplicadas): existem
**0 conteúdos** em `contents` para `category_contents_id` 2, 22, 23 e 24 — o
módulo está cadastrado e navegável, porém sem norma publicada.

## 7. Como Testar

- Portal: `GET /legislacao` → 302 para a primeira subcategoria; `GET
  /legislacao/decretos` → 200; `POST /legislacao/filtro` com
  `{slug, data_inicial, data_final, termo}` → JSON com os conteúdos.
- CMS: `GET /cms/conteudos/legislacao` (permissão `legislacao.index`);
  `GET /cms/datatable/legislacao` (Yajra) → colunas `titulo`, `categoria`,
  `data_publicacao`.
- API: `GET /api/v1/legislacoes?titulo=...&data_publicacao=01/01/2024_30/04/2024&limite=100`.
- Exportação: `GET /legislacao/export?type=csv&sub_category=decretos`.
- Casos detalhados em `07-TESTES.md`.

## 8. Migração para Laravel Moderno

Substituir a view SQL por uma query Eloquent paginada; introduzir um
`LegislationController` com `FormRequest` dedicated e `Policy` por
`legislacao.*`; migrar a paginação client-side para paginação de servidor
(infinita scroll ou paginação Laravel); trocar `whereRaw` com `translate()` por
`ilike` com `unaccent` (extensão) ou busca normalizada em coluna indexada;
sanear `$_GET['ano']` com binding; criar um único lugar para a lista de
subcategorias (evitar a duplicação "view + reimplementação PHP"). Detalhes em
`06-MIGRACAO-MODERNA.md`.

## 9. Resumo Geral

Legislação é o módulo que publica as normas do município. A árvore de
categorias vive em `category_contents` (raiz id=2, subcategorias 22/23/24) e as
normas em `contents`, com data de publicação como eixo de ordenação e
`clicks` como métrica de transparência. No CMS o módulo é genérico: as telas
`prefecture.contents.legislacao.*` e `prefecture.category-contents.legislacao.*`
são selecionadas pelo slug `legislacao` dentro de `ContentController` e
`CategoryContentController`, e a grade é montada por
`DatatableController@get_legislacao` em PHP. No portal o módulo expõe cinco
rotas: índice (redirecionador), listagem por categoria, visualização do
documento, filtro por POST e exportação. O ponto mais importante da
reconstrução é que **o legado tem duas listas concorrentes**: uma paginada no
servidor (`$contents`, ignorada por `modelo1..modelo6`) e outra montada no
cliente via `POST /legislacao/filtro` (que carrega a subcategoria inteira sem
limite). Somam-se a isso a view SQL `legislacao` órfã, o `whereRaw`/`$_GET`
concatenado (risco de injeção), os filtros de data que se sobrescrevem e o
parâmetro `texto` ignorado pelo endpoint de filtro. Todos esses pontos estão
detalhados em `08-GAPS-E-DIVIDAS.md`.

---

## Í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 |
