# Avisos — Regras e Portabilidade

> Regras não óbvias, acoplamentos e armadilhas observadas no código da `v6`.

---

## 1. Regras de negócio não óbvias

| # | Regra | Onde está | Efeito observável |
|---|---|---|---|
| R1 | **Só existe um aviso ativo.** Ativar um aviso desativa todos os outros da categoria | `v6/app/Http/Controllers/Prefecture/ContentController.php:672-674`, `:994-996`, `:1565-1567` | O portal mostra um único comunicado |
| R2 | O portal exibe `first()` da categoria `anuncios` com `status = 1` | `v6/app/Http/Controllers/Portal/PortalController.php:155-159` | A ordem exibida é a do banco (sem `orderBy`) |
| R3 | O aviso **precisa de imagem** no momento da criação | `v6/app/Http/Requests/ContentRequest.php:174-176` | `archive_highlight` é `required` apenas em `conteudo.store` |
| R4 | O destino é obrigatório e fica na tabela `links` | `ContentController.php:717-728` e `:1062-1100` | `links.isBlank` controla "abrir em nova guia" |
| R5 | A imagem é recomprimida para **700x405** na criação e **largura 700** na edição | `ContentController.php:851-857` e `:1266-1272` | Tamanho padronizado do comunicado |
| R6 | GIF não é recomprimido | `if ($size && $ext !== 'gif')` | Preserva animação |
| R7 | O módulo do CMS chama-se **"Avisos"** (`modulos.slug = 'avisos'`), mas a categoria chama-se **"Anúncios"** (`category_contents.slug = 'anuncios'`) | migration `2024_11_01_150206_create_modulos_table.php:178-183` vs `CategoryContentTableSeeder.php:161-166` | Duas identidades para a mesma feature |
| R8 | As permissões usam o slug da **categoria** (`anuncios.*`), não o do módulo (`avisos`) | `ResourcesTableSeeder.php:252-258`, `DatatableController.php:231` | `has_access(['anuncios.create'])` |
| R9 | A exibição depende do status do **módulo** `avisos` em alguns layouts | `v6/resources/views/portal/layouts/modelo1/home/aviso.blade.php:1` e `v6/app/Providers/ModulosServiceProvider.php:22-50` | Desabilitar o módulo esconde o aviso (apenas nos layouts que verificam) |
| R10 | A listagem do CMS usa a view SQL `anuncios` (com `status_name` calculado) | `DatatableController.php:230` | O rótulo "Ativado/Desativado" vem do SQL |
| R11 | O aviso não tem data de validade nem expiração | formulário `anuncios/form.blade.php` | Um aviso ativo permanece no ar até ser desativado |

## 2. Acoplamentos

| Depende de | Onde | Natureza |
|---|---|---|
| `Portal\PortalController@index` | exibição | O aviso é "empurrado" pela home; não há tela própria |
| Tabela `links` | destino | `Content.linksUnique()` |
| Tabela `archives` | imagem | `Content.archives()` com `highlight = 1` |
| `modulos` (status do módulo "Avisos") | view composer | Cache "para sempre" |
| `configurations.key = 'layout'` | escolha do layout (`getTemplateActived`) | Define o HTML do modal |
| `ContentController` (CRUD genérico) | CMS | Sem controller próprio |
| View SQL `anuncios` | DataTable do CMS | Dependência de banco |
| `FileTrait::compress` | recompressão da imagem | `Intervention\Image` |

## 3. Armadilhas

| Armadilha | Evidência | Impacto |
|---|---|---|
| Nomenclatura divergente (`avisos` x `anuncios`) | `modulos` vs `category_contents` | Confusão em rotas, permissões, seeds e views; risco de erro em código novo |
| `->path` em `null` | `$anuncio->archives->where('highlight',1)->first()->path` | Aviso ativo sem imagem causa erro 500 na home |
| Exclusividade só na aplicação | sem índice/constraint | Importação de dados ou SQL manual pode deixar dois avisos ativos; o portal mostra só um |
| `update` não exige imagem | regra só no `conteudo.store` | Dá para editar o título sem reenviar a imagem (comportamento desejado, mas não documentado) |
| `maxlen` do link (200) x validação (2999) | `anuncios/form.blade.php:29` vs `ContentRequest.php:172` | Divergência entre cliente e servidor |
| `Cache::rememberForever('modulos')` | `v6/app/Providers/ModulosServiceProvider.php:22` | Alterar o status do módulo exige limpar o cache |
| `catch (\Throwable $th) {}` no `contentList` | `PortalController.php:367` | Erros engolidos com HTTP 200 |
| HTML do modal duplicado em 7 arquivos | `home/aviso.blade.php` (modelo1/3/4), `home/index.blade.php` (modelo5/6), `pages/index.blade.php` (default) | Correção precisa ser replicada; já há divergência (Bootstrap 4 x 5, ids `anuncio` x `modalAviso`) |
| Layout `modelo2` inclui a view do `modelo1` | `v6/resources/views/portal/layouts/modelo2/home/index.blade.php:16` | Acoplamento entre layouts |
| `createActiveButton` com `alt_url = '/cms/set-status'` | `v6/public/assets/js/custom/utilities/table.js:373-393` | URL absoluta (quebra se o CMS mudar de prefixo) |
| `->geT()` | `DatatableController.php:230` | Estilo inconsistente (funciona por case-insensitivity) |
| Aviso não indexável | slugs de busca não incluem `anuncios` | O comunicado não aparece na busca do portal |

## 4. Código duplicado entre v5 e v6

| Arquivo | v5 | v6 | Diferença |
|---|---|---|---|
| `Prefecture/DatatableController::get_avisos` | presente | presente | Idêntico |
| Migration da view `anuncios` | `v5/database/migrations/2023_04_10_152724_create_view_to_anuncios.php` | `v6/database/migrations/2023_04_10_152724_create_view_to_anuncios.php` | Mesmo SQL |
| JS `assets/js/custom/contents/avisos/datatable.js` | presente | presente | Idêntico |
| Views do CMS `prefecture/contents/anuncios/*` | presentes | presentes | Equivalentes |
| `home/aviso.blade.php` | **não existia** (HTML inline na home) | `v6/resources/views/portal/layouts/modelo1/home/aviso.blade.php` (idem modelo3/modelo4) | Parcial nova na v6 |
| Registry `modulos` / `resources` | inexistente | criado (id 26) | Novo na v6 |

## 5. Onde a v6 divergiu da v5 (visível nos avisos)

| Aspecto | v5 | v6 |
|---|---|---|
| Bloco do modal | HTML **inline** em `home/index.blade.php` de cada modelo (não havia `aviso.blade.php`) | parcial extraída: `home/aviso.blade.php` em modelo1, modelo3 e modelo4; modelo2 inclui a do modelo1; modelo5, modelo6 e default seguem inline |
| Módulo no CMS | menu por categoria | menu por módulo (`avisos`, id 26) |
| Permissões | por conteúdo | recurso `anuncios` (modulo 26) |
| Exclusividade (um aviso ativo) | já existia | idem |
| View SQL `anuncios` | mesma SQL | idem |

Não há mudança de comportamento observável no módulo entre v5 e v6; a v6 **extraiu
parciais** do modal (reduzindo a duplicação em modelo1/3/4) e adicionou a camada de
registry de módulos.

## 6. Pontos de atenção para a v7

1. Criar tabela própria `announcements` (ou `avisos`) com `title`, `url`, `image_path`,
   `open_in_new_tab`, `active`, `starts_at`, `ends_at`.
2. Garantir a exclusividade **no banco** (índice único parcial em `active` ou trigger),
   além do código.
3. Unificar o HTML do modal em um componente Blade (hoje há 7 cópias).
4. Tornar a checagem de módulo uniforme entre layouts (hoje só 3 layouts verificam).
5. Evitar `->path` em `null`: usar `?->` e um placeholder quando faltar a imagem.
6. Criar uma página pública de avisos (arquivo) ou uma API — hoje o comunicado
   desaparece quando o modal é fechado.
7. Padronizar `maxlen` do link entre formulário e validação.

## 7. Checklist de portabilidade

| Item | Estado na v6 | Situação na v7 (decisão) |
|---|---|---|
| Slug técnico | `anuncios` (categoria) e `avisos` (módulo) | Unificar em `avisos` **apenas** na UI; preservar `anuncios` em permissões e seeds |
| Nome exibido ao operador | "Avisos" (menu e título da lista) | Manter "Avisos" |
| Exibição no portal | modal na home, sem rota própria | Componente único + (opcional) página `/avisos` |
| Quantidade de avisos ativos | 1 (garantido no código) | 1 (garantido no banco, com índice único parcial) |
| Imagem | `archives.highlight = 1` + `path` | Coluna `image_path` na tabela própria |
| Destino | tabela `links` (`link`, `isBlank`) | Colunas `url` e `open_in_new_tab` |
| Status | `contents.status` boolean | Coluna `active` boolean (+ `starts_at`/`ends_at` opcionais) |
| Listagem do CMS | view SQL `anuncios` | Consulta Eloquent paginada |
| Botão liga/desliga | `POST /cms/set-status` genérico | `POST /api/v1/avisos/{id}/ativar` (dedicado) |
| Tamanho da imagem | 700x405 (criação) / largura 700 (edição) | 700x405 nos dois casos |
| Controle por módulo | `$modulos['avisos']` (parcial) | Verificação única no componente |

## 8. Regras que NÃO podem mudar (equivalência funcional)

1. O aviso continua sendo **uma imagem + um link + um título**, sem texto corrido no portal.
2. No máximo **um aviso ativo** por vez.
3. O aviso continua abrindo **automaticamente** ao carregar a home.
4. A imagem continua sendo o elemento clicável do modal.
5. A opção "Abrir em nova guia" continua produzindo `target="_blank"`.
6. A imagem continua sendo recomprimida para 700x405 e mantida em `storage/public`.
7. A edição pelo CMS continua exigindo permissão do módulo (`anuncios.*`).
8. A listagem do CMS continua exibindo o estado ("Ativado"/"Desativado") por linha.
