# Destaques — Rotas e Controllers

## 1. Rotas do CMS (`/cms`)

Todas em `v6/routes/basepro.php`, dentro do grupo do CMS (prefixo `/cms`, middleware de
autenticação `check.logged` e demais middlewares do grupo).

| Método | URI (relativa) | Nome (`->name()`) | Controller@ação | Linha |
|---|---|---|---|---|
| GET | `destaques` | `destaques.index` | `Prefecture\HighlightController@index` | `v6/routes/basepro.php:392` |
| GET | `destaques/create` | `destaques.create` | `Prefecture\HighlightController@create` | `v6/routes/basepro.php:392` |
| POST | `destaques` | `destaques.store` | `Prefecture\HighlightController@store` | `v6/routes/basepro.php:392` |
| GET | `destaques/{id}/edit` | `destaques.edit` | `Prefecture\HighlightController@edit` | `v6/routes/basepro.php:392` |
| PUT | `destaques/{id}` | `destaques.update` | `Prefecture\HighlightController@update` | `v6/routes/basepro.php:392` |
| DELETE | `destaques/{id}` | `destaques.destroy` | `Prefecture\HighlightController@destroy` | `v6/routes/basepro.php:392` |
| ANY | `destaques/{id}/status` | `destaques.status` | `Prefecture\HighlightController@toggleStatus` | `v6/routes/basepro.php:393` |
| GET | `datatable/highlight` | `highlight` | `Prefecture\DatatableController@get_highlight` | `v6/routes/basepro.php:403` |

As sete primeiras rotas são geradas por `Route::resource`:

```php
// v6/routes/basepro.php:392-393
Route::resource('destaques', 'Prefecture\HighlightController');
Route::any('/destaques/{id}/status', 'Prefecture\HighlightController@toggleStatus')->name('destaques.status');
```

### Consequências do `Route::resource` + rota `any` sobre `/destaques/{id}/status`

A rota `Route::any('/destaques/{id}/status', ...)` é registrada **depois** do resource.
Como o resource já define `destaques/{id}` (PUT/PATCH/DELETE), não há colisão de
método; porém a rota `any` aceita GET, POST, PUT, DELETE… e o `{id}` não tem restrição
de tipo, de modo que `/cms/destaques/abc/status` chega ao controller.

## 2. Rotas do Portal

O módulo **não** possui rotas próprias no portal. Os destaques são carregados como
parte da home:

| Método | URI | Nome | Controller@ação | Arquivo |
|---|---|---|---|---|
| GET | `/` | `home` | `Portal\PortalController@index` | `v6/routes/web.php:8` |

Todo o grupo do portal está sob o middleware `check.site.manutention`
(`v6/routes/web.php:7`).

## 3. Controller — métodos

| Método | Arquivo:linha | Comportamento |
|---|---|---|
| `index` | `v6/app/Http/Controllers/Prefecture/HighlightController.php:15` | Devolve a view `prefecture.highlight.index` |
| `create` | `…/HighlightController.php:21` | Calcula a primeira `position` livre e devolve `prefecture.highlight.create` |
| `store` | `…/HighlightController.php:31` | Rebalanceia posições, cria o destaque, salva a imagem e o `Archive` |
| `edit` | `…/HighlightController.php:58` | Carrega destaque + `Archive` e devolve `prefecture.highlight.edit` |
| `update` | `…/HighlightController.php:66` | Rebalanceia posições, atualiza, substitui a imagem e o `Archive` |
| `destroy` | `…/HighlightController.php:117` | `Highlight::destroy($id)` e devolve JSON |
| `toggleStatus` | `…/HighlightController.php:127` | Alterna `status` entre `true` e `null` |

Trecho do cálculo da próxima posição livre:

```php
// v6/app/Http/Controllers/Prefecture/HighlightController.php:21-29
public function create()
{
    $usedPositions = Highlight::pluck('position')->toArray();

    $position = 1;
    while (in_array($position, $usedPositions)) {
        $position++;
    }

    return view('prefecture.highlight.create', compact('position'));
}
```

Trecho do `toggleStatus`:

```php
// v6/app/Http/Controllers/Prefecture/HighlightController.php:127-138
public function toggleStatus($id) {
    try {
        $destaque = Highlight::findOrFail($id);
        $destaque->update([
            'status' => $destaque->status == 1 ? null : true
        ]);
        return response()->json(['success' => 'O destaque foi desativado com sucesso.'], 200);
    } catch (\Throwable $th) {
        return response()->json(['success' => 'Não foi possível desativar o destaque. Por favor, tente novamente.'], 500);
    }
}
```

Observações:

- A mensagem de sucesso é fixa ("O destaque foi desativado com sucesso.") mesmo quando a
  operação **ativa** o destaque — inconsistência de UX.
- `destroy` **não** apaga o arquivo físico em `storage/highlights/<id>/`; apenas o
  registro `archives` (por cascade) e o model `highlights`.

## 4. Form Request / validação

Arquivo: `v6/app/Http/Requests/HighlightRequest.php`

| Campo | Regra | Observação |
|---|---|---|
| `title` | `required|max:255` | A UI limita a 150 caracteres (`maxlen => 150` no Blade) |
| `subtitle` | `required|max:999` | `text` no banco |
| `text_button` | `required|max:255` | |
| `url` | `required|max:2999` | URL livre (não validada como URL) |
| `archive_highlight` | `image|max:20000|mimes:jpg,jpeg,png,gif,webp` | Não é `required` no request (apesar de a mensagem existir) |
| `position` | `required||integer` | O `||` é redundante (equivalente a `|`) |

Mensagens customizadas relevantes:

```php
'archive_highlight.image' => "O arquivo selecionado para destaque deve ser uma imagem válida.",
'archive_highlight.max'    => "Por favor, selecione uma imagem com tamanho menor que 20MB.",
'position.required'        => 'Por favor, informe um título.',   // mensagem copiada/errada
```

`authorize()` retorna `true` — **não há** verificação de papel/guard dentro do Form
Request. A autorização real é feita por `has_access()` na camada de views.

## 5. Permissões

| Recurso | Slug | Origem |
|---|---|---|
| Módulo | `destaques` | `resources.slug = 'destaques'` (id 75, `modulo_id = 55`) |
| Item de menu | `destaques` | `menu_orders.slug = 'destaques'` (id 43, `modulo_id = 55`) |

Verificações feitas na interface:

- `has_access(['destaques.create'])` — botão "Cadastrar Destaque"
  (`v6/resources/views/prefecture/highlight/index.blade.php`)
- `has_access(['destaques.delete'])` — exclusão em lote e checkbox master
- `has_access("$permission.edit")`, `has_access("$permission.delete")`,
  `has_access("$permission.restore")`, `has_access("$permission.inactivate")` — injetados
  linha a linha em `DatatableController::struct_views`

> O item de menu "Destaques" **não aparece** no AdminLTE porque o `MenuServiceProvider`
> exige `isset($menu->modulo->status) && $menu->modulo->status`, e `modulos.status` é
> `0` para o módulo. O acesso direto por URL continua funcionando (as rotas existem).

## 6. Datatable

Fonte: `v6/app/Http/Controllers/Prefecture/DatatableController.php:56-60`

```php
public function get_highlight()
{
    $destaques = DB::table('highlight')->get();
    return DataTables::of($this->struct_views($destaques, 'destaques'))->make(true);
}
```

**Bug:** a tabela real é `highlights` (plural). `DB::table()` não usa SoftDeletes e o
PostgreSQL lançará `relation "highlight" does not exist`. O grid do CMS fica quebrado.

## 7. Recursos de API

Não há `ApiResource` nem endpoint JSON para destaques. A resposta de `toggleStatus` e
`destroy` é um JSON simples:

```json
{"success": "O destaque foi desativado com sucesso."}
```

## 8. Logs de auditoria

O controller de destaques **não** registra `activity()` (diferente de
`CategoryContentController` e `ContentController`, que registram). A rastreabilidade
depende apenas do log de acesso do Laravel.
