# Transmissões — Arquitetura

> Versão analisada: `v6`. O módulo é **novo na v6** (inexistente na v5).

## 1. Visão geral da arquitetura

O módulo não possui controller, model, tabela nem rota pública próprios. Ele é
construído sobre três mecanismos genéricos da plataforma:

| Mecanismo | Papel no módulo |
|---|---|
| **Conteúdo genérico** (`contents` + `category_contents` + `links`) | Armazenamento da transmissão (título, status, link do vídeo). |
| **CRUD genérico por slug** (`Prefecture\ContentController`) | Telas do CMS, validação e persistência, com ganchos por slug. |
| **Widget de layout Blade** | Exibição do player no portal, inline em cada tema. |

O único elemento exclusivo do módulo é a **view SQL `transmissoes`**, criada
para servir o DataTable do CMS sem precisar de um `Eloquent\Builder` com
relações.

## 2. Camadas envolvidas

### 2.1 CMS — leitura da listagem

```
Rota GET /cms/datatable/transmissoes
  -> Route::group(['prefix' => 'datatable', 'as' => 'datatable.'])   v6/routes/basepro.php:396-402
  -> middleware check.logged (grupo /cms)
  -> Prefecture\DatatableController@get_transmissoes                v6/app/Http/Controllers/Prefecture/DatatableController.php:51-55
  -> DB::table('transmissoes')->get()                                 (view SQL)
  -> struct_views($data, 'transmissoes')                              v6/app/Http/Controllers/Prefecture/DatatableController.php:504-519
       -> has_access('transmissoes.edit' / .delete / .restore / .inactivate')
  -> Yajra DataTables::of(...)->make(true)
  -> JS v6/public/assets/js/custom/contents/transmissoes/datatables.js
```

### 2.2 CMS — criação/edição

```
Rota GET /cms/conteudos/cadastrar/transmissoes  (cadastrar-conteudo)
  -> Prefecture\ContentController@genericCreate -> genericGenerate
  -> returnData('Transmissões', 'transmissoes', null, ['categoryContent' => ...], $id)
  -> view prefecture.contents.transmissoes.create -> form.blade.php

Rota POST /cms/conteudo (conteudo.store)
  -> Prefecture\ContentController@store(ContentRequest)
  -> ContentRequest::rules() case 'transmissoes'                    v6/app/Http/Requests/ContentRequest.php:139-147
  -> Content::create($contentData)                                   (contents)
  -> exclusividade: Content::where('category_contents_id', ...)->where('status', true)->update(['status' => false])
  -> Link::create([...]) com normalizeVideoLink() + sanitizeLink()     v6/app/Http/Controllers/Prefecture/ContentController.php:715-728
  -> activity()->...->log('Cadastro de link')
```

### 2.3 Portal — exibição

```
Qualquer rota do grupo Route::middleware(['check.site.manutention'])  v6/routes/web.php:8
  -> controller do portal -> view do tema (modelo1..modelo6)
  -> @include('portal.layouts.<tema>...transmissao')  ou banners.blade.php
  -> @if (isset($modulos['transmissoes']) && $modulos['transmissoes'])
  -> @inject('content', 'App\Prefecture\Content')
  -> Content::whereHas('categoryContents', slug='transmissoes')->where('status', true)->first()
  -> parser de URL inline (PHP dentro do Blade)
  -> <iframe src="https://www.youtube.com/embed/<id>">
```

## 3. Diagrama ASCII do fluxo

```
   OPERADOR (CMS)                                  CIDADÃO (PORTAL)
        |                                                  |
        v                                                  v
  /cms/conteudos/transmissoes                     qualquer pagina do portal
        |  (listar-conteudo)                                |
        v                                                  v
  ContentController@genericIndex                 ModulosServiceProvider
        |  menuClicks('transmissoes')               (injeta $modulos)
        v                                                  |
  view prefecture.contents.transmissoes.index              v
        |                                          <x sidebar/banners >
        |                                                  |
        |  DataTables ajax                                |  @if $modulos['transmissoes']
        v                                                  v
  GET /cms/datatable/transmissoes            Content::whereHas(categoryContents
        |                                     slug='transmissoes')
        v                                     ->where('status', true)->first()
  DatatableController@get_transmissoes                |
        |                                                v
        v                                      $transmissao->linksUnique->link
  DB::table('transmissoes')  (view SQL)                |
        |                                     parse_url + explode('/')
        v                                                |
  struct_views() -> flags edit/delete/active            v
        |                                     host ~ youtube ? embed/<id> : url
        v                                                |
  JSON DataTables                                      v
   createActiveButton -> POST /cms/transmissoes/{id}/status
        |                                     <iframe class="embed-responsive-item">
        v
  ContentController@setStatus
```

## 4. Classes envolvidas

| Classe | Caminho | Papel |
|---|---|---|
| `Prefecture\ContentController` | `v6/app/Http/Controllers/Prefecture/ContentController.php` | CRUD genérico; ganchos por slug `transmissoes` nas linhas 110, 256-260, 678-680, 1000-1002, 1571-1573. |
| `Prefecture\DatatableController` | `v6/app/Http/Controllers/Prefecture/DatatableController.php` | `get_transmissoes()` (linhas 51-55) e `struct_views()` (linhas 504-519). |
| `Prefecture\ContentRequest` | `v6/app/Http/Requests/ContentRequest.php` | Regras de validação por slug (case `transmissoes`, linhas 139-147). |
| `App\Prefecture\Content` | `v6/app/Http/Model/Prefecture/Content.php` | Model de `contents`; relações `categoryContents()`, `linksUnique()`. |
| `App\Prefecture\CategoryContent` | `v6/app/Http/Model/Prefecture/CategoryContent.php` | Model de `category_contents`. |
| `App\Prefecture\Link` | `v6/app/Http/Model/Prefecture/Link.php` | Model de `links` (guarda o link do vídeo). |
| `Admin\ModulosController` | `v6/app/Http/Controllers/Admin/ModulosController.php` | Liga/desliga o módulo (`/cms/modulos`). |
| `Admin\Modulos` | `v6/app/Http/Model/Admin/Modulos.php` | Model da tabela `modulos`. |
| `ModulosServiceProvider` | `v6/app/Providers/ModulosServiceProvider.php` | Cachea `modulos` e compartilha `$modulos` com as views de sidebar. |
| `MenuServiceProvider` | `v6/app/Providers/MenuServiceProvider.php` | Cria o item de menu "Transmissões" (linhas 64-66). |
| `App\Http\Middleware\CheckRoutePermission` | `v6/app/Http/Middleware/CheckRoutePermission.php` | Autorização de rota por permissão. |

## 5. Dependências externas

| Pacote | Uso |
|---|---|
| `laracasts/presentable` (`PresentableTrait`) | `Content`, `CategoryContent` e `Link` usam `ContentPresenter`/`CategoryContentPresenter`. |
| `yajra/laravel-datatables-oracle` | `DataTables::of(...)->make(true)` no `DatatableController`. |
| `cartalyst/sentinel` | `Sentinel::getUser()`, `has_access()` e `Sentinel::inRole('super-admin')`. |
| `spatie/laravel-activitylog` (`activity()`) | Trilha de auditoria ao criar o `Link`. |
| `laravel/framework` 5.5.50 / PHP 7.2.34 | Base. |

## 6. Onde a lógica realmente mora

Não há serviço, repositório ou middleware dedicado. Resumo por Responsabilidade:

| Responsabilidade | Onde está | Tipo de acoplamento |
|---|---|---|
| Listagem no CMS | View SQL `transmissoes` | SQL puro |
| Regras de validação | `ContentRequest` (switch por slug) | Acoplado ao slug |
| Exclusividade de status ativo | `ContentController` (3 pontos) | Acoplado ao slug |
| Desenho do player e parsing de URL | Blade (6 arquivos) | Lógica em apresentação |
| Consulta do conteúdo ativo | Blade (`@inject` + Eloquent) | Consulta em view |
| Flag do módulo | `modulos.status` + `ModulosServiceProvider` | Cache `rememberForever` |

## 7. Diagrama de dependências entre módulos

```
       [modulos]  (flag global do sistema)
            |
            v
   [widgets de layout do portal]  <-- consumidos por todos os módulos do portal
            |
            v
   [contents / category_contents]  <-- infraestrutura genérica de conteúdo
            |
            v
        [links]  (link do vídeo)
```

O módulo **não depende** de `sessoes`, `tv-camara` nem `vereadores`: a
transmissão é apenas um vídeo apontado por URL, sem vínculo com a ata, a pauta
ou a sessão. Também **não depende** do módulo `banners`, embora em 4 temas o
widget conviva com os banners no mesmo arquivo Blade
(`modelo3/layout/sidebar/banners.blade.php` etc.).
