# P0.S3 — módulo `Infraestrutura/Configuracoes`: seção Geral com CRUD

| Campo | Valor |
|---|---|
| **Fase** | P0 — Fundação do painel: configurações tipadas e primitivas |
| **Issue** | P0.S3 — módulo Configurações, seção Geral, rotas, FormRequest |
| **`kd` task** | `task_01hxifdv` (épico `epic_00j5mhqf`) |
| **Âncora** | `wiki/implementation-phases/P0-fundacao-painel.md` · `wiki/adr/ADR-046-configuracoes-tipadas-por-escopo.md` |
| **Status da revisão** | ✅ revisado |

## O que foi implementado

- Módulo `Infraestrutura/Configuracoes` (token `configuracoes`, grupo `Infraestrutura`), com
  `permissions = [ver, editar]`; o grupo ganhou o rótulo `layout::shell.group_infraestrutura` nos
  quatro locales.
- Rotas CMS sem closure: `GET /configuracoes` (índice), `GET /configuracoes/{section}` (formulário)
  e `PUT /configuracoes/{section}` (salvar). A rota só aceita a seção **implementada** (`institution`);
  `theme`/`seo`/etc. respondem 404 nesta fatia (nada de JSON livre — ADR-046).
- `ConfiguracoesIndexController`, `ConfiguracoesEditController` e `ConfiguracoesUpdateController`:
  `Permission::authorize('Configuracoes', VIEW/EDIT)` antes de ler/escrever; `Settings::section()`
  resolve banco → fallback → default; `Settings::put()` recebe o documento validado e o ator.
- `UpdateSettingsRequest`: regras derivadas do **schema**, normalização de vazios (limpar = omitir),
  labels/atributos i18n e erro de schema convertido em 422 pelo controller.
- Formulário gerado do schema: label/help i18n, `required`, `maxlength`, `aria-invalid`,
  `aria-describedby`, resumo `role="alert"` e foco no primeiro campo inválido. Sem JS obrigatório.
- Textarea para `text`, select para `enum`, checkbox para `bool` e input para os demais tipos; o
  formulário de Geral cobre nome, razão social, CNPJ, endereço, telefone, e-mail, horário e site.
- `src/core/Lang/{locale}/settings.php`: rótulos do schema no Core (dono dos campos), quatro locales.
- `x-cms::form-group` ganhou `maxlength`/`autofocus` opcionais (sem mudar chamadas existentes).
- E2E `17-cms-configuracoes.spec.ts` (projeto CMS desktop): edição, erro de schema, foco no
  primeiro erro, axe sem violações e 404 de seção; o teste restaura o valor original pela UI.

## Arquivos para revisar

- `src/modules/Infraestrutura/Configuracoes/ModuleProvider.php`
- `src/modules/Infraestrutura/Configuracoes/Routes/cms.php`
- `src/modules/Infraestrutura/Configuracoes/Logic/ConfiguracoesSections.php`
- `src/modules/Infraestrutura/Configuracoes/Logic/Controllers/Cms/*.php`
- `src/modules/Infraestrutura/Configuracoes/Logic/Requests/UpdateConfiguracoesRequest.php`
- `src/modules/Infraestrutura/Configuracoes/Layout/Views/cms/index.blade.php`
- `src/modules/Infraestrutura/Configuracoes/Layout/Views/cms/form.blade.php`
- `src/modules/Infraestrutura/Configuracoes/Lang/{pt_BR,en,es,fr}/{menu,cms,validation}.php`
- `src/modules/Infraestrutura/Configuracoes/Test/ConfiguracoesCmsTest.php`
- `src/core/Lang/{pt_BR,en,es,fr}/settings.php`
- `src/layout/Lang/{pt_BR,en,es,fr}/shell.php`
- `src/layout/Cms/components/form-group.blade.php`
- `src/tests-e2e/tests/17-cms-configuracoes.spec.ts`
- `src/tests-e2e/playwright.config.ts`

## Pontos de revisão

### PHP 8.4 / Laravel 12
- [ ] `declare(strict_types=1)`, controllers `final`, DI no construtor/assinatura.
- [ ] Rotas sem closure; `route()` nos links; sem `env()` fora de `config/`.
- [ ] FormRequest só valida forma; autorização no controller (`Permission::authorize`).
- [ ] `SettingsValueInvalid` convertido em 422, nunca 500.

### Dados / Schema
- [ ] Formulário lê `SettingsSchema::fields()`; nenhuma chave fora do schema é aceita/gravada.
- [ ] Seção não implementada responde 404; não existe endpoint de chave avulsa.
- [ ] Gravação preserva `schema_version`/`updated_by` e invalida o cache pelo `Settings::put`.
- [ ] Campo opcional vazio é omitido (limpa), campo obrigatório vazio é 422.

### Autorização / segurança
- [ ] Sem `configuracoes.ver` → 403 na leitura; sem `configuracoes.editar` → 403 na escrita.
- [ ] CSRF no formulário; `PUT` com `@method`; nenhuma mutação por GET.
- [ ] Nenhum segredo nesta seção; nenhum valor em log/auditoria além do contrato do Core.

### i18n / a11y
- [ ] Quatro locales para menu/cms/validation e rótulos do schema; sem texto fixo nas views.
- [ ] Um shell por view; sem `<h1>` próprio; labels/for, `aria-invalid`, resumo e foco no erro.
- [ ] Funciona sem JS; alvos e contraste ficam no gate de axe/sniff (S4/S5).

### Testes
- [ ] CRUD ponta a ponta, 403 (ver/editar), 422 (nome/URL), 404 de seção, menu do painel.
- [ ] `make check` 2×; `make check E2E=1` (o spec 17 cobre a tela e o axe).

## Comandos úteis

```bash
make check
make exec cmd='vendor/bin/phpunit src/modules/Infraestrutura/Configuracoes/Test'
make exec cmd='vendor/bin/phpstan analyse --no-progress --memory-limit=1G'
make exec cmd='php artisan core:cache-modules'
make exec cmd='php artisan route:list --name=configuracoes'
```

## Notas da revisão

| Data | Revisor | Resultado | Observações |
|---|---|---|---|
| 2026-10-24 | agente revisor P0-S3 | ✅ | Achado 1 corrigido: `Permission::authorize(EDIT)` no `authorize()` do FormRequest, antes da validação; viewer+payload inválido → 403. Achado 2 corrigido: formulário aceita VIEW ou EDIT e o redirect pós-PUT devolve 200. Achado 3 corrigido: `MODULE.md` criado. Observações menores (teste do vazio opcional, id fixo) ficam como baixo. |
