# Avisos — Arquitetura

> Versão analisada: `v6` (equivalente em `v5`). Módulo CMS: `avisos` (`modulos`, id 26)
> | Categoria de conteúdo: `category_contents.id = 28` (slug `anuncios`).

---

## 1. Visão geral

O módulo é um "cartão de aviso" (banner de comunicado) exibido em modal na home do
portal. Não existe página pública de listagem: o módulo tem **um único ponto de
exibição** — a home — e **no máximo um aviso ativo**.

| Fluxo | Entrada | Saída | Quem consome |
|---|---|---|---|
| Portal (público) | `GET /` (home) | HTML com modal `#anuncio` | Cidadão |
| CMS (admin) | `/cms/conteudos/anuncios`, resource `conteudo`, `POST /cms/set-status` | HTML + DataTable JSON | Operador |

## 2. Fluxo da requisição — Portal (home)

```
Cidadão
  │ GET /
  ▼
Portal\PortalController@index                        v6/app/Http/Controllers/Portal/PortalController.php
  │ $anuncio = Content::with('categoryContents','archives','linksUnique')
  │      ->whereHas('categoryContents', fn($q) => $q->where('slug','anuncios'))
  │      ->where('status', 1)->first();
  ▼
view('portal.layouts.{template}.home.index', compact('slidesNews', 'contents', 'anuncio', 'highlights'))   (linha 220+)
  ▼
Layout desenha o modal
  │  <button id="btn-anuncio" data-toggle="modal" data-target="#anuncio">
  │  <div class="modal" id="anuncio"><a href="{{$anuncio->linksUnique->link}}">
  │      <img src="{{url($anuncio->archives->where('highlight',1)->first()->path)}}">
  ▼
scripts do layout: $('#btn-anuncio').click();   → modal abre sozinho
```

## 3. Fluxo da requisição — CMS

```
Operador
  │ GET /cms/conteudos/anuncios
  ▼
Route::get('conteudos/{slug}') → ContentController@genericIndex      v6/routes/basepro.php:235
  │ if ($slug === 'anuncios') return $this->returnIndex('Avisos', $slug);
  ▼
view('prefecture.contents.anuncios.index')  + DataTable
  │ GET /cms/datatable/anuncios
  ▼
DatatableController@get_avisos                                       v6/app/Http/Controllers/Prefecture/DatatableController.php:228-232
  │ DB::table("anuncios")->get()   ← view SQL (value, titulo, status_name, id, status)
  │ struct_views($dados, 'anuncios') → flags de permissão
  ▼
JSON server-side
```

Cadastro/ativação:

```
POST /cms/conteudo                       (Route::resource('conteudo'))     v6/routes/basepro.php:174
PUT  /cms/conteudo/{id}
  ▼
ContentController@store / @update
  │ ContentRequest (case 'anuncios'): title, category_contents_id, link, archive_highlight
  │ se $slug === 'anuncios' && $request->get('status') == 1:
  │     Content::where('category_contents_id', $id)->where('status', true)->update(['status' => false]);
  │ grava Content, Link (link + isBlank) e Archive de destaque (highlight = 1)
  │ recomprime a imagem para 700x405 (compress com $slug == 'anuncios')
  ▼
contents + links + archives

POST /cms/set-status  → ContentController@setStatus   (toggle; desativa os irmãos ao ativar)
```

## 4. Classes envolvidas

| Classe | Caminho | Papel |
|---|---|---|
| `Portal\PortalController` | `v6/app/Http/Controllers/Portal/PortalController.php` | `index()` monta `$anuncio` (linhas 155-159) e passa ao layout |
| `Prefecture\ContentController` | `v6/app/Http/Controllers/Prefecture/ContentController.php` | CRUD genérico; `genericIndex` (linha 95: "Avisos"), `genericGenerate` (linha 167), `setStatus` (linhas ~1545-1590) |
| `Prefecture\DatatableController` | `v6/app/Http/Controllers/Prefecture/DatatableController.php` | `get_avisos` (linhas 228-232) |
| `App\Http\Requests\ContentRequest` | `v6/app/Http/Requests/ContentRequest.php` | `case 'anuncios'` (linhas 167-179) |
| `App\Prefecture\Content` | `v6/app/Http/Model/Prefecture/Content.php` | `archives()`, `linksUnique()`, `categoryContents()` |
| `App\Prefecture\Archive` | `v6/app/Http/Model/Prefecture/Archive.php` | Arquivos do conteúdo (`highlight = 1` é a imagem do aviso) |
| `App\Prefecture\Link` | `v6/app/Http/Model/Prefecture/Link.php` | Link único do conteúdo (`link`, `isBlank`) |
| `App\Providers\MenuServiceProvider` | `v6/app/Providers/MenuServiceProvider.php:249-251` | Item de menu do CMS "Avisos" |
| `App\Http\Traits\FileTrait` | `v6/app/Http/Traits/FileTrait.php` | `compress()` (recompressão da imagem) usada no módulo |

## 5. Dependências externas

| Pacote | Uso |
|---|---|
| `intervention/image` | `compress()` para redimensionar/comprimir a imagem do aviso (700x405) |
| `yajra/laravel-datatables-oracle` | DataTable server-side do CMS |
| `jquery` + `bootstrap` (modal) | Abertura automática do modal na home |
| `laravelcollective/html` | `Form::open` / `Form::model` no CMS |
| `cartalyst/sentinel` | `has_access(['anuncios.*'])` e log de atividade |

## 6. Diagrama de dependências (Mermaid)

```mermaid
graph TD
  R1["web.php: GET / (home)"] --> PC[PortalController@index]
  PC --> C[App\Prefecture\Content]
  PC --> A[App\Prefecture\Archive]
  PC --> L[App\Prefecture\Link]
  R2["basepro.php: /cms/conteudos/anuncios"] --> CTC[ContentController]
  CTC --> CR[ContentRequest]
  CTC --> C
  CTC --> L
  CTC --> A
  R3["basepro.php: /cms/datatable/anuncios"] --> DTC[DatatableController]
  DTC --> V[(view SQL anuncios)]
  R4["basepro.php: POST /cms/set-status"] --> CTC
  C --> T[(contents)]
  A --> T2[(archives)]
  L --> T3[(links)]
  V --> T
```

## 7. Observações de arquitetura

- O módulo **não tem model, view de portal ou rota pública própria**: ele reaproveita
  `contents` + `links` + `archives` e um bloco de modal copiado em cada layout.
- O "nome do recurso" (`avisos` no `modulos`) e o "nome da categoria" (`anuncios`) divergem:
  as permissões, o menu e a view SQL usam `anuncios`, enquanto o registro do módulo usa
  `avisos`.
- A exclusividade de um aviso ativo é garantida **apenas na aplicação** (três pontos do
  `ContentController`), sem restrição no banco.
- O modal é exibido na home de **todos** os layouts, mas a view varia: `modelo1`,
  `modelo3` e `modelo4` têm `home/aviso.blade.php`; `modelo2` inclui a do `modelo1`;
  `modelo5`, `modelo6` e `default` trazem o HTML inline na `home/index`.
