---
id: MATRIZ-SINGULARIDADES
tipo: matriz
onda: 5
status: concluido
unidades: []
fontes:
  - V2/Core/
  - V2/Services/
  - V2/Modules/
  - V2/layouts/
  - V2/Seeds/
depende_de: [ARCH-OVERVIEW, CORE-BOOT, CORE-AUTH, CORE-DATA, CORE-CMS, CORE-RUNTIME, UI-CMS, UI-PORTAL]
consumidores: [MATRIZ-PERMISSOES, MATRIZ-ENTIDADES, MATRIZ-INTEGRACOES, MATRIZ-FLAGS, MATRIZ-RECONCILIACAO, REIMPL-PARIDADE]
criticidade: alta
dono: Matriz
---

# Singularidades: índice de leitura para reimplementação

Este documento responde, para cada uma das **56 unidades** do manifest
(`00_inventario/manifest.json`), quatro perguntas em uma linha: o que a unidade
faz de observável, o que só ela faz, como ela se conecta ao resto e o que deixa
de existir se for removida. Ele é o mapa de entrada do corpus: quem reimplementa
lê esta tabela primeiro, escolhe a unidade e aprofunda no documento de unidade
correspondente.

## 1. Efeito

### Ficha de identidade

| Campo | Valor |
|---|---|
| Efeito primário | Ordena as 56 unidades por camada e dá, para cada uma, efeito, singularidade, integração e impacto de remoção, com a fonte canônica da afirmação. |
| Entrada | `00_inventario/manifest.json` (930 arquivos, 56 unidades); fichas de identidade dos documentos de unidade existentes; `_indices/{rotas,tabelas,componentes,servicos}.csv`. |
| Saída | 56 linhas de leitura; lista de sobreposições e contradições entre unidades; ordem recomendada de reimplementação. |
| Efeitos colaterais | Nenhum em runtime; é documento de leitura. |
| Particularidade central | O corpus tem **quatro famílias de editores** (CRE, LSE, SLE, BasicPage/Homepage) e **duas autorizações** (Sentinel e RBAC V2); a tabela evita tratá-las como uma coisa só. |
| Como se integra | Cada linha aponta o documento dono e o índice canônico; a coluna “Fonte” é a evidência mínima. |
| Se removido, quebra | Nada em runtime; a leitura deixa de ter um ponto único de entrada e as sobreposições voltam a ser descobertas arquivo a arquivo. |
| Superfície pública | Documento markdown; sem código. |

### Números do recorte

| Medida | Valor | Fonte |
|---|---|---|
| Arquivos no manifest | 930 | `00_inventario/manifest.json` |
| Unidades | 56 | `00_inventario/manifest.json` |
| LOC somadas | 174.617 | soma de `units[].loc` em `00_inventario/manifest.json` |
| Documentos de unidade (onda 1–5) | 56 das 56 unidades com doc no fechamento desta matriz | `tools/coverage.py --docs` |
| Rotas canônicas | 301 linhas (262 endpoint, 4 redirect, 33 grupo, 2 “rota”) | `_indices/rotas.csv` |
| Tabelas canônicas | 60 linhas (57 atuais + 3 históricas) | `_indices/tabelas.csv` |
| Componentes canônicos | 386 linhas | `_indices/componentes.csv` |
| Permissões canônicas | 67 linhas | `_indices/permissoes.csv` |
| Configurações canônicas | 166 linhas | `_indices/config.csv` |
| Serviços canônicos | 13 linhas | `_indices/servicos.csv` |

## 2. Abordagem

A tabela foi montada em três passos:

1. **Ficha primeiro.** Para unidade com documento, a coluna “Efeito” reproduz a
   ficha de identidade do doc dono (campo *Efeito primário*), e “Único”,
   “Integra” e “Quebra” vêm de *Particularidade central*, *Como se integra* e
   *Se removido, quebra*. Exemplo: `05_modulos/Publicacoes/Noticias/spec.md:29-35`.
2. **Medição depois.** Para unidades sem documento no momento da síntese
   (`MOD-INSTITUCIONAL-SOBRENOS`, `DATA-SEEDS-*`, `GRP-*`), a linha foi derivada
   do código e do manifest, com citação do arquivo pivô.
3. **Confronto.** Cada linha foi comparada com os índices canônicos; quando a
   ficha e o índice divergem (por exemplo, unidade sem rota no CSV), a
   divergência vai para §4 e para `reconciliacao-indices.md`.

### Como ler a tabela

- **Efeito** = o que muda no mundo (tela, linha, arquivo, e-mail, índice, cache).
- **Único** = o mecanismo que não se repete em outra unidade.
- **Integra** = a superfície pública real (namespace, rota, classe, props).
- **Quebra** = consumidores diretos e indiretos; “nada em runtime” é resposta
  legítima para documento puro.

## 3. As 56 unidades

### 3.1 Fundação e arquitetura

| Unidade (arquivos/LOC) | Efeito primário | O que é único | Como se integra | Se removido, quebra | Fonte |
|---|---|---|---|---|---|
| `ARCH-OVERVIEW` (1/28) | Descreve o contrato de pastas que faz o V2 existir; não executa nada. | É o único documento que declara o diretório como mecanismo de integração. | Leitura de `01_arquitetura/00-visao-geral.md`; aponta `V2ServiceProvider`. | Nada em runtime. | `01_arquitetura/00-visao-geral.md:21-27` |
| `CORE-BOOT` (9/565) | Uma pasta em `V2/Modules` ou `V2/Services` passa a ter rotas, views e migrations sem registro manual; o fallback `/{slug}` é registrado por último. | O nome do diretório vira namespace PHP, namespace de view, prefixo de API e chave de permissão; não há `RouteServiceProvider` substituto. | `V2ServiceProvider` em `config/app.php`; `ModuleProviderInterface`; `v2.modules.configs`. | Nenhuma rota do portal ou CMS é registrada. | `V2/Core/Providers/V2ServiceProvider.php:85-137`; `01_arquitetura/01-boot-autodiscovery.md:24-30` |
| `CORE-AUTH` (19/2223) | Autentica no CMS (Sentinel) e autoriza por módulo (`v2_roles.permissions_v2`), com dois bypasses (e-mail de suporte e role `super-admin`). | Duas autorizações independentes; `super-admin` não é semeado; o e-mail de suporte é a identidade de maior poder. | `CmsAuthenticate` chama `V2PermissionMiddleware`; `PermissionService`; `v2_can`/`@v2can`; `InternalApiKey`. | Todo o CMS, sidebar, Gestão de Permissões e escopo regional. | `01_arquitetura/03-auth-rbac-sentinel.md:51-57`; `V2/Core/Middleware/CmsAuthenticate.php:18-45` |
| `CORE-CMS` (9/801) | Entrega a classe-base, o dashboard, a busca administrativa, o CRUD de tags de conexão, os helpers globais e a sidebar. | `SidebarComposer` monta o menu de um array em memória e **ignora `position`**; 11 helpers globais `v2_*`. | `BaseController`; `DashboardCmsController`; `SearchController`; `ConexaoTagCmsController`; `@include('v2-cms::layouts.sidebar')`. | `GET /cms`, `/cms/search`, `/cms/conexao-tags`, o menu lateral e os helpers usados por 56/83/19 arquivos. | `01_arquitetura/07-controllers-core.md:32-38`; `01_arquitetura/08-helpers-composers.md:27-33` |
| `CORE-DATA` (6/616) | Gera UUID v4 em PHP/SQL, mantém o catálogo compartilhado `v2_conexao_tags`, deriva a categoria `regional-<sigla>` e aplica escopo regional. | O README promete UUIDv7, mas os geradores produzem **v4**; `RegionalScopeService` não importa model de módulo, só o contrato `RegionalOwnable`. | `v2_uuid()`; `RegionalIdentityService`; `RegionalScopeService`; trait `ApiResponse`. | FKs, seeds de migration, categorias regionais, escopo de listagem e envelope de API. | `01_arquitetura/05-persistencia-uuid-migracoes.md:24-30`; `V2/Core/Services/RegionalScopeService.php:38-141` |
| `CORE-RUNTIME` (5/472) | Minifica HTML, injeta CSP com nonce, cacheia páginas públicas (Redis 5 min) e responde 503 em manutenção. | A ordem `Csp → HtmlMinify → PageCache → PublicCache` é o contrato; o corpo cacheado nunca contém nonce. | Aliases `maintenance.v2`, `page.cache`, `public.cache` no Kernel; grupos `web` do Core, módulos, serviços e fallback. | CSP, compressão, cache de página e bloqueio de manutenção. | `01_arquitetura/09-cache-csp-minify-maintenance.md:30-36` |

### 3.2 Serviços compartilhados

| Unidade (arquivos/LOC) | Efeito primário | O que é único | Como se integra | Se removido, quebra | Fonte |
|---|---|---|---|---|---|
| `SVC-ACTIVITYLOGGER` (5/400) | Grava uma linha em `activity_log` por chamada explícita e renderiza timeline no CMS e selo de atualização no portal. | Nada é auditado automaticamente (trait `LogsActivity` comentado); sem diff; retenção de 365 dias não agendada. | `ActivityLoggerService::log(Model,...)`; views `v2-service-activitylogger::cms.timeline` e `::portal.last-updated`. | 116 chamadas de `log()` em 36 arquivos (53 arquivos referenciam o serviço), auditoria de permissões, selo do portal, painel de suporte. | `02_servicos-base/activity-logger.md:21-27`; `_indices/servicos.csv` |
| `SVC-DASHBOARD` (1/744) | Executa 12 chamadas de consulta estáticas (10 contadores de conteúdo + 2 de sistema) em `GET /cms` e devolve 5 datasets para a view do dashboard. | Agregador sem cache, cada card protegido por `class_exists` + flag e `try/catch` mudo; dois métodos públicos são código morto. | `DashboardStatsService` por autowiring; `v2-cms::dashboard`. | `GET /cms` responde 500 (controller exige o serviço no construtor). | `02_servicos-base/dashboard.md:21-27`; `V2/Core/Controllers/DashboardCmsController.php:7` |
| `SVC-CONTENTRICHEDITOR` (85/6219) | Serializa o Tiptap como JSON AST e converte o mesmo JSON em HTML/Markdown no portal. | Editor JS e renderer PHP são dois mundos sem validação; 4 nós emitem HTML cru; atributos fora do schema são descartados. | `ContentRichEditorRendererService::toHtml`; componente `v2-service-contentricheditor::components.forms.content-rich-editor`; `ContentASTParser`. | Formulários de Notícias, Sobre Nós, História, Parceiros, Unidade Regional, Associados, Associe-se e Trabalhe Conosco; previews. | `03_servicos-ui/content-rich-editor/spec.md:35-41` |
| `SVC-DIGITALSIGNATURE` (23/2592) | Importa PKCS#12, cifra a chave privada por usuário e assina PDFs com PKCS#7 detached. | Chave derivada de `sha256(APP_KEY + '\|v2-digital-signature\|' + userId)` sem KDF; PDF é reconstruído por FPDI, não incremental; sem PAdES/TSA. | `DigitalSignatureService`; `PdfSigner`; `CertificateRepository`; tabelas `v2_digital_certificates` e `v2_signature_logs`. | Certificado Digital (index/store/sign/show/destroy) e o único consumidor HTTP do serviço. | `02_servicos-base/digital-signature/spec.md:21-27`; `V2/Services/DigitalSignature/PdfSigner.php:61-328` |
| `SVC-EXCELIMPORTER` (15/2929) | Converte XLSX/XLS/CSV em relatório de validação e persiste linhas por callback do consumidor. | Schema declarativo + validação Poka-Yoke + persistência por callback; só a primeira aba é lida. | `ImportExcelService`; `ImportExcelSchema`; views `excel-importer::components.*`; `ExcelTranspilerService`. | `SpreadsheetOptimizer` (variantes CSV/HTML de planilhas) e qualquer importação guiada. | `03_servicos-ui/excel-importer/spec.md:21-27` |
| `SVC-FEEDRSS` (10/998) | Mantém `v2_feed_rss_items` como cache desnormalizado e serializa `/feed.xml` em RSS 2.0. | UPSERT por `(entity_type, entity_id)` sobre tabela com soft delete e unique sem filtro: item removido não pode ser reinserido. | `FeedSender`; `FeedRssService`; rota `v2.feedrss.feed`; painel do módulo Feed RSS. | `/feed.xml` (404), painel de monitoramento e republicação automática de Notícias/Agenda/Vagas. | `02_servicos-base/feed-rss.md:21-27` |
| `SVC-GALLERY` (21/2586) | Recebe upload ou ID existente, grava original e variantes, registra em `v2_gallery_media` e devolve a mídia. | Único registro global de mídia; autorização só por igualdade de `owner_module`, sem `CmsAuthenticate` nas rotas CMS (SEC-G1-01); picker é single-select e só o primeiro da página recebe JS. | `GalleryService`; `GallerySender`; `GalleryConfig`; rotas `v2.gallery.*`; evento `lotep:open-gallery-picker-<pickerId>`. | Todas as telas do CMS (o layout inclui o picker) e uploads de 15 unidades. | `03_servicos-ui/gallery/spec.md:24-30`; `V2/Services/Gallery/Routes/cms.php:5-13` |
| `SVC-LANDINGSECTIONSEDITOR` (86/7067) | Converte lista JSON de seções em editor CMS e em HTML de portal por widget registrado; não persiste a lista. | Registry estático com precedência módulo>padrão; 22 forms/renders, 21 tipos registrados (`video` órfão); preview sanitizado por `strip_tags`. | `WidgetRegistry::register`; `LandingSectionsEditorRendererService`; 10 rotas `/cms/v2/landing-sections/*`; 22 forms + 22 renders. | Editores e páginas de Homepage e Sobre Nós; preview e endpoints de mídia. | `03_servicos-ui/landing-sections-editor/spec.md:21-27`; `V2/Services/LandingSectionsEditor/Services/LandingSectionsEditorRendererService.php:35-80` |
| `SVC-MAILSERVICE` (7/906) | Envia SMTP por profile de `v2_system_mail_configs`, grava tentativa em `v2_mail_logs` e devolve `MailResult`. | Falha de envio nunca vira exceção; driver é ignorado (sempre `Swift_SmtpTransport`); corpo final é persistido. | `MailService::send/test/getConfig/getHistory`; `MailApiController` em `/api/v2/mail/*`; view de e-mail. | MailAudit, FaleConosco, Associe-se, SLE e SupportConfigs. | `02_servicos-base/mail-service.md:21-27` |
| `SVC-MEDIA` (14/2385) | Valida MIME, grava original e gera derivados por tipo (WebP, capa de PDF, CSV/HTML). | Único pipeline de validação/otimização, mas **não cataloga**: quem insere em `v2_gallery_media` é a Galeria; `$disk` é ignorado. | `MediaInputer`; `ImageOptimizer`; `PdfVisualOptimizer`; `ImageRedigestService`; views `v2-service-media::components.*`. | Upload da Galeria, do editor rico, logos/banners do SLE e 58 inclusões de `picture`. | `03_servicos-ui/media/spec.md:21-27` |
| `SVC-SEARCH` (9/887) | Mantém `v2_public_search_index` e `v2_cms_links_index` e responde `/busca` (20) e `/cms/search` (10). | Projeção denormalizada de 8 modelos, sem FK/fila; URL pública vem de um switch por `module`; tags não são pesquisadas; sem paginação/escopo regional. | `SearchService::publicSearch/cmsSearch`; `PublicIndexerService`; `CMSIndexerService`; hooks `saved/deleted`; comando `v2:reindex-public`. | `/busca`, `/cms/search`, seletor de links/iframes do CRE e ranking do dashboard. | `03_servicos-ui/search/spec.md:22-28` |
| `SVC-SEO` (8/1482) | Preenche `<head>` (title/meta/OG/Twitter/canonical/JSON-LD), serve `robots.txt`/`sitemap.xml` e registra visitas. | Único ponto que converte estado de request em metadados; precedência `metadata[seo] > controller/modelo > v2_portal_configs > literal`. | `SEOService`; `SeoPortalController`; `v2-service-seo::components.seo-input`; composer em 8 views de metadata. | Todo `<head>` do portal, `robots.txt`, `sitemap.xml`, ranking do dashboard e 24 controllers que referenciam o serviço. | `03_servicos-ui/seo/spec.md:21-27` |
| `SVC-STORAGE` (6/832) | Grava, lê, apaga e resolve URL de arquivos em disco local ou S3. | Sem credenciais, `media_disk='s3'` resolve `LocalAdapter('s3')`; `S3Adapter` faz fallback para `public` sem mudar `getDisk()`. | `StorageService`; `v2_storage_url()`; `UploadService`; `MediaInputer`; `GalleryService`. | Helpers de URL, uploads do CMS, Galeria, Media, seeders de SLE/BasicPage. | `02_servicos-base/storage.md:21-27` |

### 3.3 UI global

| Unidade (arquivos/LOC) | Efeito primário | O que é único | Como se integra | Se removido, quebra | Fonte |
|---|---|---|---|---|---|
| `UI-CMS` (37/2329) | Todo o CMS é um HTML5 `pt-BR` com skip-link, header, sidebar filtrada, `<main id="main-content">` e seções Blade. | Bootstrap 5 puro com CSS AdminLTE residual (`skin-blue`, `.main-sidebar`) que nenhuma folha usa; 23 blades reutilizáveis. | `@extends('v2-cms::layouts.app')`; seções `page-actions`, `page-breadcrumbs`, `css`, `content`, `scripts`; `@include('v2-cms::partials.*')`. | Todas as telas de módulo, dashboard, erros 403/404/500/503, busca e login (assets). | `04_ui/01-cms-design-system.md:25-31`; `04_ui/02-cms-componentes.md:25-31` |
| `UI-PORTAL` (50/3147) | Todo o portal herda `base → app-layout → partials.portal-content`, com header, busca, conteúdo, rodapé e erros. | Não há sistema de componentes: parciais recebem variáveis por escopo e usam `$layoutConfigs->has()` (Collection obrigatória). | `@include('v2-portal::<área>.<arquivo>')`; `@component(...main-content)`; `sle_component()`. | 35 blades que estendem `app-layout`, 5 páginas de erro, busca global e o SLE. | `04_ui/03-portal-design-system.md:63-69`; `04_ui/05-portal-componentes.md:22-28` |

### 3.4 Módulos de negócio

| Unidade (arquivos/LOC) | Efeito primário | O que é único | Como se integra | Se removido, quebra | Fonte |
|---|---|---|---|---|---|
| `MOD-PUBLICACOES-NOTICIAS` (42/9954) | Mantém o acervo editorial, publica `/noticias` e `/noticia/{slug}`, gera `news-sitemap.xml`, indexa busca e alimenta feed e widgets. | Categoria e regional são derivadas no servidor (`regional-<sigla>`); slug é recalculado em PHP e único no banco; workflow de aprovação foi removido por migration. | Rotas `v2.noticias.*`; model `News` implementa `RegionalOwnable`; hooks `NewsSearchSender`/`FeedSender`; 8 tabelas. | Portal de notícias, sitemap Google News, importação, API regional e widgets da Homepage. | `05_modulos/Publicacoes/Noticias/spec.md:29-35` |
| `MOD-PUBLICACOES-AGENDA` (14/2135) | Cria/edita/arquiva eventos e publica agenda filtrável por data/semana/mês. | `published_at` e `is_active` são eixos independentes; listagem exige os dois, detalhe só `published`, sitemap ignora ambos. | Rotas `v2.agenda.*`; model `Evento`; hooks `saved/deleted`; view `v2-agenda::*`. | `/agenda` cai no fallback `/{slug}`; home perde eventos; dashboard, sitemap e feed perdem a fonte. | `05_modulos/Publicacoes/Agenda/spec.md:28-34` |
| `MOD-PUBLICACOES-TRABALHECONOSCO` (23/2236) | Publica vagas e recebe candidaturas com currículo; com a flag desligada responde 404 e some do CMS. | Nasce desligado (`active=false` em migration); três gerações de schema em `v2_job_openings`; badge da listagem ignora `closes_at`. | Rotas `v2.trabalhe-conosco.*`; flag `trabalheconosco`; componentes CRE/Media; CSV. | Links do rodapé/editor, busca/feed, dashboard e seeders demo. | `05_modulos/Publicacoes/TrabalheConosco/spec.md:30-36` |
| `MOD-CONEXOES-ASSOCIADOS` (29/4055) | Cadastra instituições conveniadas com tags, regional, galeria e benefícios; publica `/associados`, detalhe e página por slug. | Portal filtra por `v2_associado_tags`, catálogo legado, enquanto o catálogo novo é `v2_conexao_tags`; escopo regional por `RegionalScopeService`. | Rotas `v2.associados.*`; model `AssociadoInstituicao`; `InstituicaoCmsController`; Gallery. | Portal de associados, API regional de empresas, dashboard e busca. | `05_modulos/Conexoes/Associados/spec.md:28-34` |
| `MOD-CONEXOES-PARCEIROSINSTITUCIONAIS` (20/2453) | CRUD de parceiros com tags, redes sociais, logo e endereço; duas leituras públicas paginadas. | `logo_id` é `string(36)` apontando para `v2_gallery_media.id` inteiro; tag pivô só sofre detach no destroy de tag, nunca attach no CRUD. | Rotas `v2.parceiros-institucionais.*`; `Parceiro`; `ConexaoTag`; Gallery; Search. | Home (widget de marcas), portal de parceiros, dashboard, sitemap e busca. | `05_modulos/Conexoes/ParceirosInstitucionais/spec.md:30-36` |
| `MOD-CONEXOES-UNIDADEREGIONAL` (29/6699) | Cadastra regionais, sincroniza a categoria `regional-<sigla>`, publica vitrine e emite token Bearer por unidade. | Token sem escopos (um Bearer dá acesso aos 8 endpoints), TTL fixo em 365 por fallback; grid do portal renderizado no cliente com busca por regex. | Rotas `v2.unidade-regional.*`; `UnidadeRegional`; `RegionalIdentityService`; 2 tabelas + 2 pivôs. | Portal de regionais, API das regionais, sitemap, busca e vínculo de associados. | `05_modulos/Conexoes/UnidadeRegional/spec.md:26-31`; `05_modulos/Conexoes/UnidadeRegional/api.md:25-31` |
| `MOD-INSTITUCIONAL-ASSOCIESE` (24/2656) | Publica planos e formulário, grava lead `pending`, tenta notificar o suporte e entrega CRM de leads/planos ao CMS. | `MembershipLead` declara `metadata` em `$casts`, mas a coluna não existe; selecionar plano faz o `INSERT` falhar; pivô declara `gallery_media_id` como UUID. | Rotas `v2.associe-se.*`; `MembershipLead`; `MailService`; 7 chaves em `v2_portal_configs`. | `/associe-se`, card de leads do dashboard, link semeado no header e config de apresentação. | `05_modulos/Institucional/AssocieSe/spec.md:28-34`; `05_modulos/Institucional/AssocieSe/dados.md:26-32` |
| `MOD-INSTITUCIONAL-FALECONOSCO` (12/1190) | Persiste mensagem do formulário público e permite ler/responder/arquivar no CMS; e-mails nunca alteram a resposta ao usuário. | `v2_contato_configs` é órfã (`@deprecated`, sem leitor); config real vive em `v2_portal_configs`; detalhe não usa `MailService` para o retorno. | Rotas `v2.fale-conosco.*`; `MensagemContato`; `MailService`; 2 tabelas. | Formulário de contato, inbox do CMS, dashboard e notificação por e-mail. | `05_modulos/Institucional/FaleConosco/spec.md:28-34` |
| `MOD-INSTITUCIONAL-HISTORIA` (14/1522) | Publica `/historia` com marcos ativos ordenados, imagem e AST renderizado; CMS cria/edita/reordena/arquiva. | `image_id` é `string(36)` para mídia inteira; `created_by` lógico; reordenação própria. | Rotas `v2.historia.*`; `Milestone`; CRE; Gallery; tab `LayoutBase`. | `/historia`, sitemap, seed de marcos e editor do CMS. | `05_modulos/Institucional/Historia/spec.md:27-33` |
| `MOD-INSTITUCIONAL-SOBRENOS` (49/3777) | Monta `/sobre-nos` por seções LSE, hidrata a seção `sobre-nos-team` com o biênio corrente e publica `/equipe/{slug}`. | 5 widgets próprios; `sobre-nos-testimonial` é removido só no portal (permanece no CMS); `/diretoria*` são redirects 301 legados. | Rotas `v2.sobrenos.*` e `v2.diretoria.*`; `LayoutBaseConfig` chave `sobre_nos_sections`; `Biennium`/`BoardMember`; `SobreNosDataIntegrator`. | Página Sobre Nós, páginas de membros, 5 widgets LSE e redirects legados. | `V2/Modules/Institucional/SobreNos/Controllers/SobreNosPortalController.php:75-110`; `V2/Modules/Institucional/SobreNos/Services/SobreNosDataIntegrator.php:17-51`; `05_modulos/Layouts/Homepage/spec.md` (comparação) |
| `MOD-LAYOUTS-BASICPAGE` (24/3126) | Grava `v2_basic_pages.content` e reindexa; no portal troca a view fixa por `content` cru quando não vazio. | Conteúdo runtime é HTML digitado no CMS e ecoado com `{!! !!}`; catch-all `/{slug}` vive no Core para perder para rotas específicas; 5 páginas fixas semeadas. | `BasicPagePortalController`; `BasicPage`; `BasicPageAssetManagerService`; rotas `/lgpd`, `/acessibilidade`, `/mapa-do-site`, `/ouvidoria`. | `/{slug}` (404 global), 4 páginas institucionais, SEO das páginas e sitemap. | `05_modulos/Layouts/BasicPage/spec.md:23-29`; `05_modulos/Layouts/BasicPage/runtime-e-seo.md:23-29` |
| `MOD-LAYOUTS-HOMEPAGE` (71/5851) | Monta e edita `/` como lista JSON de seções em `v2_layout_base_configs` (chave `landing_sections`), renderizada por 10 widgets `sucesu-*`. | A ordem de renderização é a ordem do array, não o campo `order`; só `sucesu-agenda` tem caminho dinâmico sempre ativo; cache `page:*` é apagado no save. | `HomepagePortalController@index`; `HomepageCmsController`; 10 widgets e 10 schemas; `HomepageDataIntegrator`. | `/` cai no fallback; menu perde Homepage; 10 widgets somem; Notícias/Agenda/Parceiros perdem vitrine. | `05_modulos/Layouts/Homepage/spec.md:24-34` |
| `MOD-INFRAESTRUTURA-CERTIFICADODIGITAL` (14/2036) | Importa certificado A1, lista validade/histórico e assina PDFs avulsos, baixando o arquivo. | UI aceita `.pkcs12` mas o servidor só aceita `pfx`/`p12`; suporte vê certificados de terceiros, mas não consegue decifrá-los. | Rotas `v2.certificadodigital.*`; `DigitalSignatureService`; `ActivityLoggerService`. | Importação/assinatura pelo CMS; o serviço DigitalSignature perde seu único consumidor HTTP. | `05_modulos/Infraestrutura/CertificadoDigital/spec.md:27-33` |
| `MOD-INFRAESTRUTURA-FEEDRSS` (4/374) | Painel de suporte que mostra itens por módulo e remove/retorna item do `/feed.xml`. | É só UI sobre `SVC-FEEDRSS`; autorização por identidade (`v2.support.email` ou `super-admin`), não por `v2_can`; pattern `cms/v2/feed-rss*`. | Rotas `v2.feedrss.support.*`; `FeedRssSupportController`; `FeedRssService`. | Apenas o painel; `/feed.xml` e a tabela continuam via serviço. | `05_modulos/Infraestrutura/FeedRss/spec.md:27-33` |
| `MOD-INFRAESTRUTURA-GESTAOPERMISSOES` (10/1582) | Cria/edita usuários e perfis; a matriz resultante controla sidebar, rotas CMS e escrita dos módulos. | Matriz é JSONB em `v2_roles.permissions_v2` lida a cada request; `super-admin` é protegido apenas como slug de V2Role, não como conceito. | Rotas `v2.gestaopermissoes.*`; `PermissionService`; `V2Role`; `v2_can`. | Administração de usuários/perfis; não há outra UI para criar papéis. | `05_modulos/Infraestrutura/GestaoPermissoes/spec.md:26-32` |
| `MOD-INFRAESTRUTURA-MAILAUDIT` (5/536) | Lista os últimos envios com destinatário, assunto, status, erro e corpo; abre detalhe. | O detalhe chama `getHistory(1)` e depois `firstWhere('id')`: só o registro mais recente abre; os demais dão 404. | Rotas `v2.mailaudit.*`; `MailAuditCmsController`; `MailService::getHistory`. | Única visualização do histórico de e-mails; `v2_mail_logs` continua sendo gravada. | `05_modulos/Infraestrutura/MailAudit/spec.md:26-32` |
| `MOD-SUPPORT-NOTICIASIMPORT` (11/836) | Executa importação de lote em dry-run/apply por sessão CMS ou chave persistente, devolvendo relatório por item. | Autenticação máquina-a-máquina com escopo/abilities/IP/TTL/consumer; `consumer` é checado no controller, não no middleware. | Rotas `/api/v2/noticiasimport/*` e `cms/importacao-noticias`; `InternalImportKey`; `NoticiasImportService`. | Coletores externos e página de suporte; `v2_internal_api_keys` fica sem consumidor. | `05_modulos/Support/NoticiasImport/spec.md:26-32` |
| `MOD-SUPPORT-STRUCTURALLANDINGEDITOR` (53/6812) | O suporte reescreve header, barras, footer, CSS, JS, tema e dados estruturais do portal sem deploy. | Cada bloco é compilado por `BladeCompiler::compileString()` e avaliado com `eval()` no request; campos decidem destino pelo prefixo (`cms_`, `mail_`). | `v2-structurallandingeditor::*`; `BlockRenderer`/`ComponentResolver`; `LayoutBaseComposer`; `sle_component()`; 3 tabelas + `v2_portal_configs`. | Header/footer/barras/CSS/JS do portal, tema do portal e CMS, logos, banner, LAI e contato. | `05_modulos/Support/StructuralLandingEditor/spec.md:28-34` |
| `MOD-SUPPORT-SUPPORTCONFIGS` (21/4041) | Um único e-mail liga/desliga módulos, ativa manutenção, expõe stack traces, trunca logs, redefine senha e restaura tema. | Guarda por action no controller, não por middleware: `active_pattern` em string com `\|` nunca casa; `reset do tema CMS` fica sem guarda (SEC-G1-04). | Rotas `v2.supportconfigs.*`; `SystemMaintenanceService`; 4 tabelas; composers de tema. | Flags, manutenção, debug, logs, senha e tema do CMS; portal perde `$portalTheme`/`$portalConfigs`. | `05_modulos/Support/SupportConfigs/spec.md:26-32`; `05_modulos/Support/SupportConfigs/rotas.md:26-32` |
| `MOD-_EXEMPLOS-EXEMPLOAPI` (4/351) | Expõe uma tela CMS somente-leitura com dois registros fictícios e uma action de escrita que valida e redireciona sem gravar. | Duas camadas de restrição por e-mail (provider + controller), mas `super-admin` também passa. | Rota `v2.exemplo-api.index`; view `v2-exemploapi::cms.index`; chave `ExemploAPI`; grupo `_Exemplos`. | Nada em runtime; perde-se o template de referência. | `05_modulos/Exemplos/ExemploAPI/spec.md:23-29` |

### 3.5 Seeds

| Unidade (arquivos/LOC) | Efeito primário | O que é único | Como se integra | Se removido, quebra | Fonte |
|---|---|---|---|---|---|
| `DATA-SEEDS-CONTENT` (1/1688) | Popula um conjunto de demonstração (regionais, notícias, eventos, associados, parceiros, vagas e vínculos regionais) quando `APP_ENV != production`. | Recusa rodar em produção; usa `firstOrCreate` por chave natural e converte Markdown em Tiptap antes de gravar. | `php artisan db:seed --class=DemoContentSeeder`; models de 8 unidades. | Ambiente de demonstração vazio; não afeta produção. | `V2/Seeds/Content/DemoContentSeeder.php:41-63` |
| `DATA-SEEDS-BASICPAGES` (9/1485) | Popula as páginas de conteúdo (agenda, associados, convênios, fale-conosco, notícias, parceiros), o payload da home, 5 marcos e imagens; as 5 linhas-base vêm da migration de `v2_basic_pages`. | Idempotência por `slug` com update/insert; `ProcessesGalleryImages` é trait compartilhada com o seeder de Sobre Nós. | `DB::table('v2_basic_pages')`; `SucesuHomepageSeeder`; `Milestone::create`; `GalleryService`. | Conteúdo inicial das páginas e da home; as linhas-base (`homepage`, `lgpd`, `acessibilidade`, `mapa-do-site`, `ouvidoria`) continuam vindo da migration. | `V2/Seeds/BasicPages/SucesuHomepageSeeder.php:45-54`; `V2/Seeds/BasicPages/ProcessesGalleryImages.php:9-24` |
| `DATA-SEEDS-SLE` (5/913) | Semeia os 8 blocos de `v2_structural_portal_contents`, assets da File Library e configurações de tema/portal. | `updateOrInsert` por `area`; `SleAssetSeeder` envia imagens para a Galeria antes de criar assets. | `StructuralPortalSeeder` chama sub-seeders; `AssetManagerService`; `GalleryService`. | Portal sem header/footer/barras default e sem assets do SLE. | `V2/Seeds/StructuralPortalSeeder.php:20-71`; `V2/Seeds/SleConfigsSeeder.php:188-218` |

### 3.6 Grupos e índices de pasta

| Unidade (arquivos/LOC) | Efeito primário | O que é único | Como se integra | Se removido, quebra | Fonte |
|---|---|---|---|---|---|
| `GRP-SUPPORT` (4/184) | README do grupo que hospeda NoticiasImport, SLE e SupportConfigs. | Só o grupo `Support` tem bloqueio de acesso por e-mail no middleware e na sidebar. | `V2/Modules/Support/`; `group` injetado pelo provider. | Nenhum código; muda o bloco do menu e o bypass de acesso. | `V2/Core/Middleware/V2PermissionMiddleware.php:50-67`; `01_arquitetura/10-grupos-e-modulos-vazios.md:34-40` |
| `GRP-LAYOUTS` (1/58) | README de `Homepage` (não é README de grupo). | O manifest o trata como grupo; o runtime não lê README. | `V2/Modules/Layouts/`; `Homepage/README.md`. | Nada em runtime. | `V2/Modules/Layouts/Homepage/README.md:3-32` |
| `GRP-INFRAESTRUTURA` (2/38) | READMEs do grupo e de MailAudit. | README diz que existe um módulo “Infraestrutura”; não existe — o controle de permissões é `GestaoPermissoes`. | `V2/Modules/Infraestrutura/`; 4 módulos reais. | Nada em runtime. | `V2/Modules/Infraestrutura/README.md:9`; `01_arquitetura/10-grupos-e-modulos-vazios.md:119-125` |
| `GRP-API` (1/9) | README de grupo sem implementação. | Promete `Exemplo`/webhooks; o diretório não existe. | Nenhuma; se um módulo for criado sob `API`, ele some da sidebar. | Nada em runtime. | `V2/Modules/API/README.md:4-9`; `V2/Core/ViewComposers/SidebarComposer.php:36-40` |
| `GRP-ATOSOFICIAIS` (1/7) | README de grupo sem implementação. | Promete diários/licitações/contratos; não há tabela nem rota. | Nenhuma. | Nada em runtime. | `V2/Modules/AtosOficiais/README.md:4-7` |
| `GRP-RELACIONAMENTOS` (1/7) | README de grupo sem implementação. | Promete ouvidoria/tickets; o contato real vive em `Institucional/FaleConosco`. | Nenhuma. | Nada em runtime. | `V2/Modules/Relacionamentos/README.md:4-7` |
| `GRP-UTILITARIOS` (1/7) | README de grupo sem implementação. | Promete QR/exportação; importação real vive em `Support/NoticiasImport` e `SVC-EXCELIMPORTER`. | Nenhuma. | Nada em runtime. | `V2/Modules/Utilitarios/README.md:4-7` |
| `GRP-CONEXOES` (1/8) | README do grupo com 3 módulos implementados. | É o grupo que concentra tenancy regional e tags compartilhadas. | `V2/Modules/Conexoes/`; `Associados`, `ParceirosInstitucionais`, `UnidadeRegional`. | Nada em runtime. | `V2/Modules/Conexoes/README.md:4-8` |
| `GRP-PUBLICACOES` (1/7) | README do grupo com 3 módulos implementados. | Concentra as três fontes do feed/busca (Notícias, Agenda, Vagas). | `V2/Modules/Publicacoes/`. | Nada em runtime. | `V2/Modules/Publicacoes/README.md:4-7` |
| `GRP-_EXEMPLOS` (1/27) | README do módulo de exemplo e sua política de restrição. | Promete restrição “independentemente do perfil”, mas `super-admin` passa. | `V2/Modules/_Exemplos/ExemploAPI`. | Nada em runtime. | `V2/Modules/_Exemplos/README.md:16-19` |
| `SVC-INDEX` (1/37) | README da pasta `V2/Services`. | Convenção de macro-componente e sufixo `Service` no slug de API. | `V2/Services/`; provider. | Nada em runtime. | `V2/Services/README.md:1-37` |
| `MOD-INDEX` (1/32) | README da pasta `V2/Modules`. | Define o “golden standard” por cópia, sem gerador. | `V2/Modules/README.md`. | Nada em runtime. | `V2/Modules/README.md:1-32` |

## 4. Particularidades

### 4.1 Quatro editores, quatro responsabilidades

| Editor | Persiste | Edita | Não faz | Evidência |
|---|---|---|---|---|
| `SVC-CONTENTRICHEDITOR` | JSON AST no campo do formulário do módulo | texto rico por nó | layout de página; não valida o schema | `03_servicos-ui/content-rich-editor/spec.md:35-41` |
| `SVC-LANDINGSECTIONSEDITOR` | nada (recebe/devolve JSON) | lista de seções por widget | não grava a lista; não conhece o módulo | `03_servicos-ui/landing-sections-editor/spec.md:21-27` |
| `MOD-SUPPORT-STRUCTURALLANDINGEDITOR` | `v2_structural_portal_contents`, `v2_layout_base_configs`, `v2_sle_assets` | código Blade/CSS/JS, tema, logos, dados estruturais | não edita seções de Homepage/Sobre Nós | `05_modulos/Support/StructuralLandingEditor/spec.md:28-34` |
| `MOD-LAYOUTS-BASICPAGE` | `v2_basic_pages.content` | HTML cru de uma página | não compõe seções nem widgets | `05_modulos/Layouts/BasicPage/spec.md:23-29` |

`Homepage` e `Sobre Nós` não são um quinto editor: são **consumidores** do LSE que
persistem a lista em `v2_layout_base_configs` (`landing_sections` e
`sobre_nos_sections`) e renderizam por widgets registrados no `ModuleProvider`
(`V2/Modules/Layouts/Homepage/ModuleProvider.php:24-34`;
`V2/Modules/Institucional/SobreNos/ModuleProvider.php:20-26`).

### 4.2 Contradições medidas

| Contradição | Números | Consequência | Evidência |
|---|---|---|---|
| Widgets do LSE | **22** forms e 22 renders; **21** tipos em `$legacyConfigs`; **36** registros quando Homepage (10) e Sobre Nós (5) carregam. `video` tem form/render e não está em nenhuma lista. | O tipo `video` existe no disco, mas não aparece no dropdown e não pode ser criado; `video-playlist` é o tipo suportado. | `V2/Services/LandingSectionsEditor/Services/LandingSectionsEditorRendererService.php:35-70`; `V2/Services/LandingSectionsEditor/Views/forms/` (22 arquivos) |
| Dualismo de tags | `v2_associado_tags` + `v2_associado_tag_pivot` (legado, usado pelo portal de Associados) × `v2_conexao_tags` + 3 pivôs (novo, usado por Parceiros/Unidade Regional). A migration copia o catálogo, mas **não migra o pivô** de Associados. | Uma tag criada em `v2_conexao_tags` não aparece no filtro de Associados; as duas listas divergem após a migration. | `V2/Core/Migrations/2026_08_18_000002_migrate_associado_tags_to_conexao_tags.php:18-46`; `V2/Modules/Conexoes/Associados/Models/AssociadoInstituicao.php:59-69` |
| TTL da API regional | Código lê `config('v2.unidade_regional.api_token_ttl_days', 365)`, mas `config/v2.php` **não tem** o bloco `unidade_regional`; tem `associados.api_token_ttl_days`. | O TTL é sempre 365 por fallback; mudar `V2_ASSOCIADOS_API_TOKEN_TTL` não afeta a API regional. | `V2/Modules/Conexoes/UnidadeRegional/Models/UnidadeRegional.php:283-285`; `config/v2.php:17-19` |
| Contagem de widgets na Homepage | README fala 9 widgets; o provider registra **10**; o manifest tem 10 classes de widget e 10 schemas. | Documento e código divergem em um widget (`sucesu-noticias` além dos 9 do README). | `V2/Modules/Layouts/Homepage/ModuleProvider.php:24-34`; `V2/Modules/Layouts/Homepage/README.md:3-32` |
| Ordem do menu | `position` existe em 19 providers, mas `SidebarComposer` ordena por `title` (`strcasecmp`) e grupos por nome; `position` não é lido em nenhum ponto. | Posições 0/1/4/5/6/7/8/90/91/98/100 são decorativas; a ordem real é alfabética. | `V2/Core/ViewComposers/SidebarComposer.php:85-93`; `02_servicos-base/dashboard.md:25` |
| Rotas × índice | 268 endpoints no código × 268 no CSV (262 endpoint + 4 redirect + 2 “rota”); 40 wrappers × 33 grupos. | Faltam 8 grupos; 1 grupo do CSV é espúrio. Detalhe em `reconciliacao-indices.md`. | `_indices/rotas.csv`; `V2/**/Routes/*.php` |
| Tabelas × índice | 57 `Schema::create` atuais × 60 linhas (57 atuais + 3 históricas). | `v2_chapters`, `v2_news_approvers` e `v2_news_configs` são linhas históricas explicitamente marcadas como removidas/arquivadas; não devem contar como tabela atual. | `_indices/tabelas.csv`; `V2/Modules/Publicacoes/Noticias/Migrations/2026_07_26_000002_remove_approval_workflow.php:27-32` |
| Blades × índice | 386 blades × 386 linhas. | Cobertura 1:1; o `.bak` saiu do índice e o blade do ExemploAPI entrou. | `_indices/componentes.csv`; `V2/layouts/cms/layouts/sidebar.blade.php.bak.20260724` |
| Mídia / região | 7 colunas usam `uuid`/`string(36)`/`bigint` para `v2_gallery_media.id` inteiro; 3 usam inteiro. | IDs de mídia não são portáveis entre tabelas e exigem cast string→int. | `_indices/tabelas.csv`; `V2/Modules/Institucional/AssocieSe/Migrations/2025_07_20_000002_create_v2_membership_plan_gallery_table.php:26` |

### 4.3 Sobreposições que não são duplicatas

- `CORE-CMS` × `CORE-AUTH`: o primeiro entrega a tela e a classe-base; o segundo
  decide quem entra. `GET /cms` é fail-open de RBAC, mas não de autenticação
  (`V2/Core/Middleware/V2PermissionMiddleware.php:74-77`).
- `SVC-SEARCH` × `SVC-SEO`: o primeiro projeta texto e resolve URL; o segundo
  consome o ranking de busca para enriquecer o dashboard, sem escrever no índice
  (`03_servicos-ui/seo/spec.md:21-27`).
- `SVC-MEDIA` × `SVC-GALLERY`: o primeiro otimiza, o segundo cataloga. Nenhum
  dos dois substitui o outro; o upload de um módulo chama Media e depois Gallery.
- `MOD-LAYOUTS-BASICPAGE` × `MOD-LAYOUTS-HOMEPAGE`: ambos respondem em `/` em
  momentos diferentes; a Homepage tem prioridade por ser registrada antes do
  fallback, e o BasicPage só resolve `/{slug}` de um segmento.

### 4.4 Anti-uso

- **Não** reimplemente os editores como um único componente: o conteúdo de cada
  um tem schema e ciclo de persistência diferentes (§4.1). Um editor genérico
  perde `eval()` do SLE, o AST do CRE e a lista ordenada do LSE.
- **Não** trate `v2_conexao_tags` como substituta imediata de
  `v2_associado_tags`: o portal de Associados ainda consulta a tabela legada
  (`V2/Modules/Conexoes/Associados/Controllers/AssociadosPortalController.php:55-78`).
- **Não** confie em `active_pattern` para negar acesso: `SupportConfigs` e as
  rotas de serviço são fail-open; a barreira real é controller/action (§2 de
  `permissoes-e-papeis.md`).
- **Não** use `position` para ordenar menu nem para prever a ordem de páginas:
  o composer ordena por título.

## 5. Integrabilidade

### 5.1 Ordem de leitura recomendada

1. `ARCH-OVERVIEW` → `CORE-BOOT` → `CORE-RUNTIME` (como o request nasce).
2. `CORE-AUTH` → `permissoes-e-papeis.md` (quem pode o quê).
3. `CORE-DATA` → `entidades-e-propriedade.md` (onde os dados vivem).
4. `SVC-STORAGE` → `SVC-MEDIA` → `SVC-GALLERY` → `SVC-SEARCH` → `SVC-SEO` →
   `SVC-FEEDRSS` → `SVC-MAILSERVICE` → `SVC-ACTIVITYLOGGER` →
   `SVC-DASHBOARD` (a pilha compartilhada).
5. `SVC-CONTENTRICHEDITOR` → `SVC-LANDINGSECTIONSEDITOR` → `SVC-EXCELIMPORTER`
   (os editores/importadores).
6. `UI-CMS` → `UI-PORTAL` (chrome).
7. Plataforma: `MOD-SUPPORT-SUPPORTCONFIGS` → `MOD-SUPPORT-STRUCTURALLANDINGEDITOR`
   → `MOD-SUPPORT-NOTICIASIMPORT`.
8. Domínio: Notícias → Agenda → Trabalhe Conosco → Associados → Parceiros →
   Unidade Regional → História → Fale Conosco → Associe-se.
9. Composições: `MOD-LAYOUTS-BASICPAGE` → `MOD-LAYOUTS-HOMEPAGE` →
   `MOD-INSTITUCIONAL-SOBRENOS`.
10. Seeds, grupos e índices.

### 5.2 Receita de uso (documento)

```bash
# 1. Confira a unidade no manifest
python3 -c "import json;m=json.load(open('00_inventario/manifest.json'));print(m['units']['MOD-PUBLICACOES-NOTICIAS']['count'])"
# 2. Leia a linha desta matriz e o doc dono
rg -n "MOD-PUBLICACOES-NOTICIAS" 08_matriz/singularidades.md
# 3. Confirme os números no índice canônico
rg -n "^MOD-PUBLICACOES-NOTICIAS," _indices/rotas.csv | wc -l
```

### 5.3 Receita de uso (reimplementação)

```text
Para cada unidade:
  1. copie a ficha (Efeito/Integra/Quebra) para o backlog;
  2. implemente a superfície pública antes das telas;
  3. valide os invariantes de §4.2 no schema e no middleware;
  4. só então implemente o editor/consumidor que depende dela.
```

## 6. Lacunas

- `LG-MATRIZ-01` — `MOD-INSTITUCIONAL-SOBRENOS` teve os documentos publicados
  durante a Onda 5 (`spec`, `dados`, `cms`, `portal`, `widgets-e-integracoes`); a
  linha desta matriz foi derivada do código e deve ser relida contra esses docs
  na revisão final.
- `LG-MATRIZ-02` — `DATA-SEEDS-CONTENT` tem 1 linha em `dados-iniciais.csv` com
  as tabelas afetadas, mas sem contagem por tabela; o seeder é condicionado a
  `APP_ENV != production` e não tem teste de idempotência.
- `LG-MATRIZ-03` — `DATA-SEEDS-SLE` agora tem doc em `07_dados-iniciais/sle-e-estrutura.md`
  e 5 linhas em `dados-iniciais.csv`; a ordem de execução dos sub-seeders ainda
  depende do `StructuralPortalSeeder`.
- `LG-MATRIZ-04` — `SVC-DASHBOARD`, `SVC-STORAGE` e `SVC-ACTIVITYLOGGER` não têm
  rotas próprias; a superfície é medida por chamadas, não por endpoints.
- `LG-MATRIZ-05` — a contagem de 36 widgets só é verdadeira quando os dois
  `ModuleProvider` de Homepage e Sobre Nós executam; em CLI/teste sem boot
  completo o registry contém apenas os 21 do LSE.

## 7. Evidências

- Manifest e totais: `00_inventario/manifest.json`.
- Índices canônicos: `_indices/rotas.csv`, `_indices/tabelas.csv`,
  `_indices/componentes.csv`, `_indices/permissoes.csv`, `_indices/config.csv`,
  `_indices/servicos.csv`.
- Fichas de unidade: `01_arquitetura/*.md`, `02_servicos-base/*.md`,
  `03_servicos-ui/**/*.md`, `04_ui/*.md`, `05_modulos/**/*.md`,
  `07_dados-iniciais/*.md`.
- Código pivô: `V2/Core/Providers/V2ServiceProvider.php`,
  `V2/Core/ViewComposers/SidebarComposer.php`,
  `V2/Core/Middleware/ModuleAccessMiddleware.php`,
  `V2/Core/Middleware/V2PermissionMiddleware.php`,
  `V2/Modules/Support/StructuralLandingEditor/Services/BlockRenderer.php`.
- Estado verificado em 2026-10-21: `git -C sucesu-cms status --porcelain V2`
  vazio; 930 arquivos, 56 unidades; 44 arquivos de rota, 308 chamadas `Route::*`.
