# P17 — Obras, contratos e integridade pública

| Campo | Valor |
|---|---|
| Programa | F7+ — operação, estrutura e conteúdo |
| Status | `planejado` |
| Depende de | P8, P15, P16 |
| Habilita | P18 |
| Tamanho | **G** (5–7 sessões) |
| ADRs | ADR-054 (VIAP/cotas), ADR-018/019, ADR-017, ADR-026/027, ADR-033, ADR-035, ADR-012 |

## 1. Objetivo

Publicar **obras, sanções, comitês, VIAP, diárias e unidades gestoras** — os dados de integridade
que o cidadão e os órgãos de controle consultam — com um dono por domínio, valores como string
decimal e anexos via Media. Nada de ETL, nada de dado pessoal desnecessário.

**Resultado observável:** o cidadão consulta uma obra e seus anexos, a lista de licitantes
sancionados, as atas do comitê, os pagamentos VIAP e as diárias; a obra paralisada aparece na visão
própria sem uma segunda tabela; todos os valores são exatos.

## 2. Escopo fechado

### S1 — Obras (e a visão Obras Paralisadas)

- Módulo `Transparencia/Obras` (token `obras`, grupo `Transparencia`).
- Tabela `obras`: `id`, `slug` único, `titulo` jsonb, `descricao` AST, `edital`, `contrato`,
  `empresa`, `valor_contratado` **string decimal** (`numeric` no banco; nunca `float`),
  `data_assinatura`, `data_inicio`, `previsao_fim`, `data_conclusao` null, `percentual_concluido`
  numeric(5,2) null, `status` enum (`planejada|em_execucao|paralisada|concluida|cancelada`),
  `data_paralisacao` null, `motivo_paralisacao` AST null, `responsavel_paralisacao` text null,
  `previsao_reinicio` date null, `processo_judicial` text null, `decisao_data` date null,
  `categoria`, `local`, `metadata` jsonb, timestamps.
- **PNTP 10.2/10.3:** `obra_itens` (`item`, `descricao`, `unidade`, `quantidade_contratada`,
  `preco_unitario`, `valor_total`) e `obra_medicoes` (`item_id`, `periodo`,
  `quantidade_executada`, `preco_unitario_pago`, `valor_pago`); totais contratados e pagos por item,
  não apenas valor global. Atualização 25/45 dias úteis.
- `obra_anexos`: `media_id`, `titulo` jsonb, `tipo` enum (`edital|contrato|projeto|medicao|foto|outro`),
  `position`, `publico` bool.
- `Obras Paralisadas` **não é tabela**: é a visão `status=paralisada` (página `/obras/paralisadas`,
  filtro e destaque), com o mesmo dado e o mesmo dono. Evita duas verdades.
- Portal `/obras` (filtros por status/categoria/ano, valor condicional), detalhe e galeria; CMS CRUD;
  sitemap/busca.
- Regras: se houver valor sigiloso, usar `show_value` como em Licitações (lista, detalhe, JSON-LD e
  sitemap); arquivar não apaga anexo; obra concluída não some; anexo público/privado.

### S2 — Licitantes Sancionados + Unidades Gestoras

- `Transparencia/LicitantesSancionados` (token `licitantes_sancionados`):
  - `licitantes_sancionados`: `id`, `nome`, `documento` (CNPJ público; CPF só se indispensável e
    cifrado), `tipo` enum (`empresa|pessoa_fisica`), `processo`, `sancao` enum/texto, `inicio`,
    `fim`, `motivo` (AST), `ativa` bool, timestamps.
  - Portal lista/detalhe com filtro por situação/período; CMS; sitemap/busca; LGPD (base legal).
- `Transparencia/UnidadesGestoras` (token `unidades_gestoras`):
  - `unidades_gestoras`: `id`, `nome` jsonb, `codigo`, `responsavel`, `contato`, `active`;
    referência para Licitações (P8) e Obras; portal de referência opcional; CMS.
  - Não duplicar Órgãos (P14): `orgao_id` nullable quando a unidade pertence a um órgão.

### S3 — Comitê de Investimentos + VIAP

- `Transparencia/ComiteInvestimentos` (token `comite_investimentos`):
  - `comite_atas`: `id`, `titulo` jsonb, `data`, `resumo`, `conteudo` AST, `publicado_em`, timestamps;
  - `comite_anexos`: `media_id`, `titulo` jsonb, `position`, `publico`;
  - `comite_membros`: `nome`, `cargo`, `periodo_inicio`, `periodo_fim`, `active` (sem CPF).
  - Portal lista/detalhe; CMS; sitemap/busca.
- `Transparencia/Viap` (token `viap`):
  - **D19:** P17 é o **dono único** de VIAP/cotas; P28 apenas lê/apresenta. Não criar tabela
    paralela em P28.
  - `viap_pagamentos`: `id`, `nome`, `partido`, `mes` (`YYYY-MM`), `categoria`, `valor` string
    decimal, `documento_media_id` nullable, `publicado_em`, timestamps.
  - Portal por mês/parlamentar/categoria, totalizadores; CMS; CSV export agregado se decidido.
  - Perfil Câmara: pode ficar `PODE` se o cliente não for câmara; o módulo é o mesmo.

### S4 — Requerimento de Diárias

- `Transparencia/Diarias` (token `diarias`), depende de P16 para o vínculo com servidor.
- Tabela `diarias`: `id`, `servidor_id` nullable FK (P16) ou `nome_solicitante`, `cargo`,
  `numero_diarias` int, `destino`, `periodo_inicio`, `periodo_fim`, `valor` string decimal,
  `finalidade`/`motivo` (AST), `status` enum (`solicitada|autorizada|realizada|cancelada`),
  `documento_media_id`, timestamps.
- **PNTP 7.2:** `diarias_valores` (`categoria` `dentro_estado|fora_estado|fora_pais`, `valor`,
  `vigencia_inicio`, `vigencia_fim`, `media_id` null); página
  `/transparencia/diarias/tabela-valores`; 1 ano/3 anos; `Atualizado em`.
- Portal lista/filtros por nome/mês/ano; CSV; 3 anos; CMS CRUD/aprovar; `diarias.aprovar`; LGPD:
  nome do servidor é público se houver base legal; não expor CPF/matrícula; valor/objetivo públicos.
- Regras: período consistente; valor > 0; anexo via Media; auditoria de aprovação.

### S5 — Integração e fechamento

- Cross-links: Obras ↔ Licitações (P8) e Unidade Gestora; VIAP ↔ Câmara (P18); Diárias ↔ Servidores
  (P16); Comitê ↔ Publicações (P15) se a ata também for publicação.
- `SitemapSource`/`SearchSource` por módulo público; valores como string decimal no JSON/CSV.
- E2E: obra/paralisada, sanção, ata, VIAP, diária; busca; sitemap; 4 locales; axe.
- `make check` 2× + `E2E=1`; cobertura ≥90%; PHPStan max 0.

## 3. Fora de escopo

- Integração contábil/financeira, empenho, liquidação, pagamento.
- Contratos completos: P23 (não duplicar aqui).
- Assinatura digital (P13).
- Câmara completa (P18) — aqui só VIAP.
- ETL do legado (ADR-042).

## 4. Fatias de sessão

| Sessão | Entrega | Prova | Depende |
|---|---|---|---|
| **P17.S1** | Obras + visão paralisadas + anexos | valor decimal; status; sem tabela duplicada; sitemap | P8/P15 |
| **P17.S2** | Licitantes Sancionados + Unidades Gestoras | documento público mínimo; vínculo órgão; busca | S1 |
| **P17.S3** | Comitê + VIAP | atas/anexos; VIAP por mês; totais; LGPD | S1 |
| **P17.S4** | Diárias | vínculo servidor; aprovação; valor; anexo | S1/P16 |
| **P17.S5** | integração + E2E + docs | cross-links; 4 locales; axe; 2× check | S1–S4 |

## 5. DoD

- [ ] Um dono por domínio; `Obras Paralisadas` é visão, não tabela.
- [ ] Valores monetários como string decimal (sem `float`).
- [ ] Anexos via Media; público/privado; arquivar não apaga.
- [ ] LGPD: documento pessoal cifrado ou ausente; DTO público allowlist.
- [ ] Busca/sitemap/4 locales/axe; `make check` 2× + `E2E=1`; cobertura ≥90%.
- [ ] PNTP 10.1: % concluído, empresa, datas; 10.2/10.3: itens e medições por item.
- [ ] PNTP 10.4: motivo/responsável/previsão/processo; 7.1: nº de diárias/cargo/motivo; 7.2: tabela.

## Fechamento — ficha de revisão

> **Obrigatório antes de fechar:** criar `_to_revision/P17-obras-integridade.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.

## 6. Riscos

| Risco | Mitigação |
|---|---|
| Duas tabelas para obras paralisadas | visão/filtro; teste de não duplicação |
| `float` em dinheiro | string decimal + validação; teste |
| CPF de sócio/sancionado exposto | cifrar/omitir; DTO allowlist; base legal |
| Diárias com dado de servidor | vínculo mínimo; sem CPF; auditoria |
| VIAP sem contexto de Câmara | perfil de produto; decidir antes de publicar |
| Anexos privados acessíveis | checagem no stream + teste 403 |

## 7. Retomada

```bash
kd prime
kd ask "obras paralisadas licitantes sancionados comitê VIAP diárias unidade gestora"
kd task list --ready
```

Ler: `dossie_modules/{obras,obras-paralisadas,licitantes-sancionados,comite-de-investimentos,viap,requerimento-de-diarias,unidade-gestora}/**`
→ `MODULOS.md` §1/P17 → P8/P15/P16 → `src/services/Media/**`.
