# Comitê de Investimentos — Resumo Executivo

> **Versão analisada:** `v6`
> **Slug do módulo:** `comite-de-investimentos` (tabela `modulos`, id 48)
> **Natureza:** Ambos (CMS em `/cms` + Portal público)
> **Estado:** novo na v6 (nenhum arquivo, rota ou view relacionado existe na `v5`)

---

## 1. Objetivo

O módulo publica, no portal público, as **atas e documentos do Comitê de Investimentos**
do município — comitês de которые se registram as decisões de aplicação de recursos
públicos. O servidor da prefeitura cadastra as atas no CMS, classificando cada
documento em **categorias** (por exemplo, "Reuniões Ordinárias", "Reuniões
Extraordinárias"), e o cidadão acessa essas atas pelo site com **filtros por ano,
mês e texto livre**. O módulo também oferece ao operador uma listagem em DataTable
alimentada por uma **view SQL** (`comite_de_investimentos`).

## 2. Efeito / Impacto

| Faixa | Efeito |
|---|---|
| Cidadão | Acesso a atas e documentos do Comitê de Investimentos com busca por ano, mês e palavra-chave; visualização do documento com anexos. |
| Prefeitura (CMS) | Cadastro de atas com título, texto rico, data de publicação, categoria e anexos; gestão de categorias do comitê; listagem com exportação Excel/PDF/CSV. |
| Transparência e legalidade | Publica atas que registram deliberações sobre recursos públicos; o contador de acessos (`contents.clicks`) alimenta indicadores de interesse. |
| Operação técnica | Depende de `contents` + `category_contents` (compartilhado com Publicações, Notícias, Requerimentos etc.) e de uma view SQL que precisa ser mantida por migration. |

## 3. Comportamento

- O módulo só aparece no menu do CMS quando o registro em `modulos` (id 48) está
  com `status = true` e o operador tem a permissão correspondente
  (`v6/app/Providers/MenuServiceProvider.php:46`).
- As atas **não têm tabela própria**: são linhas de `contents` cuja
  `category_contents_id` aponta para uma **subcategoria** de
  `category_contents` cuja categoria-pai tem `slug = 'comite-de-investimentos'`.
- O portal só exibe atas **já publicadas** (`publication_date <= agora`) e **não
  excluídas** (`deleted_at IS NULL`).
- A listagem pública é paginada em **12 itens por página**, ordenada por
  `publication_date DESC, id DESC`.
- Filtros combináveis: **ano** (`whereYear`), **mês** (`whereMonth`) e **texto**
  (`ilike` sobre `title` e `text`, com normalização de acentuação).
- Ao abrir uma ata, o contador `clicks` do conteúdo é **incrementado** e a resposta
  é redirecionada ao index do comitê caso a ata ainda não esteja publicada.
- A view SQL `comite_de_investimentos` é usada **apenas pelo CMS** (DataTable); o
  portal público consulta `contents` diretamente via Eloquent.
- Categorias do comitê são ordenáveis por drag-and-drop (`ajust.categorias`).

## 4. Como o Usuário Interage

**Cidadão (portal)**

1. Acessa `/comite-de-investimentos` → redireciona para a **primeira** categoria
   (menor `order`) do comitê.
2. Escolhe a categoria na coluna lateral (`pub-nav.blade.php`).
3. Filtra por ano, mês e texto; a lista é recarregada via **AJAX** (sem recarregar
   a página) e a paginação é controlada por `hashchange`.
4. Clica numa ata → página de leitura (`view.blade.php`) com texto rico, anexos e
   PDF embutido.

**Operador (CMS)**

1. `/cms/conteudos/comite-de-investimentos` → listagem DataTable com colunas
   ID, Título, Categoria, Data de publicação e Ações.
2. Botão "Cadastrar Comitês de Investimentos" → formulário com categoria
   (obrigatória), título, data de publicação, texto rico (Summernote) e anexos.
3. Botão "Categorias de Comitês de Investimentos" → CRUD de subcategorias com
   ordenação por arraste.
4. Exclusão individual (DELETE ajax) e em lote (`ajax.generic.content.deleteAll`).

## 5. Detalhes e Particularidades Técnicas

- **Camadas:** `routes/web.php` → `Portal\ComiteDeInvestimentosController` →
  models `Content` / `CategoryContent` / `Archive` → view Blade
  `portal.layouts.{layout}.comite-de-investimentos.*`.
- **Camadas (CMS):** `routes/basepro.php` → `Prefecture\ContentController`
  (genérico, despachado por slug) e `Prefecture\CategoryContentController` →
  `ContentRepositoryDefaultImpl` → `contents` / `category_contents` / `archives`.
- **Sem model, repository ou Form Request próprio** — o módulo reaproveita a
  infraestrutura genérica de `contents`.
- **Views SQL:** `comite_de_investimentos`, criada e depois alterada por duas
  migrations (outubro e novembro de 2024).
- **Riscos reais:** SQL interpolado direto em `DB::select` com `{$_GET['ano']}`
  (SQL injection); partial AJAX renderizado a partir de `publicacoes.list`
  em vez de `comite-de-investimentos.list`; `getTemplateActived()` pode abortar
  com 404 se o layout ativo não tiver `home/index`.

## 6. Estrutura de Dados

| Objeto | Tipo | Papel |
|---|---|---|
| `contents` | tabela | Atas do comitê (compartilhada com todos os módulos de conteúdo) |
| `category_contents` | tabela | Categoria-pai `comite-de-investimentos` (id 39 no banco de dev) e suas subcategorias |
| `archives` | tabela | Anexos das atas (`view_pdf`, `highlight`) |
| `comite_de_investimentos` | view SQL | Listagem plana para o DataTable do CMS |
| `modulos` | tabela | Registro do módulo (id 48) e seu `status` |
| `menu_orders` | tabela | Slug `comite-de-investimentos` → `modulo_id = 48`, contador `clicks` |

## 7. Como Testar

- Portal: `/comite-de-investimentos` redireciona; filtro por ano muda a lista;
  filtro por texto sem acento encontra "Comite" quando o título é "Comitê";
  ata futura não abre; contador de cliques sobe.
- CMS: cadastrar ata com categoria obrigatória; sem categoria o formulário não
  valida; exclusão em lote remove as linhas marcadas; ordenação das categorias
  persiste.
- View SQL: `comite_de_investimentos` traz `categoria_slug` e `slug` (colunas
  adicionadas em nov/2024) e reflete o `deleted_at` dos conteúdos.

## 8. Migração para Laravel Moderno

Substituir o despacho por `switch` de slug por **rotas e controllers dedicados**
(`ComiteController` + `ComiteCategoryController`), com `FormRequest` próprio
validando `title`, `category_contents_id` e `publication_date` (hoje o módulo cai
no `default` do `ContentRequest` e **não valida** data nem texto). Eliminar o SQL
interpolado usando *bindings* do Eloquent/Query Builder; substituir a view SQL por
uma **consulta Eloquent** ou por um **Resource** JSON paginado; criar Policies
no lugar do `check.route.permission` textual; tipar o filtro de ano/mês com
`enum` ou validação `integer`.

## 9. Resumo Geral

O Comitê de Investimentos é um módulo **publicador**, sem tabela própria: as atas
são conteúdos genéricos (`contents`) categorizeados sob a categoria-pai
`comite-de-investimentos`. O portal monta uma listagem paginada com filtros de
ano, mês e texto livre, todos resolvidos por Eloquent, e cada documento abre uma
página de leitura com anexos e PDF. O CMS reaproveita os controllers genéricos de
conteúdo e categoria, com um DataTable alimentado pela view SQL
`comite_de_investimentos`. O módulo é **novo na v6** (nada existir na `v5`) e
está **desativado por padrão** no banco de desenvolvimento (`modulos.status =
false`). Os principais riscos a corrigir na reconstrução são o SQL interpolado com
`{$_GET['ano']}`, o partial AJAX herdado de Publicações, a ausência de validação
de `publication_date`/`text` e a dependência frágil do layout ativo.

---

## Índice do dossiê

| Arquivo | Conteúdo |
|---|---|
| `00-RESUMO.md` | Este documento |
| `01-ARQUITETURA.md` | Camadas, classes e o diagrama de fluxo |
| `02-MODELAGEM.md` | Estrutura de dados detalhada |
| `03-ROTAS-E-CONTROLADORES.md` | Rotas, controllers, requests, resources |
| `04-VIEWS-E-UX.md` | Telas, componentes, JS, assets |
| `05-REGRAS-E-PORTABILIDADE.md` | Particularidades e armadilhas |
| `06-MIGRACAO-MODERNA.md` | Plano de reconstrução em Laravel moderno |
| `07-TESTES.md` | Estratégia e casos de teste |
| `08-GAPS-E-DIVIDAS.md` | Pendências, riscos, comparativo v5 vs v6 |
