# Glossário — Rotas e Controladores

> Separação: **Portal** = `v6/routes/web.php` (público) | **CMS** = `v6/routes/basepro.php`
> (prefixo `/cms`) | **API** = `v6/routes/api.php` (não há endpoint de glossário na API v1).

---

## 1. Rotas do Portal

| Método | URI | Nome | Controller@ação | Middleware |
|---|---|---|---|---|
| GET | `/glossario` | `glossario.index` | `Portal\GlossaryController@index` | grupo do portal (`check.site.manutention`) |
| ANY | `/glossario-ajax/{slug}` | `glossario.show` | `Portal\GlossaryController@showByLetterAjax` | idem |
| ANY | `/portal/glossario` | `conteudo.portal.list` | `Portal\PortalController@contentList` | idem |
| ANY | `/portal/glossario/{slug2}` | `conteudo.portal.show` | `Portal\PortalController@contentList` | idem |
| ANY | `/buscar` | `search` | `Portal\PortalController@searchContents` | idem |
| ANY | `/buscando` | `search.by.text` | `Portal\PortalController@searchingContents` | idem |
| ANY | `/buscar/{data}` | `search.show` | `Portal\PortalController@searchContentShow` | idem |

Fonte: `v6/routes/web.php:123-125` e `v6/routes/web.php:59-61, 191-193`.

O parâmetro `{slug}` da rota AJAX **é a letra** (A–Z ou `all`), apesar do nome `slug`.

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

| Método | URI | Nome | Controller@ação |
|---|---|---|---|
| GET | `/cms/conteudos/glossario` | `listar-conteudo` | `Prefecture\ContentController@genericIndex` |
| GET | `/cms/conteudos/cadastrar/glossario` | `cadastrar-conteudo` | `Prefecture\ContentController@genericCreate` |
| GET | `/cms/conteudos/editar/glossario/{id}` | `editar-conteudo` | `Prefecture\ContentController@genericEdit` |
| POST | `/cms/conteudo` | `conteudo.store` | `Prefecture\ContentController@store` |
| PUT/PATCH | `/cms/conteudo/{id}` | `conteudo.update` | `Prefecture\ContentController@update` |
| DELETE | `/cms/conteudo/{id}` | `conteudo.destroy` | `Prefecture\ContentController@destroy` |
| POST | `/cms/conteudo/deleteAll` | `ajax.generic.content.deleteAll` | `Prefecture\ContentController@genericDeleteAll` |
| GET | `/cms/datatable/glossario` | `datatable.glossario` | `Prefecture\DatatableController@get_glossario` |

Fontes: `v6/routes/basepro.php:235-237`, `v6/routes/basepro.php:174`, `v6/routes/basepro.php:141`,
`v6/routes/basepro.php:426`.

Todas as rotas do CMS estão dentro do grupo `Route::group(['prefix' => 'cms', 'before' => 'csrf'])`
(`v6/routes/basepro.php:34`) e sob o middleware `check.route.permission`, aplicado no construtor
de `ContentController`:

```php
// v6/app/Http/Controllers/Prefecture/ContentController.php:58-67
public function __construct(Content $contentLog, IContentRepository $contentRepository)
{
    $this->middleware('check.route.permission');
    $this->contentLog = $contentLog;
    $this->contentRepository = $contentRepository;
}
```

## 3. Controlador do portal — `Portal\GlossaryController`

Arquivo: `v6/app/Http/Controllers/Portal/GlossaryController.php`

| Método | Linha | Comportamento |
|---|---|---|
| `index()` | 19-26 | Monta `$azRange = range('A','Z')` e renderiza `portal.layouts.{template}.transparencia.glossario` |
| `showByLetterAjax($letter)` | 28-38 | Converte `all` em `''`, filtra por `title LIKE '{letra}%'` e devolve JSON |

```php
public function showByLetterAjax($letter)
{
    if ($letter == 'all') {
        $letter = '';
    }
    $contentsGlossary = $this->content->whereHas('categoryContents', function ($query) {
        $query->bySlug('glossario');
    })->where('title', 'like', ''.$letter.'%')->get();

    return response()->json(['letterActive' => $letter, 'contentGlossary' => $contentsGlossary]);
}
```

Formato de saída (JSON, não há API Resource):

```json
{
  "letterActive": "A",
  "contentGlossary": [
    { "id": 12, "title": "Alíquota", "text": "<p>Definição</p>", "slug": "aliquota", "category_contents_id": 11 }
  ]
}
```

O JSON expõe o model `Content` completo (todos os `$fillable`), não apenas
`title`/`text`.

## 4. Controlador do CMS — `Prefecture\ContentController`

| Método | Linha | Comportamento no glossário |
|---|---|---|
| `genericIndex($slug)` | 88-119 | `if ($slug === 'glossario') return $this->returnIndex('Glossário', $slug);` (linha 96) |
| `genericCreate($slug)` | 152-155 | Delega para `genericGenerate` |
| `genericEdit($slug, $id)` | 165-168 | Delega para `genericGenerate` |
| `genericGenerate($slug, $id)` | 170-205 | `if ($slug === 'glossario') return $this->returnData('Glossário', $slug, null, [], $id);` (linha 169) |
| `store` / `update` | ~600-1300 | CRUD genérico; aplica `ContentRequest`; grava `contents` |
| `genericDeleteAll` | 69-77 | Exclusão em lote via `contentRepository->destroyAll()` |

`returnIndex` registra log de menu e renderiza a view pelo slug:

```php
// v6/app/Http/Controllers/Prefecture/ContentController.php:121-125
public function returnIndex($title, $slug, $alt_click = null)
{
    $this->generateLog($title);
    isset($alt_click) ? menuClicks($alt_click) : menuClicks($slug);
    return view("prefecture.contents.$slug.index", ['title' => $title]);
}
```

## 5. Controlador do CMS — `Prefecture\DatatableController`

```php
// v6/app/Http/Controllers/Prefecture/DatatableController.php:222-226
public function get_glossario()
{
    $glossario = DB::table("glossario")->get();
    return DataTables::of($this->struct_views($glossario, 'glossario'))->make(true);
}
```

`struct_views` acrescenta, por linha, as flags de permissão consumidas pelo JS:

```php
// v6/app/Http/Controllers/Prefecture/DatatableController.php:504-520
public function struct_views($data, $permission)
{
    for ($i = 0; $i < count($data); $i++) {
        $data[$i]->edit = has_access("$permission.edit");
        if ($permission === 'diario-oficial') {
        } else {
            $data[$i]->delete = has_access("$permission.delete");
        }
        $data[$i]->active = has_access("$permission.restore");
        $data[$i]->inactivate = has_access("$permission.inactivate");
    }
    return $data;
}
```

## 6. Form Requests e validação

`v6/app/Http/Requests/ContentRequest.php` — `glossario` não possui `case` próprio e
portanto cai no bloco `default:` (linhas 308-314):

```php
default:
    $rules = [
        "title" => "required|max:120",
        "category_contents_id" => "required|numeric",
        "archive.*.0" => "mimes:jpg,jpeg,png,bmp,gif,rar,zip,doc,docx,pdf,odt,xls,xlsx,xlsb,xslm,ppt,pptx,ods,wav,mp3,wma,mp4,mpg4,mkv,flv",
        "archive_highlight" => "max:20000|mimes:jpg,jpeg,png,gif,webp",
    ];
```

| Regra | Efeito observável |
|---|---|
| `title` required, máx. 120 | Termo é obrigatório; o formulário também impõe `maxlen=120` |
| `category_contents_id` required numeric | Garante que o verbete seja ligado a uma categoria |
| `text` **não** é validado | O formulário marca "Texto" como obrigatório, mas o servidor aceita conteúdo vazio |

## 7. Breadcrumbs

`v6/routes/breadcrumbs.php:241-251`:

```php
// Home > Glossario
Breadcrumbs::register('glossario', function ($breadcrumbs) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push('Glossário');
});

// Busca > Glossario
Breadcrumbs::register('glossario-conteudo', function ($breadcrumbs, $content) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push('Glossário', url('/glossario'));
    $breadcrumbs->push($content->title);
});
```

## 8. Permissões exigidas

| Permissão | Onde é exigida |
|---|---|
| `glossario.create` | Botão "Cadastrar Conteúdo" (`v6/resources/views/prefecture/contents/glossario/index.blade.php:10`) |
| `glossario.edit` | Coluna de ação do DataTable (`v6/public/assets/js/custom/contents/glossario/datatable.js:14`) |
| `glossario.delete` | Exclusão individual e em lote (`index.blade.php:15`, `datatable.js:14`) |
| `glossario.restore` / `glossario.inactivate` | Injetadas por `struct_views` (não usadas pelo JS do glossário) |
| `check.route.permission` (middleware) | Todas as rotas do CMS |

## 9. API

Não há rota de glossário em `v6/routes/api.php`: a API v1 expõe notícias, publicações,
legislação, órgãos e secretarias (`v6/app/Http/Controllers/Swagger/V1/Portal/`). Para a v7,
recomenda-se expor `GET /api/v1/glossario?letra=A` como recurso JSON.
