# F4.I1.T1 — Shell CMS configurável: identidade + regiões + posição da sidebar (ADR-036)

| Campo | Valor |
|---|---|
| **Fase** | F4 — Produto & CMS |
| **Issue** | F4.I1 — CMS próprio e editor (plano 12) |
| **kd task** | `task_01yl2kbt` (`closed`) |
| **Âncora** | `wiki/implementation/04-produto-cms.md` |
| **Status da revisão** | 🔧 com correções |

## O que foi implementado

- Engine `CmsShellResolver`/`CmsShell`/`CmsSidebarPosition`, `config/cms.php`.
- Identidade same-origin (`/cms-theme.css` em `oklch()`); regiões opcionais com ordem de DOM por posição; órbita em Popover nativo.
- Catálogo de partials Blade + daisyUI; i18n do shell (4 locales).

## Arquivos para revisar

- `src/layout/Cms/Shell/CmsShell.php`
- `src/layout/Cms/Shell/CmsShellResolver.php`
- `src/layout/Cms/Shell/CmsSidebarPosition.php`
- `config/cms.php`
- `src/layout/Cms/Http/CmsThemeStylesheetController.php`
- `src/layout/Cms/CmsServiceProvider.php`
- `src/layout/Cms/components/*.blade.php`
- `src/layout/Cms/partials/{header,footer,sidebar,orbital}.blade.php`
- `src/layout/Cms/dashboard.blade.php`
- `src/layout/Cms/README.md`
- `tests/Feature/CmsShellTest.php`
- `tests/Feature/CmsPartialsTest.php`

## Pontos de revisão

### PHP 8.4
- [ ] `declare(strict_types=1)`; tipos nativos (union/enum/`readonly`); sem `mixed` desnecessário.
- [ ] Dependências **injetadas** (nenhum `new`/`app()`/`resolve()` no corpo); sem traits/abstract/generics.
- [ ] `match` em vez de cadeias de `if`; `?->`/`??`; sem código morto; PHPStan `max` limpo.

### Laravel 12
- [ ] Nativo primeiro (Eloquent casts/scopes, `FormRequest`, `Gate`, scheduler, events) — sem reimplementar.
- [ ] Sem closure em rota; resources/rotas nomeadas; `config()` só lê, `env()` só em `config/`.
- [ ] Migração **idempotente**; `down()` → `backup_*` (nunca `DROP`); sem `orderBy` cru quando `latest/oldest` serve.

### HTML semântico + a11y (eMAG/WCAG 2.2 AA)
- [ ] Um `<main>`, headings em nível correto, landmarks; só ARIA quando necessário.
- [ ] Alvos ≥ 24 px (≥ 44 px em ponteiro grosso); foco visível; rótulos em todos os campos; contraste (axe).
- [ ] Funciona **sem JS**; `sniffCSS` sem `fail`/`warn` fora do ledger.

### CSS moderno
- [ ] `oklch`, `clamp`, `rem`/`fr`/`dvh`/`%`; `@layer` (a11y por último); `@property`; subgrid com fallback.
- [ ] Sem `!important`, sem `style="…"` inline, sem hex/rgb (exceto justificado); sem CDN.

### Decisões do projeto (ADRs)
- [ ] Respeita a ADR do escopo (ver cabeçalho) e não escapa das demais (001, 002, 004, 013, 015…).
- [ ] Determinismo: relógio/id injetados, ordem explícita, dados idempotentes (ADR-001).

### i18n (ADR-012)
- [ ] Nenhuma string visível fixa; 4 locales com paridade de chaves; `route()`/`localized_url()` (nunca path literal).

### Observabilidade/segurança/testes
- [ ] Span + `log_event('{module}.{action}')` com atributos `scalar|null`, **sem PII** (ADR-024).
- [ ] Teste que falha sem a mudança (vermelho→verde) + evidência no `kd`; `make quality` 2×.

### Específicos desta task

- [ ] Shell é função pura do dado (`config/cms.php`); valor inválido ignorado.
- [ ] `orbital` não é o **único** caminho de navegação; DOM segue a posição (foco = visual).

## Comandos úteis

```bash
make quality            # lint + PHPStan max + gates + testes
make e2e                # Playwright + axe (se a task toca UI)
make check-boundaries   # fronteiras core/services/layout/modules
```

---

> Revisar contra `AGENTS.md`, `wiki/adr/` e o plano citado. Registrar achados no `kd` (`kd write --anchor`) e, se houver correção, teste de regressão.

## Notas da revisão

| Data | Revisor | Resultado | Observações |
|---|---|---|---|
| 2026-10-18 | agente | 🔧 | **A** (alto) o modo `orbital` lia `config('cms.nav')` — uma **semente morta** — em vez do **manifesto**: trocar a posição para `orbital` **perdia toda a navegação de módulo**, violando ADR-036 (“a **mesma** navegação, apresentada como menu acionável”) → corrigido com uma **única** fonte (`cms::partials.nav-items` alimentado pelo `PanelMenu`, usado pela coluna **e** pela órbita) e remoção da semente; **2 testes vermelho→verde** (mesmos `href`s nas duas posições; a semente não é fonte) — `fact_003qt7dl`; **B** (médio) o `src/layout/Cms/README.md` — **contrato de leitura** — mandava `@extends('cms::layouts.app')` + `@section('content')`: views **inexistentes** e padrão **proibido** por ADR-009/ADR-016 (o módulo usa `<x-layout::cms>` e preenche só o `<main>`); também citava `cms::staticPages.*` e o comentário do `CmsServiceProvider` estava stale → reescrito — `fact_01by3590`; **C** (baixo) `src/layout/Assets/icons/README.md` apontava `src/layout/Components/icon.blade.php` (real: `.../ui/icon.blade.php`) → corrigido (`fact_00ashft9`); **D** (gate) `tests/Feature/DocsReferencesTest.php` resolve **toda** referência de view/componente/arquivo em `src/**/*.md` contra o framework (vermelho com os defeitos reais → verde) — `fact_01cjx6bv`; **E** (obs) o modo `orbital` não tem cobertura e2e/axe (o `07` só exercita `left`) → `task_01ubnz8t`; **F** (obs) `.cms-orbit__item:nth-child(N)` mapeia `--i` só para os 6 primeiros itens (`risk_003a5995`). Verificados e OK: `CmsShellResolver` (camada de instância, valor inválido ignorado, `oklch()` só, largura em escala fechada), `CmsThemeStylesheetController` (`ETag`/304, `@layer overrides`, `Cache-Control`), ausência de `style=`/`<style>`, ordem de DOM por posição, `sr-only` + `aria-label` na órbita, 4 locales do shell. |

> Resultado: `✅ revisado` · `🔧 com correções` · `⏭️ delegado` (com justificativa).

| Data | Revisor | Resultado | Observações |
|---|---|---|---|
| 2026-10-19 | agente | 🔧 | **Revisão de UX (pré-F5.I3).** **A** (**alto**, D6/D7/UX) no desktop o **login do painel** renderizava o cartão **dentro da coluna da sidebar desligada**: o shell publicava `data-cms-sidebar="left"` mesmo com a região `sidebar` desabilitada (login, ADR-037 §8), então `[data-cms-sidebar='left'] .cms-frame { grid-template-columns: 18rem 1fr }` era aplicado e, sem `<aside>`, o `.cms-frame__content` caía na **1ª** coluna → medido 1366×768: `.cms-frame` 288×1078, `.cms-auth__card` **160px** à esquerda (esperado ~24rem, centrado); mobile (<64rem) ficava correto. Fix: `data-cms-sidebar="none"` quando `! $shell->hasSidebar()` + **2 regressões** (estrutural `CmsShellTest::the_regions_are_optional` e e2e novo em `07-cms-shell` provando `width>300` e centro da viewport) — `error_01yjw6ha`. **B** (**alto**, D14/ADR-033) a identidade fundadora `suporte@maxima.inf.br` **não tem usuário nem provisionamento** (o perfil `suporte` vem de migração, mas nenhum seeder/comando cria o usuário; `cms_users` só tem `admin@concordia.inf.br`) → o grupo `Suporte` é inalcançável — `risk_00sjrphk`. **C** (obs) o breadcrumb do painel **repete o título** sem hierarquia (`Painel`/`Painel`, `Notícias`/`Notícias`) — `risk_011cjiyl`. Positivos: dashboard/listas/formulários/LGPD consistentes e limpos, erro de login anunciado (`role=alert`), mobile ok. |
