# Spec 09 — Grep-friendly: token canônico por feature

> **Dono:** Core/Qualidade · **Status:** Proposta · **Plano:** 02
> **Relaciona:** ADR-004, ADR-012, ADR-013, ADR-017
> **Objetivo:** garantir que **uma única busca** (`grep -riE "<token>"`) retorne a árvore
> completa de uma feature — do banco à interface, em todas as camadas — reduzindo contexto e
> alucinação para humanos e agentes de IA.

---

## 1. Regra única

Toda feature/módulo tem **um token canônico** — identidade **PascalCase**, sem acentos, no singular
(ex.: `DiarioOficial`, `Noticia`, `Ouvidoria`) — e **todos** os artefatos derivam dele em cada estilo
de caso. A forma de **busca** remove separadores (`diariooficial`); a forma externa é **kebab**
(`diario-oficial`) e a de PHP/i18n/banco é **snake** (`diario_oficial`). Nada de nomes "criativos"
por artefato.

- **Abrangência:** `modules`, `services`, `layout` e `core`.
- **Um token por feature.** Se duas features compartilham token, o token está errado.
- **Exceções:** integração com legado (ex.: `User`) **documentada no código** e no módulo.

## 2. Tabela de derivação por artefato

| Artefato | Estilo | Exemplo |
|---|---|---|
| Identidade (pasta/namespace/classe) | Pascal | `DiarioOficial` |
| Token de busca (`grep`/`name-check`) | minúsculo, sem separador | `diariooficial` |
| Log/span/evento `module` | kebab | `diario-oficial` |
| Pasta / namespace | Pascal | `src/modules/DiarioOficial/` |
| Classes (Model/Controller/Action/DTO/Request/Resource/Policy) | Pascal | `DiarioOficialPublicarAction` |
| Eventos / Listeners | Pascal | `DiarioOficialPublicado` |
| Funções / variáveis | camel | `diarioOficialStore()`, `diarioOficialClean()` |
| Views / componentes Blade | kebab | `diario-oficial-edit.blade.php` |
| Rotas | dot + kebab/snake | `portal.diario-oficial.show` |
| Migrations / tabelas / colunas | snake | `diario_oficial_logs`, `diario_oficial_id` |
| Testes PHPUnit | Pascal + `Test` | `DiarioOficialPublicarActionTest` |
| Testes E2E (Playwright) | kebab + `.spec.ts` | `diario-oficial-publicacao.spec.ts` |
| Slots de layout | dot + kebab | `diario-oficial.after-main` |
| Permissões / policies | snake + dot | `diario_oficial.publicar` |
| Chaves i18n | dot + snake | `diario_oficial.titulo` |
| Classes CSS / `data-*` | kebab | `diario-oficial-card`, `data-diario-oficial` |
| Assets (JS/CSS) | kebab | `diario-oficial.js` |

## 3. Lado público (Portal)

O portal usa o mesmo token com o **sufixo `Portal`** no que é específico da face pública:

| Artefato | Exemplo |
|---|---|
| Controller | `DiarioOficialPortalController` |
| View | `diario-oficial-portal-show.blade.php` |
| Rota | `portal.diario-oficial.show` |
| Slot público | `diario-oficial.portal-sidebar` |

## 4. Exemplos

```bash
# ✅ Token canônico — uma busca acha tudo
grep -riE "diario[-_]?oficial" src/

# ❌ Nomes dispersos — impossível rastrear
# NoticiaController, noticias_index.blade.php, tb_news, LastNews
```

```text
src/modules/DiarioOficial/
├── ModuleProvider.php
├── Database/{Models/DiarioOficial.php, Migrations/..._create_diario_oficial_table.php}
├── Logic/{Actions/DiarioOficialPublicarAction.php, Controllers/DiarioOficialPortalController.php}
├── Routes/{web.php, cms.php}
├── Views/{diario-oficial-index.blade.php, diario-oficial-portal-show.blade.php}
└── Tests/DiarioOficialPublicarActionTest.php
```

## 5. Gates (verificáveis)

- `make exec cmd='bash tools/name-check.sh --grep <token>' term=<token>` — retorna ≥1 arquivo por camada esperada (`Logic`, `Database`,
  `Views`, `Tests`).
- `tools/name-check` — falha se um arquivo dentro de `src/modules/{Grupo}/{Modulo}` não carregar
  o token do módulo (criado em F1.I4).
- `tests/Feature/Adr004GrepFriendlyTest` — roda no `make check`; garante token **único** e nome dos
  artefatos (tabela da ADR; exceção via `@name-check-exception`) nas **features de domínio**
  (módulos e services) e **localidade por namespace** + **nomes de rota** nos concerns de
  **`core`/`layout`** (busca única; a entidade pode não derivar do nome do diretório).
- `make exec cmd='php tools/arch-check'` + esta spec sustentam a **localidade léxica** de cada feature.

## 6. Checklist de revisão

- [ ] A identidade é PascalCase, sem acento, no singular; as formas derivadas usam kebab (externo)
      e snake (PHP/i18n/banco), sempre a partir do mesmo token.
- [ ] Todos os artefatos derivam do token conforme a tabela.
- [ ] A face pública usa o sufixo `Portal`.
- [ ] `make exec cmd='bash tools/name-check.sh --grep <token>' term=<token>` acha a feature em todas as camadas.

## 7. Referências

- ADR-004 · ADR-012 · ADR-013 · ADR-017
- `wiki/plan/02-governanca-ia-first.md` · `wiki/specs/08-ia-e-qualidade.md`
- `prefeituras_v5/.agents/rules/domain_isolation.md` (origem do princípio)
