# P10 — Legislação: normas, versionamento e revogação

| Campo | Valor |
|---|---|
| Programa | F7+ — operação, estrutura e conteúdo |
| Status | `planejado` |
| Depende de | P9 |
| Habilita | P11 (prazos/atos), P13 (assinatura digital) |
| Tamanho | **G** (5–6 sessões) |
| ADRs | **ADR-048 (aceita)** — versionamento/consolidação/revogação; ADR-012, ADR-017, ADR-027, ADR-028, ADR-033, ADR-035, ADR-042 |

## 1. Objetivo

Publicar o acervo normativo do município com o que o backlog exige e o legado não tinha: **linha do
tempo** — versão publicada imutável, consolidação, alteração e revogação expressas, anexos e busca.
Não é um repositório de PDFs.

**Resultado observável:** uma lei publicada tem versão 1 imutável; uma alteração gera a versão 2
consolidada sem apagar a 1; a revogação marca a norma e mantém todo o histórico; o portal mostra o
texto vigente, o histórico e “revogada por”; o CSV de carga reaplica sem duplicar.

## 2. Estado atual

- Não existe módulo de legislação no V7.
- O dossiê V2 resolve agendamento por data e anexos com magic bytes, mas **não** tem
  versionamento/consolidação/revogação — exatamente a lacuna do backlog.
- `RichText` (AST), `Media` (anexos), `Seo` (`@graph`/sitemap), `Search` (P9) e `Importador` (P9)
  já existem.

## 3. Escopo fechado

### S1 — ADR-048 + modelo

> **D5:** versão publicada é imutável; consolidação/revogação são derivadas; a alternativa mais
> simples (sem Git de textos) é a escolhida.

- **ADR-048 (aceita)**: o que é “norma”, “versão”, “consolidação”, “alteração” e “revogação”; imutabilidade
  de versão publicada; como o texto vigente é derivado; o que nunca é apagado; como a URL de uma
  versão antiga responde (200 com aviso de “versão histórica”, não 404).
- Tabelas (schema `legislacao`):

| Tabela | Colunas principais |
|---|---|
| `legislacao_tipos` | `id`, `slug`, `nome` jsonb, `position` (dado de referência idempotente); inclui `lei`, `lei_complementar`, `decreto`, `portaria`, `resolucao`, `instrucao`, `aviso`, `outro` |
| `legislacao_normas` | `id` uuidv7, `tipo_id` FK, `numero` text, `ano` int, `data_publicacao` date, `data_vigencia` date null, `esfera` enum, `orgao` text null, `ementa` text, `slug` único, `status` enum (`vigente|alterada|revogada|suspensa`), `revogada_por_id` FK null, `metadata` jsonb, timestamps |
| `legislacao_versoes` | `id`, `norma_id` FK, `versao` int, `texto` jsonb (AST), `publicada_em` timestamptz, `publicada_por` FK user null, `notas` text null, `created_at`; `UNIQUE (norma_id, versao)`; versão publicada **imutável** |
| `legislacao_anexos` | `id`, `norma_id`, `versao_id` null, `media_id`, `titulo` jsonb, `position`, timestamps |
| `legislacao_alteracoes` | `id`, `norma_id`, `alterada_por_id`, `tipo` enum (`altera|revoga|consolida|suspende`), `descricao` text, `vigencia_em` date null, timestamps |

- Unicidade `(tipo, numero, ano)` case-insensitive; slug determinístico; `down()` preserva em
  `backup_*`.
- Status: derivado por ação explícita (não string livre); revogação grava `revogada_por_id` e
  `status=revogada`; uma norma revogada continua acessível com aviso, nunca 404.

### S2 — CMS editorial

- Rotas `/cms/legislacao` (lista/filtros por tipo/ano/status), criar/editar norma, versões
  (rascunho/publicar), anexos, alterações/revogação.
- Editor de texto rico (TipTap/AST) por locale; `ementa`/título traduzíveis; `texto` AST.
- Publicar versão exige `legislacao.aprovar`; versão publicada não é editável (nova versão);
  rascunho pode ser descartado; auditoria `legislacao.version_published`.
- Anexos via Media, MIME + magic bytes; PDF é o caso principal; ordem; vínculo opcional a uma versão.
- Alteração: seleciona a norma alteradora, o tipo, a descrição e a vigência; ao publicar, gera uma
  nova versão consolidada (texto editado no CMS) e mantém a anterior; a UI mostra o diff? Diff
  visual fica fora; mostrar “versão 1 → 2” e notas.
- Revogação: exige `legislacao.arquivar`, confirma, grava vínculo, não apaga anexos/versões.
- Importação: target do `Importador` (P9) com chave `tipo+numero+ano`; preview/dry-run; não importa
  texto sem confirmação; relatório de falhas parciais.

### S3 — Portal e API

- `GET /legislacao` — lista com filtros server-side (tipo, ano, status, esfera, texto), paginação,
  ordenação `data_publicacao desc, id desc`; normas revogadas visíveis com badge.
- `GET /legislacao/{slug}` — norma vigente: ementa, texto consolidado da última versão publicada,
  anexos, linha do tempo (versões/alterações/revogação), “revogada por” quando houver.
- `GET /legislacao/{slug}/versoes/{versao}` — versão histórica com aviso, `canonical` para a atual,
  `X-Robots-Tag: noindex`? Decisão: indexável se tiver conteúdo estável; canonical para a atual.
- `GET /api/v1/legislacao` read-only, rate limit, sem PII; `ETag`.
- SEO: `@graph` com `Legislation` (schema.org) + `GovernmentService` quando aplicável; sitemap das
  normas/publicações; canonical/hreflang.
- Busca: fonte do `Search` (P9) indexa ementa + texto consolidado; versões históricas não entram
  (ou entram com `url` da versão e `published_at`).
- Acessibilidade: texto longo com headings, sumário opcional, links de versão, tabela de anexos;
  4 locales.

### S4 — Fechamento

- **PNTP 2.6/20.2:** tipos incluem decretos, portarias, resoluções, instruções e avisos; filtros por
  tipo/ano/palavra; PDF pesquisável; `Atualizado em`; série de 3 anos; CSV do índice. A página
  `/transparencia/institucional/atos-normativos` pode ser uma visão filtrada de `/legislacao`.
- E2E: publicar v1 → alterar → v2 → revogar; portal mostra vigente/histórico; import CSV; busca.
- `make check` 2× + `E2E=1`; axe; cobertura ≥90%; query count (anti-N+1).
- Atualizar `INVENTARIO.md`, `modulo-legislacao.md` e a ADR-048.

## 4. Fora de escopo

- Diário Oficial (publicação oficial do ato) — **não é escopo de P10**; é o módulo separado
  `Publicacoes/DiarioOficial` em P15, referenciado por id/link quando a norma for publicada.
- Assinatura digital/ICP-Brasil (P13).
- Integração com sistemas de atos oficiais/lexml; export LexML fica para depois.
- ETL do legado (ADR-042); a carga é manual/CSV via importador.
- Diff textual sofisticado/patch automático de artigos.

## 5. Fatias de sessão

| Sessão | Entrega | Prova | Depende |
|---|---|---|---|
| **P10.S1** | ADR-048 + schema + tipos seed + unicidade | versão publicada imutável; revogação preserva; slug | P9 |
| **P10.S2** | CMS norma/versão/anexo/alteração/revogação | publicar exige permissão; v2 mantém v1; auditoria | S1 |
| **P10.S3** | portal lista/detalhe/versão + SEO + busca | vigente/histórico; `@graph`; canonical; axe | S2 |
| **P10.S4** | importador target + API | dry-run; idempotência; rate limit; `ETag` | S2, P9 |
| **P10.S5** | E2E, docs, 2× check | evidência no `kd` | S3–S4 |

## 6. Contratos e dados

- **Módulo:** `Publicacoes/Legislacao` (token `legislacao`).
- **Tabelas:** `legislacao_tipos`, `legislacao_normas`, `legislacao_versoes`,
  `legislacao_anexos`, `legislacao_alteracoes`.
- **Rotas:** `legislacao.portal.*`, `legislacao.cms.*`, `api.legislacao.*`.
- **Permissões:** `legislacao.ver/editar/aprovar/arquivar`.
- **Portas:** `SearchSource` (P9), `ImportTarget` (P9), `SitemapSource`.
- **Eventos:** `legislacao.norm_created`, `legislacao.version_published`, `legislacao.amended`,
  `legislacao.revoked`.

## 7. DoD

- [ ] Versão publicada é imutável; alteração cria nova versão; revogação não apaga nada.
- [ ] Portal mostra texto vigente, histórico, anexos e “revogada por”; versão histórica responde 200.
- [ ] Unicidade tipo+numero+ano; slug determinístico; import CSV idempotente.
- [ ] Busca/SEO/sitemap integrados; API read-only com rate limit.
- [ ] Permissões de aprovar/arquivar aplicadas; auditoria de cada transição.
- [ ] `make check` 2× + `E2E=1`; cobertura ≥90%; PHPStan max 0.
- [ ] PNTP 2.6/20.2: tipos de ato, filtro tipo/ano/palavra, PDF, 30 dias/3 anos, CSV.

## Fechamento — ficha de revisão

> **Obrigatório antes de fechar:** criar `_to_revision/P10-legislacao.md` e seguir
> `_to_revision/README.md` + `_to_revision/PROTOCOLO.md` (v2.0). A ficha não é gate de build; é a
> entrada da fila de revisão profunda.

- Cabeçalho: fase, `kd` épico/tasks/slices, âncoras (este arquivo, ADRs e código) e status
  `⬜ pendente` → `🟡 em revisão` → `✅ revisado` / `🔧 com correções`.
- Conteúdo: o que foi implementado, arquivos/superfícies a revisar, checklist D1–D14 aplicável,
  riscos e observações.
- Fechamento: preencher “Notas da revisão” com data/revisor/resultado e achados (`kd write
  --anchor`), atualizar a fila em `_to_revision/README.md` e `_to_revision/_inventario.md`.
- Achado com correção exige teste vermelho→verde; a fase só é `closed` no `kd` com a ficha
  registrada.

## 8. Riscos

| Risco | Mitigação |
|---|---|
| Editar versão publicada e perder a história | versão imutável no model/DB; nova versão; teste de update proibido |
| Revogação apagar anexos | revogação é vínculo/status; teste de preservação |
| Texto consolidado divergente | uma versão publicada é a verdade; consolidação é uma nova versão explícita |
| Importação duplicar | chave `tipo+numero+ano` + `key_hash`; dry-run; teste |
| URL histórica quebrar | rota de versão + canonical; teste |
| Legislação virar “drive de PDF” | versão/AST/anexo vinculado; ementa obrigatória; teste de conteúdo |

## 9. Retomada

```bash
kd prime
kd ask "legislação versionamento revogação consolidação"
kd task list --ready
```

Ler: `wiki/backlog/modulo-legislacao.md` → `dossie_modules/legislacao/**` →
`lotep-v2/publicacoes-legislacao/09-APROVEITAMENTO-V7.md` → `sucesu_analise/05_modulos/AtosOficiais/**`
→ `src/services/RichText/**` → `src/services/Media/**`.
