---
id: REIMPL-PILHA-ALVO
tipo: reimplementacao
onda: 5
status: concluido
unidades: []
fontes:
  - V2/
  - README.md
depende_de: [REIMPL-ORDEM, REIMPL-RISCOS, REIMPL-MIGRACAO, ARCH-OVERVIEW]
consumidores: [equipe-de-reconstrucao, arquiteto, qa, agente-reconstrucao-cega]
criticidade: alta
dono: agente-reimplementacao
---

## Efeito

Registra a **pilha-alvo** da reimplementação e separa duas verdades que o corpus vinha
misturando: o **fato do legado** (o que o V2 faz, documentado nas unidades) e a **decisão
de destino** (como o sistema novo é construído). Sem essa separação, um leitor copia
Bootstrap, Sentinel, nonce por request e `v2_*` como se fossem requisitos.

A decisão adotada é a constituição do `public-v7` (Concordia), em especial as ADR-001
(determinismo, nativo primeiro, simplicidade) e ADR-004 (token canônico grep-friendly),
com a pilha **PHP 8.4 + Laravel 12 + PostgreSQL 18 + Valkey 9**, UI **Blade + Tailwind 4 +
daisyUI 5 + Lucide**, build **Vite**, testes **PHPUnit estrito + Playwright/axe** e
qualidade **PHPStan `max` sem baseline + cobertura ≥ 90% + mutation testing**.

O corpus continua sendo a fonte de **comportamento observável**. Este documento é a fonte
de **como reconstruí-lo**. Em conflito, o comportamento documentado vence apenas onde ele
é contrato externo (URL, status, mensagem, schema semântico, arquivo); a implementação
interna segue a pilha-alvo.

## Abordagem

### 1. Fundamento (ADR-001)

| Princípio | Consequência para a reconstrução da V2 |
|---|---|
| Determinismo | clock, aleatoriedade e geração de ID **injetados**; proibido `now()`/`rand()`/`md5()` no corpo de regra. O `v2_uuid()` global do legado vira porta `IdGen` com UUIDv7. |
| Ordem explícita | descoberta de módulos, sidebar, slots e widgets com ordenação declarada (`position`, `sort`), nunca ordem de diretório/hash. |
| Dados idempotentes | migrations de referência rodam 2× com o mesmo estado; seeds são **só demonstração** (ADR-041), nunca caminho de migração. |
| Nativo primeiro | esgotar FormRequest, Validation, Casts, Events, Jobs, Policies/Gate, Resources, Blade Components, Flysystem, Cache e Scheduler antes de criar classe. |
| Funcional com DI | regras em funções/Actions; dependências por parâmetro; sem `new`/`resolve` no corpo. |
| Simplicidade | sem traits, classes abstratas, genéricos ou `Result<T>`; duplicação eventual é aceita; classes só onde o framework exige. |
| Padronização | Pint + Prettier/ESLint; `make check` como interface única. |

### 2. Pilha e fronteira física (ADR-003/013/014)

| Camada V2 | Destino | Regra |
|---|---|---|
| `V2/Core/` | `src/core/` | fundamento: descoberta, contratos, permissões, auditoria, observabilidade; **não** importa `modules`/`services`. |
| `V2/Services/` | `src/services/<Nome>/` | headless, sempre disponível, contrato no próprio serviço; **não** importa `modules`. |
| `V2/Modules/<Grupo>/<Modulo>/` | `src/modules/<Grupo>/<Modulo>/` | caso de uso autocontido; **não** importa outro módulo (porta/evento do Core). |
| `V2/layouts/{cms,portal}` | `src/layout/{Cms,Portal}` | shell e componentes; views `cms::`/`portal::`; módulo só preenche `<main>` e slots. |
| `V2/Seeds/` | `src/demonstration/` | demonstração; dado de referência vem de migration. |
| `app/` (raiz) | `app/` | só o que o Laravel exige (bootstrap, providers, middleware base). |
| `public/assets/**` (CSS/JS versionados) | build Vite | sem CDN; assets com hash e `immutable`. |

**Raiz:** Laravel 12 típico; sem `Kernel.php`, sem `Handler.php`, providers em
`bootstrap/providers.php`, exceções em `bootstrap/app.php` (`withExceptions`).

### 3. Token canônico (ADR-004)

A identidade é **PascalCase** (pasta, namespace, classe). As demais formas são derivadas,
não nomes criativos. O prefixo `v2_` do legado **não** é token: é sujeira de versão.

| Forma | Uso | Exemplo (`UnidadeRegional`) |
|---|---|---|
| Identidade canônica | pasta/namespace/classe | `Modules\Conexoes\UnidadeRegional` |
| Token de busca | grep/name-check, minúsculo sem separador | `unidaderegional` / regex `unidade[-_]?regional` |
| Kebab | URL, nome de rota, log/span, slot | `unidade-regional`, `cms.unidade-regional.index` |
| Snake | tabela, coluna, permissão, i18n | `unidade_regional`, `unidade_regional.ver` |
| Pascal | classe de ação/evento/teste | `UnidadeRegionalSalvarAction`, `UnidadeRegionalSalvaTest` |

**Preservação de contrato externo:** URLs públicas e nomes de arquivos existentes são
contrato e **não** mudam sem redirect/alias. Nomes internos (rota nomeada, tabela, coluna,
classe) seguem o token. Exemplo: a URL `/cms/noticias` permanece; a rota passa de
`v2.noticias.cms.index` para `cms.noticias.index`; a tabela `v2_news` passa a `noticias` (nome exato no mapa da LG-ALVO-02)
(mapeada na migração de dados).

Tabela de derivação por grupo (o sufixo é a identidade; a URL pública é preservada):

| Grupo | Tokens canônicos |
|---|---|
| Publicações | `Noticias`, `CategoriaNoticia`, `Agenda`, `TrabalheConosco` |
| Conexões | `UnidadeRegional`, `Associado`, `ParceiroInstitucional` |
| Institucional | `Historia`, `FaleConosco`, `AssocieSe`, `SobreNos` |
| Layouts | `Homepage`, `PaginaFixa` |
| Infraestrutura | `CertificadoDigital`, `GestaoPermissoes`, `FeedRss`, `MailAudit` |
| Support | `ConfiguracaoSuporte`, `EditorEstrutural`, `ImportacaoNoticias` |
| Serviços | `Midia`, `Galeria`, `EditorRico`, `EditorSecoes`, `Seo`, `Busca`, `ImportadorPlanilha`, `Armazenamento`, `AssinaturaDigital`, `Auditoria`, `Mail`, `Dashboard`, `FeedRss` |
| Core/Layout | `Autenticacao`, `Permissao`, `CachePagina`, `Csp`, `LayoutCms`, `LayoutPortal` |

### 4. Substituições nativas obrigatórias

| Legado V2 | Alvo | Observação |
|---|---|---|
| Sentinel (`users`, `roles`, `persistences`, `activations`, `reminders`, `throttle`) | auth nativa do Laravel 12 + `Gate`/`Policy` + tabela de perfis | manter semântica de papel/permissão e as mensagens literais; não portar o pacote. |
| `v2_roles.permissions_v2` + `v2_can()` + `@v2can` | `Permission`/`Gate` + `@can` | `none|read|write` vira ability; suporte/`super-admin` explícito, não bypass implícito. |
| `v2_uuid()` (v4) | `IdGen` injetado, UUIDv7 | PK e FKs seguem `uuid` no PostgreSQL 18. |
| `V2ServiceProvider` varrendo diretórios a cada boot | `ModuleDiscovery` + manifesto em cache (`bootstrap/cache/modules_manifest.php`) | mantém `ModuleProvider.php` como único arquivo de declaração; sidebar sem consulta ao banco. |
| `PageCacheMiddleware` + `Cache-Control` + `X-Cache-Status` | middleware fino de ETag/304 + FPC opcional em Valkey | preservar a semântica de 300 s; cache público só para GET sem formulário; nunca cachear HTML com nonce. |
| `CspMiddleware` com nonce por request e `script-src-attr 'unsafe-inline'` | CSP estática/hash-based, sem inline, Trusted Types no CMS | o legado injeta nonce por regex; no alvo, nenhum `<script>`/`onclick=` inline. |
| `HtmlMinify` | **removido** | compressão fica em brotli/gzip; minificar HTML em runtime é frágil. |
| Bootstrap 5 + jQuery + AdminLTE + Select2/Owl/toastr | Blade + Tailwind 4 + daisyUI 5 + Lucide; JS pequeno vendorizado | componentes documentados em `04_ui/` são **comportamento/DOM**, não classes CSS obrigatórias. |
| `ContentRichEditor` (TipTap + AST + parser PHP) | `src/services/RichText` com TipTap + AST JSON + renderers | arquitetura aprovada na ADR-028; **manter** o parser. |
| Blocos especiais do editor (HTML livre, FAQ, carrossel, cards, passos, tabela interativa, barra de comandos) | **descartados** | ADR-028: sem nó de HTML livre (XSS); conjunto sóbrio de blocos. |
| `LandingSectionsEditor` (jQuery/Bootstrap/Owl) | widgets Blade + registry, JS mínimo | preservar o contrato de registry e a ordem dos slots; reimplementar os 21 widgets padrão como componentes. |
| Imagem crua em `<img>` e variantes WebP próprias | serviço Media + `<picture>` (AVIF/WebP, larguras) | ADR-026; upload valida MIME real e tamanho. |
| `activity_log` (spatie) | serviço de auditoria do Core | manter `log_name`/`event`/`subject`/`properties` como contrato de consulta. |
| Busca própria (`v2_public_search_index`/`v2_cms_links_index`) | full-text nativo do PostgreSQL (`tsvector`/`whereFullText`) ou tabela própria | decidir na E5; o contrato é o ranking e os limites 20/10, não o índice. |
| `StorageService` + adaptadores | Flysystem nativo (`Storage::disk`) | manter chave relativa e URL `/storage/<path>`; S3/RustFS por disco. |
| `MailService` + `v2_mail_logs` | Mail nativo + listener de log | manter `sent`/`failed`, `MailResult` e o painel MailAudit. |
| `v2_cms_theme_configs` + CSS do AdminLTE | tema/layout como **dado** (jsonb) com precedência e slots | ADR-016/036: shell não injeta CSS de tema; nome/logo/favicon e presets viram dados. |
| Erros JSON (`{"error":...}`) | RFC 7807 onde o contrato permitir | ADR-024; preservar status e mensagem literal nos endpoints já consumidos. |
| Throttle pontual | rate limiting day-zero (login, formulários, API) | ADR-021; `429` com corpo de erro explícito. |
| SEO (metas + sitemap/robots) | serviço SEO + `@graph` + arquivos-raiz | ADR-027; preservar slugs, canonical e precedência documentada. |
| Página `/lgpd` estática | programa LGPD (classificação, DSAR, retenção, incidentes) | ADR-019; a página sozinha não cumpre o programa. |
| Seeds de conteúdo | `src/demonstration/` | dado de referência idempotente em migration; seed não migra dado real. |
| PHP 7.4 / Laravel 5.5 / Postgres 10 / PHPUnit 6 | PHP 8.4 / Laravel 12 / PG 18 / PHPUnit 13 | R-19 deixa de ser risco aberto; contratos são testados na pilha nova. |

### 4.1 PHP 8.4 e Laravel 12: o que usar e o que não emitir

| Usar | Evitar |
|---|---|
| `declare(strict_types=1)`, enums para estado, `readonly` para DTOs, property hooks para acesso derivado, `#[\Override]`, `array_find`/`array_any`. | `create_function`, `each()`, `mcrypt_*`, `(real)`, `FILTER_SANITIZE_STRING`, `lcg_value`, `rand()`/`mt_rand()` para segredo. |
| FormRequest/Validation, Policies/Gate, Resources, casts nativos, jobs/eventos, `bootstrap/app.php` + `bootstrap/providers.php`. | `app/Http/Kernel.php`, `app/Exceptions/Handler.php`, providers em `config/app.php`, `routes/api.php` sem `install:api`. |
| `DB::transaction`, `afterCommit`, eager loading, `cursor`/`lazyById`, full-text nativo. | `env()` fora de config, `$request->all()` em create/update, N+1, SQL concatenado. |
| Blade `{{ }}`, componentes, slots; JS vendorizado sem inline. | `{!! !!}` com entrada de usuário, handlers `onclick=`, scripts inline. |

### 5. Fronteira de fidelidade

| Preservar | Pode mudar |
|---|---|
| URL, método, status, headers e mensagens literais de erro de negócio | classe/namespace, nome de rota nomeada, biblioteca de auth |
| Efeito transacional, tabelas/colunas **semânticas**, chaves, índices, soft delete | nome físico de tabela/coluna (com mapa de migração) |
| Chaves de storage, caminhos de arquivo e formato de URL de mídia | pipeline de assets, CSS classes, DOM interno de componentes |
| JSON de resposta, payload de webhook, formato de AST e e-mail | `eval`, HTML livre, nonce por request, minificação |
| Regras de negócio, precedências, ordenações e limites | biblioteca de UI, jQuery, Bootstrap, AdminLTE |
| Acessibilidade: atalhos, skip links, preferências, VLibras | meta de conformidade: **eMAG 3.1 + WCAG 2.2 AA** (ADR-025), não “AAA” por declaração |

### 6. Conflitos resolvidos

| Ponto | Corpus (legado) | Decisão alvo |
|---|---|---|
| UI | Bootstrap 5/jQuery; AdminLTE inerte | Tailwind 4/daisyUI/Lucide; shell `Layout\Cms`; sem framework reativo (ADR-009). |
| Editor | 26 nós + 7 marks, blocos especiais, HTML livre | TipTap único, AST jsonb, renderers PHP; blocos especiais descartados (ADR-028). |
| CSP/cache | nonce por request + `unsafe-inline` + HTML minify | CSP hash estática + ETag/304; sem minify (ADR-020/022). |
| A11y | “WCAG AAA/eMAG 3.1” em README, sem auditoria | eMAG 3.1 + WCAG 2.2 AA como gate; AAA só onde não custa contrato (ADR-025). |
| Auth | Sentinel + bypass de suporte | auth nativa + abilities explícitas; suporte é perfil, não bypass (ADR-033). |
| IDs | UUIDv4 gerado por helper | UUIDv7 por `IdGen` injetado (ADR-007). |
| Dados | seeds misturados com referência | seeds demo; referência em migration idempotente (ADR-017/041). |
| Conteúdo legado | ETL com `legacy_mapping` e quarentena | decisão de produto: ETL **ou** entrada manual; ver §7 e ADR-042. |
| Tabelas | nomes `v2_*` | token canônico sem prefixo; mapa `v2_* → *` na migração. |

### 7. Migração de conteúdo: duas modalidades

O corpus descreve um ETL (M0–M9). A filosofia do `public-v7` (ADR-042) prefere base nova
com conteúdo migrado **à mão** pelo CMS, sem camada de compatibilidade. A escolha depende
de um fato que o corpus não tem: exigência de histórico/URLs antigas.

- **Modo A — cutover com ETL:** necessário se o acervo for grande e houver exigência de
  preservar IDs, datas, autoria e URLs. Executar `migracao-de-dados.md` como escrito,
  com schema de destino novo e mapa de nomes.
- **Modo B — greenfield com curadoria:** base nova; conteúdo entra pelo CMS; `301`
  curados em `seo.redirects`; sem `legacy_mapping`, sem quarentena. Recomendado quando o
  volume é pequeno e a revisão editorial é obrigatória de qualquer forma.

Em ambos: segredos (APP_KEY, certificados, SMTP) são custodiados; logs/índices/feed são
reconstruídos, não copiados; `backup_*` não é migrado.

### 8. Gates de aceite

| Camada do corpus | Gate alvo |
|---|---|
| A1 contrato HTTP | PHPUnit feature + Playwright; snapshot de rotas; status/mensagens literais. |
| A2 contrato de dados | migrations + `assertDatabaseHas`; idempotência 2×; sem `backup_*`. |
| A3 contrato de serviço | testes de ação/serviço; mutation testing nos caminhos críticos. |
| A4 contrato de UI/JS | Playwright + axe; DOM ids/eventos; CSP sem inline; sem regressão visual. |
| A5 integração | indexação, feed, cache/ETag, e-mail, storage e auditoria ponta a ponta. |
| Transversal | PHPStan `max` sem baseline; Pint/Prettier/ESLint; `make check` quente ≤ 100 s; cobertura ≥ 90%. |

## Particularidades

1. **O corpus não é a arquitetura.** Ele prova o que o V2 faz; a pilha-alvo decide como
   fazê-lo. Copiar `v2_*`, Sentinel ou Bootstrap porque “está documentado” é erro de
   leitura, não fidelidade.
2. **A URL é o contrato mais forte.** Nome de tabela, classe e rota nomeada podem mudar;
   URL pública, status e mensagem não, salvo decisão registrada com redirect.
3. **O editor é o único caso de “copiar a arquitetura”.** A ADR-028 adota explicitamente
   o desenho AST + parser PHP do `sucesu-cms`, mas reduz o conjunto de blocos e remove
   HTML livre.
4. **Acessibilidade é gate, não comentário.** O legado declara AAA sem auditoria; o alvo
   é eMAG 3.1 + WCAG 2.2 AA verificado por axe e checklist manual.
5. **Determinismo muda o teste.** Com clock/ID injetados, `freezeTime` e IDs previsíveis
   tornam os testes de cache, feed e auditoria reproduzíveis; `now()` no corpo de regra
   quebra o gate.
6. **A decisão de migração é de produto.** O corpus não pode escolher entre ETL e
   curadoria manual; §7 torna a escolha explícita e evita que o ETL vire default silencioso.

## Integrabilidade

### Receitas de uso

**1. Decidir o destino de um artefato V2.**

```text
1. Ache a unidade em 05_modulos/... ou 03_servicos-ui/....
2. Separe: contrato externo (URL/status/mensagem/schema semântico) × mecanismo interno.
3. Aplique a tabela §4 para o mecanismo.
4. Derive o token pelo §3; registre o mapa v2_* → token no plano de migração.
5. Escreva o teste A1–A5 correspondente antes de portar o corpo.
```

**2. Criar um módulo novo (após a fundação).**

```php
// src/modules/Publicacoes/Noticia/ModuleProvider.php — único arquivo de declaração
declare(strict_types=1);
namespace Modules\Publicacoes\Noticia;

use Core\Contracts\ModuleProvider as ModuleProviderContract;

final class ModuleProvider implements ModuleProviderContract
{
    public function register(): void {}
    public function config(): array
    {
        return ['title' => 'Notícias', 'icon' => 'newspaper', 'position' => 2,
                'route' => 'cms.noticia.index'];
    }
}
```

**3. Consumir outro módulo sem importá-lo.**

```php
// ❌ proibido: Modules\...\Noticia importado por outro módulo
// ✅ porta no Core; o módulo de origem registra a implementação no provider
interface UltimasNoticias { public function recentes(int $limite): array; }
```

**4. Portar um componente de UI documentado.**

```text
Bootstrap `.card` + jQuery `.modal` → componente Blade + daisyUI (`<x-cms::card>`,
`<dialog>` nativo) com os mesmos ids/eventos/aria documentados em 04_ui/.
```

### Anti-uso

1. **Copiar classes CSS Bootstrap para o alvo.** O corpus documenta o DOM/estado; o CSS é
   Tailwind/daisyUI. Copiar `.btn btn-primary` recria o débito que a ADR-009 descarta.
2. **Portar Sentinel “para manter paridade”.** A paridade é de papel, permissão, sessão e
   mensagem; o pacote EOL não é contrato.
3. **Manter nonce por request porque o legado usa.** Isso inviabiliza ETag/304 e cria a
   *static nonce vulnerability* (ADR-022). A CSP alvo é estática.
4. **Criar tabela `v2_*`.** O prefixo não é token; use o nome canônico e mapeie na
   migração. `v2_*` só aparece em documento histórico, nunca no schema novo.
5. **Tratar seed como migração.** Seed é demonstração; dado real entra por ETL ou pelo
   CMS, com idempotência e trilha.
6. **Usar `public-v7` como código a importar.** É referência de arquitetura e decisão;
   copiar classes entre projetos viola a fronteira e o token (ADR-004/013).

## Lacunas

| ID | Lacuna | Impacto | Como resolver |
|---|---|---|---|
| LG-ALVO-01 | Modalidade de migração (A ou B) não decidida | define se o ETL M0–M9 é necessário | decisão do dono com base em volume, histórico e URLs |
| LG-ALVO-02 | Nome físico das tabelas/colunas alvo | quebra joins e relatórios durante a transição | mapa `v2_* → token` aprovado antes da E1 |
| LG-ALVO-03 | Biblioteca de planilhas para o Importador | ADR-002 exige licença permissiva e dependência mínima | avaliar `openspout` (MIT) ou parsing nativo; registrar ADR |
| LG-ALVO-04 | Assinatura de PDF no alvo | o legado usa biblioteca própria; PHP 8.4 tem `sodium`/OpenSSL | reavaliar `PdfSigner` e manter `CERT_*`/`SIG_*` como contrato |
| LG-ALVO-05 | Busca: full-text nativo ou tabela própria | afeta ranking e reindexação | protótipo com `tsvector` na E5; comparar com os 20/10 resultados |
| LG-ALVO-06 | Conformidade AAA em telas específicas | pode haver exigência legal além de AA | auditoria por tela; AA é o piso, AAA é exceção documentada |

## Evidências

- `public-v7/wiki/adr/ADR-001-nativo-funcional-di-simplicidade.md` — determinismo,
  nativo primeiro, sem traits/abstrações.
- `public-v7/wiki/adr/ADR-004-grep-friendly-token-canonico.md` — token único e formas
  derivadas.
- `public-v7/wiki/adr/ADR-009-ui-cms-proprio-tailwind-daisyui.md` — crítica explícita ao
  Bootstrap/jQuery do `sucesu-cms` e decisão Tailwind/daisyUI/Lucide.
- `public-v7/wiki/adr/ADR-013-ddd-lite-fronteira-fisica.md` — fronteira `core/services/
  layout/modules` e proibição de import entre módulos.
- `public-v7/wiki/adr/ADR-014-autodescoberta-modulos-agrupamento.md` — descoberta por
  pasta + `ModuleProvider` + manifesto em cache.
- `public-v7/wiki/adr/ADR-020-seguranca-web-moderna.md` e `ADR-022` — CSP estática,
  ETag/304, sem HTML minify, CSRF fora do HTML cacheável.
- `public-v7/wiki/adr/ADR-028-editor-rico-tiptap.md` — adoção do AST/parser do
  `sucesu-cms`, remoção de HTML livre e blocos especiais.
- `public-v7/wiki/adr/ADR-038-cobertura-90-e-rigor-de-nao-regressao.md` e `ADR-040` —
  cobertura ≥ 90%, PHPStan `max` sem baseline, mutation.
- `public-v7/wiki/adr/ADR-041-seeds-exclusivamente-demonstracao.md` e `ADR-042` — seeds
  demo, base nova e conteúdo manual.
- `public-v7/.agents/skills/php-84-correct/SKILL.md` — tipagem, segurança e performance
  PHP 8.4.
- `public-v7/.agents/skills/laravel-12/SKILL.md` — `bootstrap/app.php`,
  `bootstrap/providers.php`, Eloquent/Blade/validação nativos.
- `01_arquitetura/00-visao-geral.md` — camadas e boot do legado.
- `01_arquitetura/03-auth-rbac-sentinel.md` — Sentinel, perfis e bypass de suporte.
- `01_arquitetura/09-cache-csp-minify-maintenance.md` — nonce por request, cache de 300 s
  e minify.
- `04_ui/01-cms-design-system.md` — Bootstrap/AdminLTE e acessibilidade do shell.
- `03_servicos-ui/content-rich-editor/spec.md` — AST, parser e blocos especiais.
- `05_modulos/README.md` — declaração de eMAG/WCAG AAA sem auditoria.
- `09_reimplementacao/riscos.md` — R-19 e as lacunas LG-REIMPL-11/12 agora resolvidas.
