# Aproveitamento da V2 no Public V7

> **Regra.** Nada aqui é “copiar código”: o V2 é Laravel 5.5/PHP 7.4, com Sentinel, traits, abstract e
> HTML em banco. O que se porta é **desenho**, traduzido para as regras do V7 (ADR-001..045). Cada
> linha diz o que fazer e onde encaixa.

## 1. Veredito por capacidade

| Capacidade da V2 | V7 hoje | Veredito | Encaixe |
|---|---|---|---|
| Busca full-text (público + CMS) | **não existe** (backlog `servico-search`) | **PORTAR desenho** | service `Search` + registry de fontes |
| Importador de planilha | **não existe** (backlog `servico-excel-importer`) | **PORTAR pipeline** | service `ExcelImporter` (operação) |
| Seções de landing/home | **não existe** (F4/widgets) | **PORTAR contrato** | `layout` + módulo (não service) |
| Motor de formulários versionado | **não existe** | **PORTAR motor** | service próprio + módulo `Formularios` |
| Conversores DOCX/HTML→AST | V7 tem RichText, sem conversores | **PORTAR extra** | `services/RichText` |
| Assinatura A1/PAdES | **não existe** (backlog) | **ADAPTAR especificação** | service `DigitalSignature` |
| Envio de e-mail + log | nativo, sem histórico/retenção | **ADAPTAR (nativo)** | `email-deliverability` |
| Partial/anatomia do CMS | V7 tem shell próprio | **PORTAR ideia** (partials) | `src/layout/Cms` |
| Envelope de auditoria + GELF | ADR-024/035 já cobrem | **JÁ SUPERADO** | — |
| RBAC `none/read/write` + aliases | ADR-033 (4 ações, deny-by-default) | **REJEITAR modelo** | usar ADR-033 |
| Ativação por flag | ADR-034 (Valkey + fail-open) | **JÁ SUPERADO** | — |
| UUID “v7” falso | `uuidv7()` nativo (ADR-007) | **REJEITAR** | — |
| HTML/Blade em banco | proibido (ADR-017/028) | **REJEITAR** | — |
| Domínio de loteria | não existe | **NÃO TRAZER** | — |

## 2. Search — o desenho que falta no V7

**Portar:** índice desnormalizado por entidade, `tsvector` ponderado por trigger, GIN, UPSERT
idempotente, `ts_headline`/`ts_rank`, reindex comandado e separação público × CMS.

**Traduzir:**
- `search_vector` gerado por **coluna gerada**/trigger na tabela do índice (PG 18, ADR-007), com
  `setweight` A título / B resumo / C corpo;
- `entity_id` **text** (não `uuid`) para aceitar qualquer PK; `(entity_type, entity_id)` unique;
- URL resolvida por **porta do módulo** (`SearchSource::url(entity)`), nunca `switch`;
- indexação por **evento de domínio** (`{module}.{action}`) + job na fila, com reindex idempotente
  (`search:reindex`), em vez de escrita síncrona no request;
- ranking/paginação explícitos (`ts_rank`, `limit/offset`, total), locale fixo `portuguese`;
- `search_path` do Seo só é configurável **depois** que a rota existe (hoje o `BuildSeoGraph` aceita
  qualquer string — mitigar validando a rota).

**Testes de contrato:** upsert idempotente; item despublicado sai do índice; `ts_headline` escapa
HTML; URL por source; reindex não duplica.

## 3. ExcelImporter — pipeline, não “upload de planilha”

**Portar o fluxo:** preview → relatório Poka-Yoke → confirmação → persistência em lote → log com
`summary` jsonb; schema com colunas/aliases/validador por linha; chave de unicidade; template.

**Traduzir:**
- **CSV nativo primeiro** (streaming, `fgetcsv`); XLSX só com justificativa de licença (PhpSpreadsheet
  MIT, mas pesado);
- validar **no servidor** a planilha original (o V2 confia nas linhas devolvidas pelo browser);
- unicidade **consultando o banco** (não só intra-arquivo);
- job na fila + `batch_id`, orçamento de linhas/bytes, dry-run com relatório de falhas parciais;
- bloquear **CSV injection** (`=`, `+`, `-`, `@`), detectar encoding uma vez, sem `ini_set` de memória;
- nome de arquivo determinístico (hash do conteúdo), não `time()`;
- LGPD: arquivo privado, retenção e auditoria da importação (ADR-019/035).

**Testes:** encoding ISO-8859-1; cabeçalho com alias; linha inválida não aborta o lote; dry-run não
escreve; duplicata no banco é atualizada, não inserida.

## 4. LandingSections — o contrato que o plano 16 precisa

**Portar:** registry de tipos, schema por bloco, `prepareSections()` que coleta mídia em lote (um
único `whereIn`) e renderização determinística; home como **lista ordenada** `{type, params, hide}`
com defaults por tipo e fallback.

**Traduzir:**
- conteúdo em **jsonb**, nunca HTML (ADR-017); nada de Blade vindo do banco;
- widgets como **classes concretas** com `match` por tipo (sem abstract/interface — ADR-001);
- sanitização por schema (valor inválido ignorado), não `strip_tags`; texto rico via AST (ADR-028);
- mídia via `<x-service-media::picture>` (ADR-026); imagens referenciadas por **ID**, resolvidas no
  prepare;
- preview autenticado e efêmero (cache com TTL + escopo de usuário), sem token solto;
- acessibilidade: um `<h1>` só, ordem de foco = ordem visual (ADR-025).

## 5. FormularioDinamico — maior lacuna, melhor encaixe

**Portar:** versão imutável (`schema` + `scoring_config`), campos com peso/regras, submissão com
`answers` jsonb + GIN, `ip_hash` HMAC, consentimento, scoring por faixas, diagnóstico, resultado por
token, export CSV e agregações.

**Traduzir:**
- `result_token` **assinado** (HMAC) — o V2 promete “URL assinada” mas não assina;
- storage de respostas com retenção/LGPD e auditoria de acesso;
- render por componente Blade + escape central (não string por tipo);
- i18n pt_BR/en/es/fr (ADR-012);
- agregações em SQL (não carregar todas as respostas na memória);
- tipos de campo como classes concretas; validação em `FormRequest`/regra de domínio.

**Nota de escopo:** o V7 não tem item de backlog para formulários. Se for adotado, promover a
`wiki/backlog/servico-forms.md` + ADR (schema/versionamento) antes do código.

## 6. RichText — três extras

1. **Conversor DOCX→AST** (`DocxToTiptapConverter`): ZipArchive, `word/document.xml`, numeração,
   hyperlinks, imagens→Media. Útil para migração **manual** de atos (não é ETL — ADR-042).
2. **Conversor HTML→AST**: descarta `script/style/head/iframe/form`, normaliza `<del>+<ins>` em
   retificação. Útil para colar conteúdo legado no editor.
3. **Live preview** por `postMessage`: o V7 já tem preview server-side; o ganho é UX. Só depois de
   resolver CDN zero (o V2 carrega TipTap de `esm.sh`).

**Rejeitar:** `contentRichHtmlFree`, estilo inline, `searchRecords` por `ILIKE` sem índice.

## 7. DigitalSignature — especificação antes de biblioteca

O V2 resolve o **fluxo** (PFX→X.509→chave cifrada→PAdES→carimbo→log com SHA-256) e falha no que
importa para validade: **sem TSA, sem OCSP/CRL, sem verificação pública**. No V7: decidir biblioteca
compatível com PHP 8.4 e licença permissiva, exigir carimbo do tempo e endpoint de verificação, e
guardar a chave com o mesmo rigor do `EncryptionService` (ADR-020), nunca derivada de `APP_KEY` + IV
ao lado.

## 8. E-mail e notificações

`MailService` tem o que o V7 não tem (**histórico**, config por locatário, template), mas troca o
mailer global e grava corpo completo. Traduzir para: `Mail`/`Notification` nativo, `ShouldQueue`,
config em `.env`/data cifrada, **sem corpo em log** (só metadados), supressão/bounce (backlog
`email-deliverability`), retenção. Não portar `Swift_SmtpTransport` (inexistente no Laravel 12).

## 9. O que portar em uma semana (baixo atrito, alto ganho)

| Item | Esforço | Onde |
|---|---|---|
| Validação por **magic bytes** em upload (Legislação/Licitações) | B | `services/Media` |
| `safe_previous` (anti open-redirect) e sanitizador de snippet SEO | B | `core`/`services/Seo` |
| Partial/anatomia de listagem CMS (`table`, `filter-card`, `empty-state`, `status-badge`) | M | `src/layout/Cms` |
| Envelope `{module, action, target_id, user_id, ts, duration_ms}` no log de domínio | B | já previsto ADR-024; conferir campos |
| Preview por token de rascunho (Notícias) | M | módulo Notícias |
| Publicação agendada por data (Legislação) | B | módulo futuro |
| Importação idempotente `number+year` (Legislação) — sobre o ExcelImporter | M | idem |

## 10. O que **não** trazer (e por quê)

| Item | Motivo |
|---|---|
| Sentinel e `config('v2.support.email')` | bypass por identidade fixa; ADR-033 |
| Níveis `none/read/write` e aliases de módulo | ADR-033 exige 4 ações e token único |
| `ModuleProviderInterface` sem tipos + instanciação por request | ADR-014 (manifesto cacheado, `config(): array` tipado) |
| UUID “v7” (`v2_gen_uuid`) e `v2_uuid()` | são v4; ADR-007 usa `uuidv7()` |
| `HtmlMinify` e CSP por nonce | ADR-022 |
| Blade/HTML vindo do banco (SLE, `contentRichHtmlFree`, `BasicPage.runtime`) | RCE/XSS + ADR-017/028 |
| jQuery/Bootstrap/AdminLTE/Cropper (CDN) | ADR-009/002 |
| Domínio de loteria (SorteSua/Sorteios/SeloOperador) | sem contraparte no V7 |
| `activity_log` do Spatie | ADR-035 (BLAKE3, imutável) |
| S3→local silencioso | ADR-030 (S3 é o disco de domínio; falha tem de ser visível) |

## 11. Sequência sugerida para o V7

1. **Atualizar os itens de backlog existentes** com os detalhes de desenho desta revisão:
   `servico-search`, `servico-excel-importer`, `servico-landing-sections`, `assinatura-digital-icp-brasil`,
   `email-deliverability`.
2. **Criar** `wiki/backlog/servico-forms.md` (motor versionado) — hoje não existe item.
3. Implementar na ordem do backlog consolidado: `Search` (após o 2º consumidor), `ExcelImporter`
   (junto de Transparência), `LandingSections` (junto do plano 16), `FormularioDinamico` (quando houver
   demanda real), `DigitalSignature` (após Legislação).
4. Ao portar, escrever **teste de contrato** por serviço (lista nas seções acima) e medir cobertura
   do novo código (piso 90%).

> **Fronteira.** Esta revisão não promove nenhum item: o `wiki/backlog/REVISAO.md` decide o que pode
> entrar; este documento só diz **como** a V2 já resolveu cada um.
