# Agenda de Eventos — Gaps, Bugs e Dívidas

---

## 1. Bugs / erros conhecidos

| # | Descrição | Evidência | Efeito |
|---|---|---|---|
| B1 | A rota `agenda-evento.show` (do `Route::resource`) aponta para um método inexistente | `v6/routes/basepro.php:202` x `v6/app/Http/Controllers/Prefecture/CalendarEvent/CalendarEventController.php` (não há `show()`) | `GET /cms/agenda-evento/{id}` retorna **erro 500** |
| B2 | `categoria-agenda-evento.create` e `.show` também não têm métodos correspondentes | `v6/routes/basepro.php:203` x `v6/app/Http/Controllers/Prefecture/CalendarEvent/CategoryCalendarEventController.php` | Erro 500 nessas rotas |
| B3 | `final_date` vazio faz o salvamento **falhar em silêncio** | `toUSDataHourFormat(null)` lança exceção (`v6/app/Http/Traits/AppTrait.php:285-296`); `upInsert` engole o `Throwable` (`v6/app/Repositories/Eloquent/Prefecture/CalendarEvent/CalendarEventRepositoryDefaultImpl.php:37-51`) | O operador vê "Ocorreu um erro!" genérico e perde o preenchimento; agravado pela mudança da v6 que tornou `final_date` `nullable` |
| B4 | Slug inexistente no portal gera erro 500 | `v6/app/Http/Controllers/Portal/CalendarEventController.php:72-74` acessa `$content->id` antes do teste `!empty($content)` | A tela "NOTÍCIA NÃO ENCONTRADA" é inalcançável |
| B5 | A view do portal usa `@getMinFile(...)`, que não é diretiva Blade registrada | `v6/resources/views/portal/layouts/calendar-events/index.blade.php`; não há `Blade::directive('getMinFile')` no projeto | URL de imagem quebrada no card da listagem |
| B6 | O botão de galeria da listagem do CMS nunca é habilitado | O JS usa `data.galery` (`v6/public/assets/js/custom/contents/agenda-eventos/datatable.js`) e a view expõe `galeria` (`v6/database/migrations/2024_11_29_093605_update_view_agenta_de_eventos.php`) | Botão "Galeria" sempre desabilitado |
| B7 | Evento sem categoria quebra o card da listagem pública | O template usa `$eventList->categoryCalendarEvents->slug` sem verificação de nulo; a v6 permite `category_calendar_events_id = null` | Erro 500 em `/agenda-eventos` se houver evento sem categoria |
| B8 | Rascunho é acessível publicamente pela URL direta | `@show` não filtra `status` |Burla da regra de publicação |
| B9 | O template `default` não possui `layout/layout.blade.php` | `v6/resources/views/portal/layouts/default/` não tem a pasta `layout/` | Se `Configuration['layout'] = 'default'`, as páginas da agenda quebram (`@extends("portal.layouts.default.layout.layout")`) |
| B10 | `@include("portal.pages.elements.video-youtube")` aponta para uma view inexistente | A view real está em `v6/resources/views/portal/components/secretarias/video-youtube.blade.php` | Include quebrado — hoje inerte porque `$content->linksUnique` não existe |
| B11 | `ajaxUploadFiles` engole exceções e não devolve resposta | `v6/app/Http/Controllers/Prefecture/CalendarEvent/CalendarEventController.php:303-383` | Upload legado sem retorno nem log de erro |
| B12 | `ajaxUploadFiles` aceita 24 extensões (incluindo `rar`, `zip`, `doc`, `mp4`) no fluxo "sem evento" | mesmo arquivo | Endpoint legado com superfície de upload ampla e sem uso |
| B13 | `CategoryCalendarEventRequest` permite `name` vazio, e o `create()` usa mass assignment do POST cru | `v6/app/Http/Controllers/Prefecture/CalendarEvent/CategoryCalendarEventController.php:79-92` | Categoria sem nome e sem slug |
| B14 | O model `CalendarEvent` declara `archives_id` no `$fillable`, coluna inexistente | `v6/app/Http/Model/Prefecture/CalendarEvent.php:20-34` | Inofensivo hoje; quebra futura |
| B15 | A listagem do CMS carrega **todos** os eventos sem paginação de servidor | `v6/app/Http/Controllers/Prefecture/DatatableController.php:153-157` | Degradação com base grande |
| B16 | Relação `CategoryCalendarEvent::contents()` referencia coluna inexistente | `v6/app/Http/Model/Prefecture/CategoryCalendarEvent.php:47-50` | Erro em runtime se usada |
| B17 | A listagem pública não tem ordenação definida | `v6/app/Http/Controllers/Portal/CalendarEventController.php:28` | Ordem dos eventos varia entre requisições |

---

## 2. Funcionalidades incompletas ou mortas

| Item | Situação |
|---|---|
| `POST /cms/ajax-upload-files-calendar-event` (`ajax.upload.files.calendar.event`) | **Sem chamador** no front atual: a galeria usa `/cms/galeria`. O método grava em `archives` com caminho `calendar-events/midias/...` |
| Rota portal `/agenda` (nome `agenda`) | Alias sem link interno no portal (o menu usa `/agenda-eventos`) |
| `CalendarEvent::agendaEventosSecretarias()` / `agendaEventosOrgaos()` | Auto-relacionamentos sem uso |
| `CalendarEvent::archiveGallery()` | Não é usada pelas views (a galeria é buscada diretamente na tabela `archives`) |
| `CategoryCalendarEvent::calendarEvents()` e `::contents()` | Relações com FK invertida, sem uso |
| `ICalendarEventRepository` | Interface vazia: não documenta o contrato |
| Método `show()` do resource de eventos | Rota gerada sem implementação |
| Bloco de vídeo (`portal.pages.elements.video-youtube`) no detalhe | Código morto (relação `linksUnique` inexistente) |
| Exclusão dos arquivos ao excluir o evento | Não existe — `archives` e os arquivos em disco ficam órfãos |

---

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

| # | Risco | Impacto | Mitigação na v7 |
|---|---|---|---|
| D1 | Tabela `archives` compartilhada com 8+ módulos via colunas FK | Migrar `calendar_events_id` para tabela própria pode quebrar outros módulos que consultam `archives` | Extrair apenas os registros com `calendar_events_id` não nulo; manter FK compatível durante a transição |
| D2 | Soft delete em eventos, mas arquivos e storage permanecem | Crescimento de storage e "fantasmas" em relatórios | Job de expurgo + política de retenção |
| D3 | Sem índice em `slug` nem em `status` | Degradação de performance conforme a base cresce | Índices em `slug`, `(status, initial_date)` |
| D4 | `slug` pode ser `NULL` e não é único | URL ambígua | Índice único parcial (`WHERE slug IS NOT NULL`) |
| D5 | Coluna `galery` com grafia incorreta e usada por SQL cru | Renomear quebra a view e o JS | Manter o nome ou renomear em migration coordenada |
| D6 | `status`/`galery` boolean sem default | Eventos antigos podem ter `NULL` (tratado como rascunho pelo portal) | `DEFAULT false` + backfill |
| D7 | `archives.calendar_events_id` sem `ON DELETE CASCADE` | Deleção física quebra a integridade | `nullOnDelete()` na v7 |
| D8 | `calendar_events.text` contém HTML do Summernote (sem sanitização) | Risco de XSS armazenado se o HTML contiver `<script>` | Sanitizar na entrada e na saída |
| D9 | A view `agenda_de_eventos` é consumida pelo dashboard e pelo CMS | Alterar a tabela sem atualizar a view quebra dois consumidores | Recriar a view por migration ao alterar colunas |
| D10 | Secretarias/órgãos apontam para `contents.id` (a tabela de conteúdo genérica) | Reorganização do conteúdo pode deixar o evento sem órgão | `nullOnDelete()` + campos desnormalizados (nome do órgão) |

---

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

1. A agenda deve mostrar **eventos passados**? Hoje sim (não há filtro de data) — é
   desejável? A resposta afeta portal, busca e dashboard.
2. Um evento pode ter **várias** secretarias/órgãos? O schema atual só aceita um de cada.
3. É aceitável um evento **sem categoria**? A v6 passou a permitir; o template público
   assume que sempre há categoria (ver B7).
4. Deve existir **calendário mensal** na agenda? O nome do módulo sugere, mas hoje há
   apenas lista paginada.
5. A exclusão em lote deve remover os arquivos e gerar aviso ao usuário?
6. O módulo deve ser **integrado ao dashboard** com o mesmo peso de outros indicadores?
   Hoje existe `EventosWidget` com a regra "todos os eventos não deletados".
7. O slug da categoria pode ser alterado depois? Isso quebraria URLs públicas já
   divulgadas.
8. É necessário **exportar** a agenda pública (PDF/ICS)? Hoje só o CMS exporta a listagem.

---

## 5. Mapa v5 -> v6

### 5.1 O que existe nos dois (sem mudança)

| Item | v5 | v6 |
|---|---|---|
| Controller CMS de eventos | `v5/app/Http/Controllers/Prefecture/CalendarEvent/CalendarEventController.php` | `v6/app/Http/Controllers/Prefecture/CalendarEvent/CalendarEventController.php` — **idêntico** |
| Controller CMS de categorias | `v5/app/Http/Controllers/Prefecture/CalendarEvent/CategoryCalendarEventController.php` | `v6/app/Http/Controllers/Prefecture/CalendarEvent/CategoryCalendarEventController.php` — **idêntico** |
| Controller do portal | `v5/app/Http/Controllers/Portal/CalendarEventController.php` | `v6/app/Http/Controllers/Portal/CalendarEventController.php` — **idêntico** |
| Models `CalendarEvent` e `CategoryCalendarEvent` | `v5/app/Http/Model/Prefecture/…` | `v6/app/Http/Model/Prefecture/…` — **idênticos** |
| Repository (contrato e implementação) | `v5/app/Repositories/…/CalendarEvent/…` | `v6/app/Repositories/…/CalendarEvent/…` —contrato idêntico; implementação com ajuste de categoria |
| Views do portal (`calendar-events/index`, `calendar-events/show`) | `v5/resources/views/portal/layouts/calendar-events/` | idênticas |
| Views do CMS (`index`, `create`, `edit`, `category-calendar-events/*`) | `v5/resources/views/prefecture/…` | idênticas (exceto `calendar-events/form.blade.php`) |
| Migrations (5 arquivos do módulo) | `v5/database/migrations/…` | `v6/database/migrations/…` — mesmas datas e nomes |
| Rotas CMS | `v5/routes/basepro.php:114,145,183,184,200,429` | `v6/routes/basepro.php:124,156,202,203,228,418` — mesmas rotas |
| Rotas do portal | `v5/routes/web.php:36-38` | `v6/routes/web.php:27-29` — mesmas rotas + uma nova |

### 5.2 Diferenças: v5 -> v6

| # | Mudança | Onde | Efeito |
|---|---|---|---|
| V1 | **Nova rota** `GET /agenda` (nome `agenda`) | `v6/routes/web.php:26` | Alias público da agenda; inexistente na v5 |
| V2 | `final_date` deixa de ser `required` | `v6/app/Http/Requests/CalendarEventRequest.php` | Permite eventos sem data de encerramento (com o efeito colateral B3) |
| V3 | `name` da categoria deixa de ser `required` | `v6/app/Http/Requests/CategoryCalendarEventRequest.php` | Permite categoria sem nome (B13) |
| V4 | `SelectRule` passa a receber o rótulo do campo | `v6/app/Http/Requests/CalendarEventRequest.php` | Mensagem "O campo Categoria é obrigatório" |
| V5 | `category_calendar_events_id == 0` é normalizado para `null` | `v6/app/Repositories/Eloquent/Prefecture/CalendarEvent/CalendarEventRepositoryDefaultImpl.php:26-30` | Permite eventos sem categoria (com o efeito B7) |
| V6 | Formulário do CMS: "Secretaria" deixa de ser obrigatória; select de categoria com `size => 2`; wrapper com `p-0` | `v6/resources/views/prefecture/calendar-events/form.blade.php` | Ajuste visual |
| V7 | **Dashboard**: novo `EventosWidget` + teste de regressão | `v6/app/Services/Dashboard/Widgets/EventosWidget.php`, `v6/tests/Feature/DashboardEventosWidgetTest.php` | O módulo passa a ser indicador do painel do CMS |
| V8 | View SQL `agenda_de_eventos` versionada por migrations e com a coluna `slug` | `v6/database/migrations/2023_04_06_143633_create_view_to_agenda_de_eventos.php`, `…/2023_05_25_095627_update_eventos_view_date_hour.php`, `…/2024_11_29_093605_update_view_agenta_de_eventos.php` | Habilita o botão "Acessar Evento" na listagem |
| V9 | Registro em `modulos` (`agenda-de-eventos`, id 39) e `resources`/`menu_orders` ligados a ele | `v6/database/seeds/ResourcesTableSeeder.php:468`, `v6/database/seeds/MenuOrderSeeder.php:33` | Consolida a navegação do CMS |
| V10 | Item de menu do portal "Agenda" ligado à categoria de conteúdo `agenda-eventos` | `v6/database/seeds/MenuItemsTableSeeder.php:173`, `v6/database/seeds/CategoryContentTableSeeder.php:222` | Publica a agenda no menu do site |

### 5.3 Removido na v6

Nada do módulo foi removido: todas as rotas, métodos, models, views e migrations da v5
existem na v6. As únicas ausências são **funcionalidades que nunca existiram** na v5
(o método `show`, a diretiva `getMinFile`, a view `portal.pages.elements.video-youtube`),
mantidas como dívida histórica.

---

## 6. Resumo para o planejamento da v7

| Prioridade | Item |
|---|---|
| P0 | Corrigir B3 (falha silenciosa ao salvar), B4 (500 em slug inexistente), B7 (evento sem categoria) |
| P1 | Implementar `show()` (B1), padronizar `galery`/`galeria` (B6), substituir a view SQL por query Eloquent (B15), definir ordenação (B17) |
| P2 | Extrair a mídia da agenda para tabela própria (D1), criar índices (D3/D4), expurgar órfãos (D2), sanitizar o HTML (D8) |
| P3 | Remover o código morto (`ajax-upload-files-calendar-event`, relações invertidas, interface vazia) e unificar os cinco templates do portal (B9) |
