# Pauta do Dia — Arquitetura

> **Slug:** `pauta-do-dia` · **Módulo:** `modulos.id = 42` · **Novo na v6**
> Escopo: como uma requisição percorre o portal e o CMS até a tela e o banco.

---

## 1. Visão geral

O módulo "Pauta do Dia" é um **conteúdo genérico tipado por categoria**. Não
existe model, migration ou tabela própria: tudo é gravado em `contents` e
classificado por `category_contents.slug = 'pauta-do-dia'`. Consequência
arquitetural: o portal e o CMS **não compartilham a mesma fonte de dados**.

| Lado | Fonte da listagem | Mecanismo |
|---|---|---|
| Portal (público) | tabela `contents` | Eloquent (`Content::whereHas('categoryContents', ...)`) |
| CMS (AdminLTE) | view SQL `pauta_do_dia` | `DB::table('pauta_do_dia')->get()` + Yajra DataTables |

A duplicação de fonte é a origem da duplicação da regra de ordenação
(descrita em `05-REGRAS-E-PORTABILIDADE.md`).

## 2. Fluxo de requisição — Portal (público)

```
Navegador
   |
   |  GET /pauta-do-dia
   v
v6/routes/web.php:49
   Route::get('/pauta-do-dia', 'Portal\PautaDoDiaController@index')
        |
        |  middleware do grupo: check.site.manutention
        v
v6/app/Http/Controllers/Portal/PautaDoDiaController.php:14  index()
   |  1) CategoryContent::where('slug','pauta-do-dia')->whereNull('category_contents_id')->first()
   |  2) Content::whereHas('categoryContents', fn($q) => $q->where('slug','pauta-do-dia'))
   |          ->orderByRaw("publication_date::date DESC, COALESCE(NULLIF(regexp_replace(...)), '0')::numeric DESC, id DESC")
   |          ->paginate()
   v
v6/app/Http/Controllers/Admin/Controller.php:39  getTemplateActived()
   |  Configuration 'layout' -> "modelo1".."modelo6" | "default"
   v
view("portal.layouts.{$this->getTemplateActived()}.pauta-do-dia.index")
   -> v6/resources/views/portal/layouts/modelo1/pauta-do-dia/index.blade.php
```

Detalhe público:

```
GET /pauta-do-dia/{slug}
   v
v6/app/Http/Controllers/Portal/PautaDoDiaController.php:25  show(string $slug)
   |  Content::whereHas('categoryContents', ...)->where('slug',$slug)->firstOrFail()  (404 se nao existir)
   |  Archive::where('contents_id',$pauta->id)->where('highlight', null)->get()
   |  Archive::where('contents_id',$pauta->id)->where('view_pdf', true)->first()
   v
v6/resources/views/portal/layouts/modelo1/pauta-do-dia/show.blade.php
   + include v6/resources/views/portal/components/view_pdf/files-list.blade.php
```

## 3. Fluxo de requisição — CMS (AdminLTE)

```
Navegador (operador logado)
   |
   |  GET /cms/conteudos/pauta-do-dia          (menu "Pauta do Dia")
   v
v6/routes/basepro.php:235  listar-conteudo
   -> Prefecture\ContentController@genericIndex
        v6/app/Http/Controllers/Prefecture/ContentController.php:112
        if ($slug === 'pauta-do-dia') return $this->returnIndex('Pauta do dia', $slug);
   |  generateLog('Pauta do dia')  -> ActivityLog
   |  menuClicks('pauta-do-dia')   -> menu_orders.clicks++
   v
v6/resources/views/prefecture/contents/pauta-do-dia/index.blade.php
   |  carrega v6/public/assets/js/custom/contents/pauta-do-dia/datatables.js
   |  -> runDatatables('pauta-do-dia', collums, true, 'DESC', null, true, null, 3)
   |     (v6/public/assets/js/custom/utilities/table.js:3)
   v
GET /cms/datatable/pauta-do-dia                (v6/routes/basepro.php:459)
   -> Prefecture\DatatableController@get_pauta_do_dia
        v6/app/Http/Controllers/Prefecture/DatatableController.php:464-468
        DB::table("pauta_do_dia")->get()  -> struct_views($data,'pauta-do-dia')
        -> DataTables::of(...)->make(true)   (Yajra)
```

Fluxo de cadastro/edição (CRUD genérico de conteúdo):

```
GET  /cms/conteudos/cadastrar/pauta-do-dia  -> genericCreate -> returnData(...)
GET  /cms/conteudos/editar/pauta-do-dia/{id}-> genericEdit  -> returnData(...)
POST /cms/conteudo                          -> ContentController@store(ContentRequest)
PUT  /cms/conteudo/{id}                     -> ContentController@update(ContentRequest)
DELETE /cms/conteudo/{id}                   -> ContentController@destroy (via JS addDelete)
POST /cms/conteudo/deleteAll                -> ContentController@genericDeleteAll
```

## 4. Classes e arquivos envolvidos

| Classe / arquivo | Papel no módulo |
|---|---|
| `v6/app/Http/Controllers/Portal/PautaDoDiaController.php` | Controller público: `index()` e `show()`. Aplica a ordenação customizada e carrega anexos. |
| `v6/app/Http/Controllers/Admin/Controller.php` | Controller base dos controllers de portal; `getTemplateActived()` (linha 39) define o tema das views. |
| `v6/app/Http/Controllers/Prefecture/ContentController.php` | CRUD genérico do CMS; `genericIndex` (linha 112) e `returnData` (linha 235) roteiam o slug `pauta-do-dia`; `store`/`update`/`genericDestroy` gravam e auditam. |
| `v6/app/Http/Controllers/Prefecture/DatatableController.php` | `get_pauta_do_dia()` (linhas 464-468) alimenta a listagem do CMS a partir da view SQL; `struct_views()` (linha 504) injeta as flags de permissão. |
| `v6/app/Http/Requests/ContentRequest.php` | Validação do formulário; `case 'pauta-do-dia'` na linha 262 define as regras. |
| `v6/app/Http/Model/Prefecture/Content.php` | Model da tabela `contents` (SoftDeletes, `casts` de `publication_date`, relações `archives()` e `categoryContents()`). |
| `v6/app/Http/Model/Prefecture/CategoryContent.php` | Model da tabela `category_contents` (árvore por `category_contents_id`). |
| `v6/app/Http/Model/Prefecture/Archive.php` | Model da tabela `archives` (anexos, `highlight`, `view_pdf`). |
| `v6/app/Http/Middleware/CheckRoutePermission.php` | Autorização por rota do CMS: converte o segmento da URL em permissão (`pauta-do-dia.create`, `.edit`, `.index`). |
| `v6/app/Library/Helper/appHelpers.php` | `has_access()` (linha 22): verifica `hasAccess`/`hasAnyAccess` do Sentinel; `super-admin` passa. |
| `v6/app/Helpers/functions.php` | `menuClicks()` (linha 865): telemetria de cliques; `clean_slug()` (linha 823); `embedVideo()` (linha 607). |
| `v6/app/Providers/MenuServiceProvider.php` | Insere o item de menu "Pauta do Dia" no CMS (linhas 142-144). |
| `v6/public/assets/js/custom/contents/pauta-do-dia/datatables.js` | Colunas do DataTable e `converterDataPauta()` (chave de ordenação). |
| `v6/public/assets/js/custom/utilities/table.js` | `runDatatables()` (linha 3), `createBTN()` (linha 227), `createSingleButton()` (linha 266), `addDelete()` (linha 466). |
| `v6/public/assets/js/custom/utilities/deleteAll.js` | Exclusão em lote (botão `deleteByLoteSubmitButton`). |
| `v6/database/migrations/2024_10_13_010549_create_view_pauta_do_dia.php` | Cria a view SQL `pauta_do_dia`. |
| `v6/database/migrations/2024_11_01_150206_create_modulos_table.php` | Registra o módulo 42 (`Pauta do Dia`, `status = 0`). |
| `v6/database/seeds/CategoryContentTableSeeder.php` | Cria a categoria `pauta-do-dia` (linha 212). |
| `v6/database/seeds/ResourcesTableSeeder.php` | Cria o recurso/funcionalidade `pauta-do-dia` ligado ao módulo 42 (linha 504). |
| `v6/database/seeds/MenuOrderSeeder.php` | Cria `menu_orders` com `slug = 'pauta-do-dia'` e `modulo_id = 42` (linha 284). |
| `v6/database/seeds/MenuItemsTableSeeder.php` | Cria o item de menu do portal "Pauta do Dia" (linha 382). |

## 5. Diagrama de dependências

```
                 +-------------------------------------------+
                 |  Categoria (category_contents)            |
                 |  slug = 'pauta-do-dia'  (id 38 no banco)  |
                 +----------------------+--------------------+
                                        | 1:N (contents.category_contents_id)
                                        v
   +---------------------------   +-----------------------------+   +------------------+
   |  Portal (público)        |   |  contents                   |   |  archives        |
   |  PautaDoDiaController     +-->|  title, text,               |<--+|  contents_id     |
   |  index() / show()         |   |  publication_date, slug,   |   |  highlight,      |
   +------------+--------------+   |  author, source, status    |   |  view_pdf, path  |
                |                  +--------------+--------------+   +------------------+
                |                                 |
                |                  +--------------v--------------+
                |                  |  category_contents (pai)    |
                |                  +-----------------------------+
                v
   +---------------------------------------------------+
   |  Blade portal.layouts.modelo1..modelo6               |
   |            .pauta-do-dia.index / .show              |
   |  + portal.components.view_pdf.files-list            |
   +---------------------------------------------------+

   +---------------------------------------------------+
   |  CMS (AdminLTE)                                    |
   |  ContentController (genericIndex/returnData/store)  |
   |  ContentRequest (case 'pauta-do-dia')              |
   |  DatatableController@get_pauta_do_dia               |
   |  -> DB::table('pauta_do_dia')  (view SQL)           |
   |  -> Yajra DataTables + datatables.js                |
   +---------------------------------------------------+
```

## 6. Dependências externas

| Pacote | Versão (v6/composer.json) | Uso no módulo |
|---|---|---|
| `laravel/framework` | `5.5.*` | Base: Eloquent, rotas, Blade, paginação. |
| `yajra/laravel-datatables` | `^1.5` | DataTable server-side da listagem do CMS. |
| `cartalyst/sentinel` | `2.0.*` | Autenticação e permissões (`has_access`, `Sentinel::inRole`). |
| PostgreSQL 10 (+ PostGIS) | servidor | View SQL, `regexp_replace`, casts `::date`/`::numeric`, `to_char`. |
| jQuery + DataTables (CDN/asset) | — | Ordenação client-side da coluna "Data e Hora" pela chave `converterDataPauta`. |
| Summernote | plugin do AdminLTE | Editor de texto rico do formulário do CMS. |

## 7. Onde o módulo se acopla ao resto do sistema

- **Depende de** `contents`/`category_contents`/`archives` (núcleo de conteúdo
  do CMS) e do `MenuServiceProvider` (item de menu do CMS).
- **Alimenta** o item de menu público "Pauta do Dia" (`menu_items`), a
  telemetria `menu_orders.clicks` e a tabela de atividades (auditoria).
- **Compartilha a tabela `contents` com** Notícias, Requerimentos, Sessões,
  Transmissões, Atas e Pontos, Publicações, Legislação, Banners e demais
  módulos genéricos. Uma falha no CRUD genérico de conteúdo atinge todos.
- **Relaciona-se conceitualmente** com o módulo `sessoes` e
  `atas-e-pontos` (mesma domínio legislativo), mas **não há vínculo de dados**
  entre eles: a pauta não referencia a sessão, e a ordenação por número de
  sessão é apenas textual, extraída do título.

## 8. Pontos de atenção arquitetural

1. **Duas fontes de listagem** (tabela x view) podem divergir: a view filtra
   `deleted_at IS NULL` e a categoria exata; o controller do portal filtra via
   `whereHas` + SoftDeletes. Hoje coincidem, mas nada garante isso.
2. **A ordenação é implementada duas vezes** (PHP e JS), sem teste cruzado.
3. **O módulo é desligado por padrão** (`modulos.status = 0`): o operador
   precisa habilitá-lo em `/cms/modulos`; a habilitação controla a exibição
   do item de menu, não a rota.
4. **Não há model, repository ou service dedicado**: tudo depende do CRUD
   genérico de `contents`.
