# Legislação — Arquitetura

> **Slug:** `Legislacao` · **Versão analisada:** `lotep` (Laravel 5.5 / PHP 7.4, camada `V2/`)
>
> Todos os caminhos são relativos à raiz `lotep/`.

---

## 1. Fluxo da requisição

### 1.1 CMS (escrita)

```mermaid
sequenceDiagram
    participant U as Operador
    participant R as Routes/cms.php
    participant M as Middleware v2
    participant C as LegislationCmsController
    participant V as LegislationRequest
    participant S as LegislationFileService
    participant A as V2AuditLogger
    participant D as Models/PostgreSQL

    U->>R: POST /cms/v2/legislacao
    R->>M: v2.authenticate + v2.permission:Legislacao,read
    M->>C: store()
    C->>C: v2_can('Legislacao','write')
    C->>V: valida título/slug/datas/categoria/files.*
    V-->>C: dados válidos
    C->>C: normalizePublicationDate()
    C->>D: V2Legislation::create()
    C->>S: upload(item, file) por anexo do form
    S->>S: validateMime + validateMagicBytes
    S->>D: V2LegislationFile::create()
    C->>A: activity(item,'created')
    C-->>U: 302 -> items.index
```

### 1.2 Portal (leitura)

```mermaid
sequenceDiagram
    participant Cid as Cidadão
    participant R as Routes/web.php
    participant C as LegislationPortalController
    participant M as V2Legislation
    participant V as Blade v2-legislacao
    participant SEO as SEOService

    Cid->>R: GET /legislacao?q=termo&category=slug&dt_inicial=data
    R->>C: index()
    C->>M: published()->search()->when(category)->fromDate()->toDate()->ordered()->paginate(10)
    M-->>C: paginator
    C->>V: portal.index
    Cid->>R: GET /legislacao/{slug}
    R->>C: show()
    C->>M: published()->where(slug)->with(category,files)->firstOrFail()
    C->>C: renderer->toHtml(content)
    C->>SEO: setTitle/setDescription/setCanonical
    C->>V: portal.show
```

## 2. Tabela de rotas principais

Rotas completas em `03-ROTAS-E-CONTROLADORES.md`. Resumo do encadeamento:

| Superfície | Arquivo | Prefixo | Middleware de grupo |
|---|---|---|---|
| CMS | `V2/Modules/Publicacoes/Legislacao/Routes/cms.php` | `cms/v2/legislacao` | `v2.authenticate`, `v2.permission:Legislacao,read` |
| Portal | `V2/Modules/Publicacoes/Legislacao/Routes/web.php` | `/legislacao` | nenhum (público) |

O registro é automático: `V2ServiceProvider` varre `V2/Modules/<Grupo>/<Modulo>`,
carrega migrations, views (`v2-legislacao::`) e as rotas dos arquivos `web.php`
e `cms.php` do diretório `Routes/`
(`V2/Core/Providers/V2ServiceProvider.php:85-127`). Não há `api.php` neste módulo.

## 3. Classes envolvidas

| Classe | Caminho | Papel |
|---|---|---|
| `ModuleProvider` | `V2/Modules/Publicacoes/Legislacao/ModuleProvider.php` | Declara título, ícone, posição, padrão ativo e rota inicial do sidebar. |
| `LegislationCmsController` | `V2/Modules/Publicacoes/Legislacao/Controllers/Admin/LegislationCmsController.php` | CRUD da norma, categorias, importação e anexos. |
| `LegislationPortalController` | `V2/Modules/Publicacoes/Legislacao/Controllers/Portal/LegislationPortalController.php` | Listagem, detalhe e download público. |
| `LegislationRequest` | `V2/Modules/Publicacoes/Legislacao/Requests/LegislationRequest.php` | Validação do formulário da norma e dos arquivos embutidos. |
| `LegislationFileService` | `V2/Modules/Publicacoes/Legislacao/Services/LegislationFileService.php` | Upload com MIME/magic bytes, metadados, exclusão e reordenação. |
| `V2Legislation` | `V2/Modules/Publicacoes/Legislacao/Models/V2Legislation.php` | Entidade norma, escopos de publicação/busca/ordem. |
| `V2LegislationCategory` | `V2/Modules/Publicacoes/Legislacao/Models/V2LegislationCategory.php` | Taxonomia com unicidade de slug considerando soft delete. |
| `V2LegislationFile` | `V2/Modules/Publicacoes/Legislacao/Models/V2LegislationFile.php` | Anexo, resolução de URL e detecção de PDF. |
| `LegislationImportSchema` | `V2/Modules/Publicacoes/Legislacao/Imports/LegislationImportSchema.php` | Colunas e chave natural (`number`,`year`) da planilha. |
| `LegislacaoDataSource` | `V2/Modules/Publicacoes/Legislacao/DataSources/LegislacaoDataSource.php` | Métricas para o módulo de Estatísticas. |
| `LegislationSeeder` | `V2/Modules/Publicacoes/Legislacao/Seeds/LegislationSeeder.php` | Categorias fixas e dados de demonstração opcionais. |

### 3.1 Serviços do Core/Services consumidos

| Serviço | Caminho | Uso no módulo |
|---|---|---|
| `V2AuditLogger` | `V2/Core/Services/V2AuditLogger.php` | `activity()` em criação/edição/exclusão e eventos de anexo/importação. |
| `CmsActionLogger` | `V2/Core/Logging/CmsActionLogger.php` | `info()` e `measure()` para telemetria do CMS. |
| `BaseController` | `V2/Core/Controllers/BaseController.php` | Base com `ValidatesRequests`/`AuthorizesRequests`. |
| `PermissionService` (helper `v2_can`) | `V2/Core/Services/PermissionService.php` | Resolve `Legislacao.read|write` por `v2_roles.permissions_v2`. |
| `ImportExcelService` | `V2/Services/ExcelImporter/Services/ImportExcelService.php` | Preview e processamento streaming da planilha. |
| `ImportExcelTemplateGenerator` | `V2/Services/ExcelImporter/Services/ImportExcelTemplateGenerator.php` | Geração do XLSX modelo. |
| `ContentRichEditorRendererService` | `V2/Services/ContentRichEditor/Services/ContentRichEditorRendererService.php` | Converte AST TipTap em HTML no detalhe. |
| `SEOService` | `V2/Services/SEO/Services/SEOService.php` | Título, descrição e canonical do detalhe. |

## 4. Middleware aplicado

| Middleware | Onde é registrado | Efeito observável |
|---|---|---|
| `v2.authenticate` | `Routes/cms.php:4` (grupo) | Exige sessão Sentinel/V2 no CMS. |
| `v2.permission:Legislacao,read` | `Routes/cms.php:4` (grupo) | Bloqueia todo o módulo para quem não tem leitura. |
| `v2.permission:Legislacao,write` | Rotas de escrita em `Routes/cms.php` | Bloqueia escrita antes de chegar ao controller (302/403). |
| `v2_can('Legislacao','write')` | Dentro das actions e em `LegislationRequest::authorize()` | Segunda barreira, redundante com a rota, mas necessária para chamadas internas e testes. |
| `VerifyCsrfToken` | Kernel global | POSTs exigem token; os testes desativam explicitamente. |

O portal não tem middleware de autenticação nem de cache explícito; a única
proteção é o escopo `published()` aplicado nas consultas.

## 5. Dependências externas

| Pacote | Versão | Para que é usado aqui |
|---|---|---|
| `laravel/framework` | 5.5.* | Rotas, Eloquent, validação, storage, paginação. |
| `maatwebsite/excel` | ^3.1 | Leitura/geração de XLSX/XLS/CSV pela importação. |
| `cartalyst/sentinel` | 2.0.* | Autenticação do CMS (indireta, via middleware). |

Não há biblioteca de sanitização de HTML instalada; o parser de conteúdo é
próprio (`V2/Services/ContentRichEditor`).

## 6. Acoplamento com outros módulos

| Módulo | Tipo de acoplamento | Onde acontece |
|---|---|---|
| `Publicacoes/Noticias` | Mesmo padrão de UI e de editor; sem import de código. | Views e serviços compartilhados. |
| `Support/MigracaoLegada` | Importador V1 grava em `V2Legislation`, `V2LegislationCategory` e `V2LegislationFile`. | `V2/Modules/Support/MigracaoLegada/Services/LegislacaoLegacyImporter.php` |
| `Infraestrutura/Estatisticas` | Consome as tabelas por `DB::table` via contrato de DataSource. | `V2/Modules/Publicacoes/Legislacao/DataSources/LegislacaoDataSource.php` |
| `V2/Services/ExcelImporter` | Motor de importação e template. | Controller de importação. |
| `V2/Services/ContentRichEditor` | Renderização do AST no portal. | `LegislationPortalController.php:69` |
| `V2/Services/SEO` | Metadados do detalhe. | `LegislationPortalController.php:71-76` |

O módulo **não** é consumido por nenhum outro controller; é folha na árvore de
dependências, exceto pelas referências externas de importação e estatística.

## 7. Pontos de entrada alternativos

- **Seeder:** `LegislationSeeder` cria três categorias (Leis, Decretos, Portarias)
  mesmo sem dados de demonstração; os documentos demo só entram com
  `run(true)` (`V2/Modules/Publicacoes/Legislacao/Seeds/LegislationSeeder.php:23-47`).
- **Importador legado:** registrado no `LegislacaoLegacyImporter` e executado pelo
  painel de Migração Legada; grava `v1_id` e `imported_at` para idempotência.
- **DataSource:** `LegislacaoDataSource` expõe seis métricas ao editor de
  estatísticas (`getMetrics()`), incluindo gráficos por categoria e por ano.
- **Jobs, eventos e comandos artisan:** nenhum específico do módulo.
- **API:** inexistente na camada `V2/`; a exposição de dados abertos do V7 é
  requisito novo (ADR-018), não uma migração de rota.

## 8. Decisões estruturais observáveis

1. **Controller único e gordo:** todas as responsabilidades do CMS (norma,
   categoria, importação, anexos) estão em `LegislationCmsController`, com
   métodos privados de apoio. Não há Actions nem DTOs.
2. **Validação híbrida:** o formulário principal usa FormRequest; categorias,
   upload avulso, edição de anexo e reordenação usam `$this->validate()` inline.
3. **Anexos em tabela própria:** `file_url` em `v2_legislation` permanece como
   "documento principal" legado, e `v2_legislation_files` guarda todos os
   anexos. O portal exibe os dois caminhos.
4. **Portal sem presenter/API Resource:** a view recebe models Eloquent e resolve
   URLs por accessor; não existe camada de serialização.
5. **Nenhuma interface de repositório:** consultas Eloquent direto no controller,
   model e DataSource.
