# Rotas e Permissões — Diário Oficial

Mapa verificado das rotas do módulo e das permissões Sentinel associadas.

## Prefixos

| Arquivo | Grupo | Prefixo final |
|---------|-------|---------------|
| `routes/basepro.php` | `Route::group(['prefix' => 'cms', 'before' => 'csrf'])` | `/cms/...` |
| `routes/basepro.php` | subgrupo `prefix => 'ajax'` (dentro de `cms`) | `/cms/ajax/...` (parte das rotas) |
| `routes/basepro.php` | subgrupo `prefix => 'datatable', as => 'datatable.'` | `/cms/datatable/...` |
| `routes/web.php` | portal | `/...` (raiz) |

Middleware:
- `DiarioController` aplica `check.route.permission` **exceto** `dados_diario` e `destroyAreas`.
- `DiarioCertificadosController` aplica `check.route.permission`.
- `dados_diario` e `diario.generation-status` usam `check.logged`.
- `generation-status` é liberado pelo `CheckRoutePermission`.

---

## 1. Resource routes (CMS)

### `diario-oficial` → `Prefecture\DiarioController`

| Método | URI | Nome | Ação |
|--------|-----|------|------|
| GET | `/cms/diario-oficial` | `diario-oficial.index` | Listagem (DataTable) |
| GET | `/cms/diario-oficial/create` | `diario-oficial.create` | Formulário de cadastro |
| POST | `/cms/diario-oficial` | `diario-oficial.store` | Salva (sem gerar PDF) |
| GET | `/cms/diario-oficial/{id}` | `diario-oficial.show` | Stream do PDF ou JSON de status |
| GET | `/cms/diario-oficial/{id}/edit` | `diario-oficial.edit` | Formulário de edição + matérias |
| PUT/PATCH | `/cms/diario-oficial/{id}` | `diario-oficial.update` | Atualiza (sem gerar PDF) |
| DELETE | `/cms/diario-oficial/{id}` | `diario-oficial.destroy` | Exclui |

### `certificado` → `Prefecture\DiarioCertificadosController`

| Método | URI | Nome |
|--------|-----|------|
| GET | `/cms/certificado` | `certificado.index` |
| GET | `/cms/certificado/create` | `certificado.create` |
| POST | `/cms/certificado` | `certificado.store` |
| GET | `/cms/certificado/{id}` | `certificado.show` |
| GET | `/cms/certificado/{id}/edit` | `certificado.edit` |
| PUT/PATCH | `/cms/certificado/{id}` | `certificado.update` |
| DELETE | `/cms/certificado/{id}` | `certificado.destroy` |

> O controller implementa apenas `index`, `create`, `store` e `destroy`.

### `area` → `Prefecture\DiarioAreaController`

| Método | URI | Nome |
|--------|-----|------|
| GET | `/cms/area` | `area.index` |
| GET | `/cms/area/create` | `area.create` |
| POST | `/cms/area` | `area.store` |
| GET | `/cms/area/{id}` | `area.show` |
| GET | `/cms/area/{id}/edit` | `area.edit` |
| PUT/PATCH | `/cms/area/{id}` | `area.update` |
| DELETE | `/cms/area/{id}` | `area.destroy` |

> O mesmo controller cria/edita **Matérias** (`diario_has_areas`) quando não há `name`.
> A edição de matéria usa a rota de `edit` com `{id}_modal` (ex.: `/cms/area/15_modal/edit`).

### `subarea` → `Prefecture\DiarioSubAreaController`

| Método | URI | Nome |
|--------|-----|------|
| GET | `/cms/subarea` | `subarea.index` |
| GET | `/cms/subarea/create` | `subarea.create` |
| POST | `/cms/subarea` | `subarea.store` |
| GET | `/cms/subarea/{id}` | `subarea.show` |
| GET | `/cms/subarea/{id}/edit` | `subarea.edit` |
| PUT/PATCH | `/cms/subarea/{id}` | `subarea.update` |
| DELETE | `/cms/subarea/{id}` | `subarea.destroy` |

---

## 2. Rotas específicas

| Método | URI | Nome | Controller@method |
|--------|-----|------|-------------------|
| GET | `/cms/ajax/dados-diario/{id}` | `dados_diario` | `DiarioController@dados_diario` |
| POST | `/cms/ajax/diario-oficial` | `diario.destroy` | `DiarioController@destroy` |
| PUT | `/cms/ajax/diario-oficial/{id}/sort` | `diario.sort` | `DiarioController@sort` |
| GET | `/cms/ajax/diario-generation-status/{id}` | `diario.generation-status` | `DiarioController@generationStatus` |
| POST | `/cms/diario/destroyAll` | `diario.destroyAll` | `DiarioController@destroyAll` |
| POST | `/cms/area/destroyAll` | `area.destroyAll` | `DiarioAreaController@destroyAll` |
| POST | `/cms/subarea/destroyAll` | `subarea.destroyAll` | `DiarioSubAreaController@destroyAll` |
| POST | `/cms/diario/status` | `diario-status-toggle` | `DiarioController@toogle_status` |
| GET | `/cms/diario/configuracoes` | `diario-config.index` | `DiarioController@get_configuration` |
| PUT | `/cms/diario/configuracoes/update` | `diario-config.update` | `DiarioController@update_configuration` |
| DELETE | `/cms/diario/configuracoes/header-img/{id}` | `diario-config.delete.header-img` | `DiarioController@delete_header_img` |
| DELETE | `/cms/diario-area/{id}` | — | `DiarioController@destroyAreas` |

> ⚠️ As rotas `diario/configuracoes`, `diario/configuracoes/update` e `diario-area/{id}`
> estão **declaradas em duplicidade** em `basepro.php` (linhas 219-222 e 224-226).

---

## 3. Rotas de refresh / preview / loading

Declaradas em `routes/web.php` (raiz do site), mas apontando para o controller do CMS.

| Método | URI | Nome | Controller@method |
|--------|-----|------|-------------------|
| GET | `/refresh-diario/{id}` | `refresh-PDF` | `Prefecture\DiarioController@refresh_PDF` |
| GET | `/refresh-diario-preview/{id}` | `refresh-PDF-previe` | `Prefecture\DiarioController@refresh_PDF_preview` |
| GET | `/loading-diario-preview` | `loading-diario-preview` | `Prefecture\DiarioController@loading` |

> `refresh_PDF_preview` aceita `?force=1` para regenerar mesmo com status `completed`.
> `refresh_PDF` não gera: apenas redireciona para a edição.

---

## 4. DataTables (CMS)

| Método | URI | Nome | Fonte (view) |
|--------|-----|------|--------------|
| GET | `/cms/datatable/diario_oficial` | `datatable.diario_oficial` | `diario_oficial` |
| GET | `/cms/datatable/areas_diario` | — | `areas_do_diario` |
| GET | `/cms/datatable/sub_areas_diario` | — | `sub_areas_do_diario` |

---

## 5. Portal (público) — `routes/web.php`

| Método | URI | Nome | Controller@method |
|--------|-----|------|-------------------|
| GET | `/diario-oficial` | `portal-diario.index` | `Portal\DiarioController@index` |
| GET | `/diario-oficial/{id}` | `portal-diario.show` | `Portal\DiarioController@showPDF` |
| POST | `/diario-oficial/filtro` | `portal-diario.fill` | `Portal\DiarioController@filtroGET` |
| GET | `/diario-oficial/viewer/search` | `portal-diario.search` | `Portal\DiarioController@search` |
| GET | `/diario-oficial/viewer/{id}/file-info` | `portal-diario.file-info` | `Portal\DiarioController@fileInfo` |

> ⚠️ Ordem de registro: `/diario-oficial/{id}` é declarada **antes** de
> `/diario-oficial/viewer/search` — o segmento literal `viewer` não colide porque `{id}`
> está no primeiro nível, mas depende da ordem para `{id}` não capturar `viewer`.

---

## 6. Breadcrumbs

`routes/breadcrumbs.php`:

```php
Breadcrumbs::register('diario-oficial', function ($breadcrumbs) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push("Diário Oficial", route('portal-diario.index'));
});
```

---

## 7. Permissões (Sentinel)

### 7.1 Verificadas no menu (`MenuServiceProvider`)

| Item | Permissão |
|------|-----------|
| Menu "Diário Oficial" | — (agrupador) |
| "Diários" → `/cms/diario-oficial` | `diario-oficial.index` |
| "Áreas do Diário" → `/cms/area` | `diario-area.index` |
| "Subáreas do Diário" → `/cms/subarea` | `diario-subarea.index` |

### 7.2 Verificadas em `DatatableController::struct_views()`

| Ação | Chave | Regra |
|------|-------|-------|
| Editar | `{permission}.edit` | `diario-oficial` / `diario-area` |
| Excluir (diário) | — | `super-admin` **ou** `administrador` |
| Excluir (área/subárea) | `{permission}.delete` | `diario-area` |
| Ativar | `{permission}.restore` | — |
| Inativar | `{permission}.inactivate` | — |

> ⚠️ `get_sub_areas_diario()` usa a permissão `diario-area` em vez de `diario-subarea`.

### 7.3 Verificadas nas views

| Tela / botão | Permissão |
|--------------|-----------|
| Botão "Configurações" | `diario-oficial.create` |
| Botão "Cadastrar" | `diario-oficial.create` |
| Botão "Certificados" | `certificado.index` |
| Botão "Excluir Selecionados" | `diario-oficial.delete` |
| Checkbox "Publicar Diário?" | `diario-oficial.inactivate` (ou sem permissões) + `diario-oficial.permission_edit` |
| Ações de matéria no modal | `super-admin` ou `$diario->permission_edit` |

### 7.4 Rotas de certificado

`certificado.index` / `certificado.create` / `certificado.delete` governam a listagem,
o cadastro e a exclusão (checadas via `has_access()` na view).

---

## 8. Observações rápidas

- `toogle_status` recebe `contents_id` no corpo (nome legado de outro módulo).
- `destroy` do diário usa `$this->table->destroy($id)` (soft delete) e responde JSON.
- O PDF **não** é gerado por `store`/`update`; apenas por `refresh_PDF_preview` ou pelo
  portal (marcação `pending`) — ver `23-GUIA_EXECUCAO.md`.
- Pontos de atenção de rota/permissão estão catalogados em `22-ANOMALIAS_E_RISCOS.md`.
