# Lotep V2 — panorama

> **O que é.** Dossiê da camada modular `V2/` do CMS/portal da LOTEP, produzido com o
> [protocolo de dossiê](../../_protocolo/README.md) e **sem executar** o projeto. O objetivo não é
> migrar o LOTEP: é registrar **como** os módulos e serviços foram implementados, porque muitos deles
> têm contraparte nominal no Public V7 e chegaram aqui antes do backlog do V7.
>
> **Projeto:** `lotep/` — Laravel 5.5, PHP 7.4.33, PostgreSQL, Sentinel. **Escopo:** `V2/` (Core +
> Modules + Services + layouts + Seeds + Console).
> **Data:** 2026-10-23 · **Estado do dossiê:** `preparado` (inventário + panorama + 8 dossiês de
> módulo; os demais estão no inventário com destino declarado).

## Números

| Item | Valor |
|---|---|
| Módulos de negócio (após ignorar `_Exemplos`) | **31** |
| Serviços transversais | **15** |
| Arquivos PHP / Blade | 1.344 / 533 |
| Migrações | 95 |
| Testes declarados | 650 (2.107 asserções, 9 skipped) |
| E2E declarado | 89 |
| PHPStan | nível 9, “0 erros” com ~60 supressões |

## Os 10 achados que importam para o V7

1. **Search** resolve busca pública e “search-to-edit” com índice desnormalizado (`tsvector`
   ponderado por trigger + GIN + UPSERT idempotente), separado por superfície. O V7 não tem busca;
   o desenho é portável, a URL por `switch` não.
2. **ExcelImporter** tem o pipeline completo (preview → relatório → streaming → log `jsonb`), não um
   upload. É a base do backlog `servico-excel-importer`.
3. **LandingSections** tem contrato de widget + 22 schemas + `prepareSections()` que resolve mídia em
   **um** `whereIn`. É o motor que o plano 16 do V7 ainda não tem.
4. **FormularioDinamico** é o serviço com maior lacuna no V7: versão imutável, `answers` jsonb + GIN,
   scoring por faixas, consentimento e `ip_hash` HMAC.
5. **Notícias** já traz taxonomia (categoria hierárquica + tags + galeria), workflow de aprovação,
   preview por token e sitemap — o V7 entregou o módulo sem tags/destaque/RSS.
6. **Legislação** resolve agendamento por `publication_date`, múltiplos anexos com ordem e importação
   idempotente `number+year`; falta o versionamento que o backlog do V7 exige.
7. **PermissionService** mostra o custo de um RBAC de 2 níveis com resolução tolerante por alias:
   funciona, mas é fail-open e não separa aprovar/editar. ADR-033 já é a resposta correta.
8. **Auditoria** tem envelope com `correlation_id`, buffer por request e bulk insert — o V7 já cobre
   com ADR-024/035 e BLAKE3, mas o formato de log pode inspirar o `log_event`.
9. **CDN e licenças**: o V2 carrega TipTap de `esm.sh` e usa `maatwebsite/excel`, `tcpdf`/`fpdi`,
   `spatie/activitylog`. Portar código exige trocar dependência, não só namespace.
10. **Qualidade**: o baseline é um contrato bem escrito, mas “650 testes / PHPStan 9” não cobrem
    RBAC, XSS, upload nem dois módulos inteiros. Número não é cobertura.

## Os 8 riscos que o V7 não pode herdar

1. **Blade executado a partir do banco** (`BlockRenderer`) — RCE.
2. **Permissão fail-open** fora de `active_pattern` e `GET/HEAD` sempre liberado.
3. **HTML livre** em conteúdo, página runtime e blocos do portal — XSS armazenado.
4. **SVG sem sanitização** e upload validado pela extensão do cliente.
5. **Bypass de autorização** por e-mail fixo (`config('v2.support.email')`) e `super-admin`.
6. **Login sem throttle**, logout por `GET` e CSRF isento pelo token de avaliação.
7. **S3→local silencioso** — perda de integridade sem sinal.
8. **PII em log** (corpo de e-mail e dados de contato).

## Índice

| Documento | Conteúdo |
|---|---|
| [`01-ARQUITETURA.md`](01-ARQUITETURA.md) | boot, auto-descoberta, contrato de módulo, ciclo da requisição |
| [`02-SERVICOS.md`](02-SERVICOS.md) | os 15 serviços: contrato, persistência, limites, comparação com o V7 |
| [`03-MODULOS.md`](03-MODULOS.md) | os módulos com contraparte no V7, padrão a portar e riscos |
| [`04-QUALIDADE-E-GATES.md`](04-QUALIDADE-E-GATES.md) | PHPUnit/E2E/PHPStan/lint e o que cada número prova |
| [`05-SEGURANCA.md`](05-SEGURANCA.md) | autenticação, RBAC, XSS, upload, headers, PII (potencial) |
| [`06-APROVEITAMENTO-V7.md`](06-APROVEITAMENTO-V7.md) | **o que portar/adaptar/rejeitar**, com encaixe em ADR e ordem |
| [`07-DIVERGENCIAS-E-LICOES.md`](07-DIVERGENCIAS-E-LICOES.md) | premissas × código, D1–D20, limites do método |
| [`10-INVENTARIO-DE-MODULOS.md`](10-INVENTARIO-DE-MODULOS.md) | lista canônica (gerada) |
| [`11-INVENTARIO-MECANICO.md`](11-INVENTARIO-MECANICO.md) | volumetria (gerada) |
| `../inventario.json` | artefato bruto da F1 |

Dossiês completos (9 arquivos + `09-APROVEITAMENTO-V7.md`): `publicacoes-noticias`,
`publicacoes-legislacao`, `servicos-ouvidoria`, `publicacoes-licitacoes`,
`dadosabertos-transparenciafiscal`, `infraestrutura-formulariosdinamicos`,
`support-structurallandingeditor`, `infraestrutura-gestaopermissoes`.

## Como isto foi produzido (e como repetir)

1. **F0/F1** — projeto registrado em `_protocolo/projetos.json` com `raiz_codigo` (projeto fora do
   workspace) e `modulos.profundidade: 2` (layout `Modules/<Grupo>/<Modulo>`); inventário mecânico
   gerado por `_tools/inventario.py --projeto lotep-v2`.
2. **F2** — 31 módulos de negócio; `_Exemplos` ignorado como andaime; serviços tratados como
   capacidade transversal no panorama (não como módulo).
3. **F3 (parcial)** — oito dossiês completos, com um décimo arquivo `09-APROVEITAMENTO-V7.md`.
4. **F4** — este panorama.
5. **F5** — **não executado**: sem ambiente, nenhum crítico foi provado; ver §1 de
   `07-DIVERGENCIAS-E-LICOES.md`.
6. **F6** — `auditar.py --projeto lotep-v2` (caminhos, estrutura, placeholders) e `gerar-readme.py`.

## Fronteira

Este dossiê **não decide** o que entra no V7: a decisão está em
[`wiki/backlog/REVISAO.md`](../../../REVISAO.md) e nos itens de backlog. Aqui está **como** cada
capacidade já foi resolvida no LOTEP, com evidência e limites.
