# Como Decidir o que é um Módulo

Este é o passo mais crítico do protocolo. Tudo que vem depois (dossiês,
migração, backlog) herda a qualidade desta decisão. Se a lista de módulos
estiver errada, o erro se propaga e a v7 nasce com a estrutura errada.

---

## 1. Definição operacional

> **Módulo** = uma **capacidade de negócio** do sistema, com uma fronteira
> reconhecível, que pode ser reconstruída, testada e implantada de forma
> independente — e que um usuário do sistema consegue **nomear**.

Três filtros, aplicados em ordem:

| # | Filtro | Teste | Se falhar |
|---|---|---|---|
| 1 | **Nomeabilidade** | Um usuário chamaria isso de "módulo"? | Não é módulo; é infraestrutura, integração ou detalhe |
| 2 | **Fronteira** | Tem conjunto próprio de rotas, dados ou tela? | Não é módulo; é parte de outro |
| 3 | **Autonomia** | Pode ser reconstruído e testado isoladamente? | É um recorte artificial; consolidar |

**Contraprova:** se o candidato não é nomeável por quem usa ("a parte do
Diário que gera o PDF"?), ele é um **estágio interno** de um módulo — e
descreve-se dentro dele, não como módulo.

---

## 2. Três modelos de registro de módulos

O modelo varia por projeto. O `inventario.py` detecta os três
automaticamente; a F2 decide como aplicar o critério em cada caso.

### 2.1 Baseado em registro (registry) — *Portal Municipal, TecVoto*

O projeto tem uma **tabela de módulos** (`modulos`) populada por seed, e
tudo se refere a ela (`resources.modulo_id`, `menu_orders.modulo_id`).

- **Fonte da verdade:** a tabela/seed.
- **Vantagem:** a lista já é a vocabulary do sistema; o menu do CMS, as
  permissões e o breadcrumb já a respeitam.
- **Cuidado 1:** a tabela pode estar **desatualizada**. Comparar com o
  inventário de código: módulos no registro sem código (morta) e código sem
  registro (órfã).
- **Cuidado 2:** o slug pode ter **typo** e a tabela pode ter **duplicata
  semântica** (dois slugs para a mesma capacidade). No Portal Municipal havia
  `diario-ofifical` e `detaques` — typos do legado, tratados por um mapa de
  alias para um dossiê único.
- **Cuidado 3:** **status = false** esconde o módulo do menu. Módulo
  "desativado" ainda é módulo (documentar e sinalizar), não ausência.

> **Detalhe do caso real:** o pedido afirmava que o módulo `a-cidade` havia
> sido renomeado. O inventário mostrou que o seed renomeia a **categoria 6**
> (`a-prefeitura` → `a-instituicao`); o slug `a-cidade` continua idêntico
> nas duas versões. É exatamente o tipo de premissa que a F2 existe para
> checar.

### 2.2 Baseado em pastas (folders) — *CMS, Sucesu-CMS*

O projeto é um Laravel moderno com módulos como **diretórios físicos**
(`cms/modules/`, `sucesu-cms/V2/Modules/`), tipicamente via
`nwidart/laravel-modules`.

- **Fonte da verdade:** o sistema de arquivos.
- **Vantagem:** a fronteira é explícita; o autoload do PSR-4 já segmenta.
- **Cuidado 1:** o diretório pode estar **vazio** ou ser apenas andaime
  (`Demo`, `_Exemplos`, `Support`).
- **Cuidado 2:** subpastas de infraestrutura (`Infraestrutura`, `Support`,
  `Utilitarios`, `Layouts`) **não são módulos de negócio** — são
  cross-cutting (taxonomia `infraestrutura`).
- **Cuidado 3:** a mesma capacidade pode estar **partida** em dois diretórios
  (ex.: `AtosOficiais` e `Publicacoes` podem ser o mesmo domínio visto de
  ângulos diferentes). Isso é uma decisão de negócio, não de código: registrar
  a dúvida e tratar como módulos ligados, não fundir por conta própria.

### 2.3 Implícito (por convenção) — *qualquer Laravel sem registro explícito*

Não há tabela nem pastas. Os módulos são derivados de rotas + controllers.

- **Fonte da verdade:** a combinação `routes/*.php` + `app/Http/Controllers/**`.
- **Critério de agrupamento:** controllers que compartilham **prefixo de
  rota** e **domínio de dados** formam um módulo.
- **Cuidado:** um controller "cruzado" (`DashboardController`, `SettingController`)
  costuma ser infraestrutura, não módulo.

### 2.4 Híbrido

Alguns projetos misturam: registro **e** pastas. Tratar a interseção como
canônica e reportar a diferença dos dois lados na F2.

---

## 3. Taxonomia de classificação

Cada módulo receives uma classificação. Ela define **o que o dossiê precisa
cobrir** e como ele entra no plano de migração.

| Classe | Definição | O dossiê deve cobrir | Migração |
|---|---|---|---|
| `registrado` | Tem entrada no registro oficial e código | Completo (9 arquivos) | Módulo de primeira classe |
| `exclusivo-<versão>` | Existe só numa das versões | Completo, com mapa de versões | Decisão: resgatar ou descartar formalmente |
| `portal-only` | Só superfície pública, sem backoffice | Foco em rota, view, JS, dados | Podem virar Livewire/Blade parcial |
| `sem-cms` | Regra de negócio exposta por API/serviço, sem backoffice | Foco em regra, contrato e segurança | Service/Job próprio |
| `infraestrutura` | Transversal: log, config, menu, permissões, migração de conteúdo | Foco em contrato, não em CRUD | Candidato a framework interno da v7 |
| `morto` | No registro, sem código, ou código inacessível | Foco em evidência de morte | Remover do plano |

---

## 4. Teste de consistência da lista

A lista canônica passa por estas cinco verificações. Falha em qualquer uma
indica que a F2 não terminou.

| # | Verificação | Como |
|---|---|---|
| **C1** | **Cobertura de código** | Todo controller e todo model tem um módulo dono. Sem órfãos. |
| **C2** | **Cobertura de registro** | Toda entrada do registro tem um dossiê (mesmo que de módulo morto). |
| **C3** | **Sem duplicata semântica** | Dois slugs que descrevem a mesma capacidade → um dossiê + alias, com o alias registrado. |
| **C4** | **Sem falso positivo** | Nenhum diretório de andaime (`Demo`, `Test`, `_Exemplos`) na lista de módulos. |
| **C5** | **Toda decisão tem razão** | Exclusões e fusões estão registradas com justificativa. |

> **C3 em ação:** o Portal Municipal tinha `diario-ofifical` (typo) e
> `diario-oficial`. Dois registros, uma capacidade. O dossiê é único, sob o
> slug correto, e o alias fica explícito na configuração do gerador de índice
> — não escondido.

---

## 5. Como registrar a decisão

Cada módulo da lista canônica deve ter, no mínimo:

| Campo | Exemplo |
|---|---|
| `slug` | `diario-oficial` |
| `nome` | Diário Oficial |
| `classe` | `registrado` |
| `versoes` | `v5, v6` |
| `evidencia` | rota `cms/diario-oficial.*`, controller `Prefecture\DiarioOficialController`, 3 migrations, 12 views |
| `decisao` | `documentar` |
| `notas` | `slug 'diario-ofifical' no registro é typo; ver alias` |

`evidencia` é o que torna a decisão auditável: qualquer pessoa consegue
reproduzir a inclusão do módulo a partir dela.

---

## 6. Anti-padrões

| Anti-padrão | Como se manifesta | Como evitar |
|---|---|---|
| **Módulo por tabela** | Cada tabela vira um "módulo" | Filtrar pelo teste de nomeabilidade |
| **Módulo por controller** | 20 módulos para 20 controllers | Agrupar por domínio de dados e prefixo de rota |
| **Módulo por menu** | O que está no menu do CMS é a lista | O menu é uma *visão*, não o registro |
| **Módulo por tela** | Cada view vira um módulo | Filtrar pelo teste de autonomia |
| **Módulo idealizado** | Lista tirada da nomenclatura de mercado, não do código | Toda entrada nasce do inventário |
| **Módulo fantasma** | Entra no plano de migração sem código | C2 + registro `morto` |
| **Fusão silenciosa** | Dois registros viram um dossiê sem registro do alias | C3 + alias explícito |
