# Sessões da Câmara Municipal — Gaps, Bugs e Dúvidas

> Módulo `sessoes` na `v6`.
> **Registro explícito:** o módulo **não existe na v5** — é integralmente novo
> na v6.

---

## 1. Mapa v5 → v6

### 1.1 Ausência na v5

Uma busca por `sessoes` / `sessions` em `v5/routes/`, `v5/app/`,
`v5/database/` e `v5/resources/views/` **não retorna nenhum equivalente
funcional**. Os únicos aciertos são arquivos de configuração de sessão do
framework (`v5/config/session.php`) e bibliotecas de terceiros (AWS SDK,
Symfony HttpFoundation, Guzzle), sem relação com o módulo.

| Camada | v5 | v6 |
|---|---|---|
| Rotas do portal | — | `sessoes.index`, `sessoes.show` (`v6/routes/web.php:113-114`) |
| Controller do portal | — | `v6/app/Http/Controllers/Portal/SessionsController.php` |
| Rotas do CMS | — | `listar-conteudo`, `cadastrar-conteudo`, `editar-conteudo`, `datatable.sessoes` |
| View SQL | — | `sessoes` (`v6/database/migrations/2024_09_30_004936_create_view_sessoes.php`) |
| Categoria | — | raiz `sessoes` (`v6/database/seeds/CategoryContentTableSeeder.php:196-200`) |
| Módulo do CMS | — | `modulos.id = 40`, `status = 0` (`v6/database/migrations/2024_11_01_150206_create_modulos_table.php:262-267`) |
| Recurso de permissão | — | `resources.slug = 'sessoes'` (`v6/database/seeds/ResourcesTableSeeder.php:486-493`) |
| Menu do CMS | — | `v6/app/Providers/MenuServiceProvider.php:51-53` |
| Widget da home | — | `layouts.sessoes` / `layouts.sessoes-list` (`v6/database/seeds/AddSessoesToLayout.php`) |
| Blades do portal | — | 6 layouts × 2 arquivos + 1 widget |
| Blades do CMS | — | `index`, `create`, `edit`, `form` |
| Testes | — | nenhum |

### 1.2 Lacuna funcional que isso representa para o município

Na v5, **o portal não oferecia nenhuma forma de publicar as sessões da
Câmara**. Concretamente, o município que operava a v5:

- **não tinha** uma página pública com o histórico das sessões plenárias;
- **não tinha** galeria de fotos das reuniões;
- **não tinha** vídeo da gravação da sessão embedado no portal;
- **não tinha** registro de ata/ementa em formato de conteúdo rico com data e
  hora (o que existe hoje é apenas a seção de atas e pontos de frequência, um
  módulo distinto);
- ficava **obrigado** a usar um sistema externo (YouTube avulso, álbum de
  fotos, PDF solto) sem integração com o portal, o que quebrava a
  rastreabilidade entre a sessão e sua mídia.

O impacto de transparência é relevante: sem registro público das plenárias,
o cidadão não conseguia conferir quais projetos foram apreciados, quais
votações ocorreram e quem/generated participates.

### 1.3 O que precisa ser decidido/replicado na v7

| # | Decisão | Alternativas |
|---|---|---|
| D1 | **Escopo do dado**: tabela própria `sessions` ou continuação do `contents` genérico. | Recomendação: tabela própria (o módulo tem semântica própria: `starts_at`, `ends_at`, `session_type`, `session_number`, `video_url`). |
| D2 | **URL canônica**: `/sessoes/{slug}` ou `/portal/sessoes/{slug}`. | Recomendação: `/sessoes/{slug}`, com *redirect* 301 da outra. |
| D3 | **Subcategorias**: a raiz `sessoes` hoje comporta subcategorias, mas elas são **invisíveis** para o módulo (o portal e a view filtram pelo id exato da raiz). | Decidir: (a) prohibiting subcategorias; (b) migrar para `category_contents_id IN (subtree)`. |
| D4 | **Tipos de sessão**: ordinária, extraordinária, solene, de presque. | Definir o enum com o negócio e cadastrar as séries históricas. |
| D5 | **Numeração**: a v6 não tem campo de número da sessão ("12ª Sessão Extraordinária"). O título livre é a única informação. | Criar `session_number` e/ou `session_legislature` (legislatura 2025-2028). |
| D6 | **Vínculo com a pauta do dia**: a v6 tem o módulo `pauta-do-dia` como conteúdo genérico, **sem** relação com a sessão. | Decidir se a pauta é filha da sessão (FK `session_id`) ou se basta uma referência textual. |
| D7 | **Vínculo com os vereadores/ordem do dia**: não há FK entre a sessão e `councilmen`. | Avaliar o modelo de dados para "participantes da sessão". |
| D8 | **Padrão de legenda**: a v6 usa `links` genérico como vídeo; a v7 pode ter `video_url` dedicado (recomendado). | — |
| D9 | **Ata em PDF**: hoje a ata é o próprio texto rico; não há PDF oficial vinculado. | Avaliar `media` para a ata assinada. |
| D10 | **Retenção**: o acervo é permanente ou há expiração (mandato de 4 anos)? | Definir política de arquivamento e de exclusão lógica. |

## 2. Bugs e comportamentos problemáticos encontrados

| # | Severidade | Descrição | Evidência |
|---|---|---|---|
| B1 | **Alta** | O **detalhe** da sessão (`/sessoes/{slug}`) não filtra por `status` nem por `publication_date`. Uma sessão em **rascunho** ou com data **futura** é acessível por URL direta, desde que o layout ativo tenha a pasta `sessoes/`. O filtro existe apenas na listagem. | `v6/app/Http/Controllers/Portal/SessionsController.php:42-53` (sem `where('status', true)` nem pelo limite de `publication_date`, filtros que existem apenas no `index`) |
| B2 | **Alta** | O **widget da home** (`modelo5`) usa a consulta crua do `PortalController` (`orderBy('publication_date','desc')->limit(4)`), **sem** filtro de `status` nem de data. Um rascunho com data passada aparece na home mas **não** em `/sessoes`. | `v6/app/Http/Controllers/Portal/PortalController.php:145-150` |
| B3 | **Média** | Subcategorias criadas dentro de `sessoes` ficam **invisíveis**: a view SQL e o controller do portal filtram pelo `id` exato da raiz (`category_contents_id IS NULL` na raiz), não pela subárvore. | migration da view; `SessionsController.php:24-27` |
| B4 | **Média** | **Duas URLs públicas** para o mesmo conteúdo. `modelo1` e `modelo2` apontam para `conteudo.portal.show` (`/portal/sessoes/{slug}`); `modelo3`..`modelo6` usam `sessoes.show` (`/sessoes/{slug}`). O breadcrumb do detalhe sempre aponta para a primeira. | `v6/resources/views/portal/layouts/modelo1/sessoes/index.blade.php:18`, `v6/routes/breadcrumbs.php:73` |
| B5 | **Média** | A listagem de sessões nos `modelo3` e `modelo4` é **condicionada** a `getStatusDisplayNews()['displayNews'] == 0`, configuração que pertence ao módulo de Notícias. Desligar Notícias **esconde** as sessões. | `v6/resources/views/portal/layouts/modelo3/sessoes/index.blade.php:11` |
| B6 | **Média** | `getTemplateActived()` aborta 404 e **grava `configurations.pagina_em_manutencao = 1`** quando o layout ativo não tem `home/index.blade.php`. Como `default` e `newsbit` não têm, trocar o tema **coloca o portal inteiro em manutenção**. | `v6/app/Http/Controllers/Admin/Controller.php:39-49` |
| B7 | **Média** | `get_sessoes()` carrega a view **inteira** em memória (`DB::table('sessoes')->get()`), sem paginação no servidor. O DataTables pagina no cliente. Acervo grande = consumo de memória e lentidão. | `v6/app/Http/Controllers/Prefecture/DatatableController.php:28-32` |
| B8 | **Baixa** | O `form.blade.php` referencia `assets/js/custom/contents/sessoes/edit.js`, arquivo inexistente no repositório (o diretório só tem `datatables.js`). 404 silencioso. | `v6/resources/views/prefecture/contents/sessoes/form.blade.php` |
| B9 | **Baixa** | A comparação estrita `$session->galery === true` depende do tipo retornado pelo driver. Sem `cast` declarado no model `Content`, uma mudança de driver (MySQL, ou um novo cast) pode devolver `1` e **ocultar a galeria silenciosamente**. | `v6/resources/views/portal/layouts/modelo5/sessoes/show.blade.php:36`; `v6/app/Http/Model/Prefecture/Content.php` (sem `casts` para `galery`) |
| B10 | **Baixa** | A ordenação da listagem do CMS é `ASC` sobre `value` (o `row_number()` da view), de modo que a sessão **mais recente aparece primeiro**. O número exibido na coluna ID é, portanto, um **rank** da data, não o `id` da tabela `contents` — e a URL de compartilhamento no Facebook usa o `slug`, não esse número. | `v6/public/assets/js/custom/contents/sessoes/datatables.js` |
| B11 | **Baixa** | A view SQL ordena por `publication_date DESC` mas **não** desempata por `created_at`; sessões com a mesma data (ou data nula) têm ordem arbitrária, e o `row_number()` não é estável entre chamadas. | migration da view |
| B12 | **Baixa** | `Content::linksUnique()` é `hasOne`: se houver mais de um link para a mesma sessão, apenas o primeiro (menor `id`) vira vídeo; os demais são ignorados pelo portal sem aviso. | `v6/app/Http/Model/Prefecture/Content.php:116` |
| B13 | **Informativo** | A listagem do CMS mostra **rascunhos e sessões futuras** — comportamento intencional para o operador, mas que exige cuidado para não confundir com a lista pública. | view SQL `sessoes` |
| B14 | **Informativo** | A exclusão é lógica (`deleted_at`) e a view já filtra `deleted_at IS NULL`; o operador não vê a diferença entre "excluído" e "nunca existiu" na listagem. | migration da view; `SoftDeletes` |

## 3. Funcionalidades incompletas ou mortas

| # | Item | Situação |
|---|---|---|
| F1 | Galeria de fotos | Implementada (aba no CMS + lightGallery no portal), mas **não há** legendas, ordem manual por mouse, paginação nem limite de quantidade de fotos. |
| F2 | Vídeo | Aceita apenas **um** link por sessão; não há playlist, nem support a múltiplos ângulos (plenária, oradores). |
| F3 | Busca | Não há busca dentro de sessões; a rota genérica `busca.por.categoria` não considera o módulo. |
| F4 | Filtros | A listagem pública não tem filtro por ano, tipo ou período (ao contrário do módulo de Legislação, que tem `/legislacao/filtro`). |
| F5 | Exportação | Só o CMS exporta (Excel/PDF via DataTables). O público não tem exportação. |
| F6 | Número da sessão | Não existe campo estruturado; fica no título. |
| F7 | Ata oficial | Não há vínculo com a ata em PDF assinada nem com a ementa. |
| F8 | SSO / integração com a Câmara | Nenhuma. Todo o conteúdo é digitado manualmente no CMS. |
| F9 | Padrão de imagem de destaque | O `ContentPresenter::getArchiveContentHighlightOrThumbnail()` gera thumbnail de YouTube/Vimeo **em tempo de execução** na renderização do card, sem cache — custo por requisição. |
| F10 | Testes | Nenhum teste cobre o módulo. |

## 4. Riscos de dados (migração de schema)

| # | Risco | Impacto |
|---|---|---|
| RD1 | **Dados zerados**: na base de análise há **0 conteúdos** na categoria `sessoes`. A migração para `sessions` não terá volume histórico, mas também não há massa de teste para validar. | Baixo na migração, alto na validação funcional. |
| RD2 | **View SQL fora do versionamento do schema**: `CREATE VIEW` por `DB::statement` não é gerenciado pelo `Schema` do Laravel; ambientes com `migrate` parcial ficam sem a view e a listagem do CMS quebra. | Médio. |
| RD3 | **Colisão de `slug`**: `contents.slug` não tem índice único; o `store` desambigua em memória (`-{max_id}`), mas `update` usa `pub{id}-{slug}`. Ao criar `unique(sessions.slug)` na v7, duplicatas históricas quebram a migração. | Médio. |
| RD4 | **Timestamps ausentes**: `contents.created_at` e `updated_at` são aceitos como nulos; `publication_date` também pode ser nula em conteúdos antigos. Sessões sem data ficariam invisíveis no portal (ou visíveis, se o filtro mudar). | Médio. |
| RD5 | **Fotos de galeria e destaque na mesma tabela**: `archives` mistura os dois papéis via `highlight`; a migração precisa respeitar `highlight IS NULL` / `highlight = 1` exatamente como o legado. | Médio. |
| RD6 | **Links órfãos**: `links.contents_id` pode apontar para conteúdos de outras categorias; a migração deve filtrar por `category_contents_id` da raiz `sessoes`. | Baixo. |
| RD7 | **HTML legado**: o texto do Summernote referencia imagens em `summernote-files/temporarios/` e em `summernote-files/content/{slug}/{id}/`. A migração de arquivos precisa reescrever esses caminhos. | Médio. |
| RD8 | **Permissões**: o recurso Sentinel `sessoes` precisa ser recriado no novo modelo de permissões, ou os operadores perdem o acesso. | Alto se esquecido. |
| RD9 | **Storage**: `archives.path` aponta para `storage/content/sessoes/{id}/destaque`; a migração de arquivos para o disco `public` precisa reescrever os paths gravados no banco. | Médio. |

## 5. Perguntas em aberto para o negócio

1. As sessões devem ser **vinculadas a uma legislatura** e a um **período**
   (2025-2028)? Hoje não há essa informação.
2. Existe **número oficial** da sessão ("12ª Sessão Ordinária da 3ª Sessão
   Legislativa")? Precisa de campo próprio?
3. O **vídeo** deve ser único (a gravação da plenária) ou a sessão pode ter
   vários (por orador)?
4. A **pauta do dia** e a **ata** devem ser filhas da sessão, ou continuam
   como módulos independentes?
5. É preciso registrar os **vereadores presentes** e o **quórum**?
6. A galeria deve ter **legenda, autor da foto e data**?
7. Existe exigência de **publicar a ata em PDF assinado**?
8. O módulo deve ser **público sem autenticação** (como hoje) ou há uma área
   restrita para rascunhos em preparação?
9. Deve haver **retenção** do acervo ou o histórico é permanente?
10. Os conteúdos publicados hoje (se houver, em outra instalação) devem ser
    **migrados** ou o módulo começa vazio?

## 6. Itens que existem na v5 e foram removidos na v6

Nada a reportar: o módulo `sessoes` **não existia na v5**, portanto não houve
remoção. O inverso também é verdadeiro — a v6 **introduziu** o módulo.

## 7. Recomendações priorizadas para a v7

| Prioridade | Ação | Origem |
|---|---|---|
| P0 | Corrigir o vazamento de rascunhos e de conteúdo futuro no detalhe (`show`) e no widget da home. | B1, B2 |
| P0 | Definir uma URL canônica e redirecionar a outra. | B4, D2 |
| P1 | Eliminar a dependência da view SQL e paginar o endpoint do CMS no servidor. | B7, RD2 |
| P1 | Decidir o destino das subcategorias dentro de `sessoes`. | B3, D3 |
| P1 | Remover a dependência de `getStatusDisplayNews()` nos layouts de sessão. | B5 |
| P1 | Garantir que a troca de layout não coloque o portal em manutenção (validar o `home/index` do tema ativo antes de abortar). | B6 |
| P2 | Criar testes automatizados para o módulo (ver `07-TESTES.md`). | F10 |
| P2 | Corrigir a referência ao `edit.js` inexistente. | B8 |
| P2 | Declarar `casts` para `status` e `galery` no model. | B9 |
| P2 | Tornar estável a ordenação da listagem do CMS (desempate por `created_at` na ordenação da view). | B11 |
| P3 | Cachear a thumbnail de vídeo e as miniaturas de destaque. | F9 |
| P3 | Criar campo `session_number` e `session_legislature`. | D5 |
