# Revisões — Rotas e Controllers

> Todas as rotas vivem em `v6/routes/basepro.php`, dentro do grupo de prefixo `cms`
> (`v6/routes/basepro.php:35`).
> **Não existe rota de portal**: verificado em `v6/routes/web.php`, `v6/routes/api.php`,
> `v6/routes/prefecture.php` e `v6/routes/service_letter.php` (nenhuma ocorrência de
> `revis`, `rating` ou `question`).

---

## 1. Mapa de grupos de rota relevante

| Grupo | Linhas | Prefixo efetivo | Efeito |
|---|---|---|---|
| `cms` | 35–513 | `/cms` | envelopa tudo |
| `ajax` | 114–168 | `/cms/ajax` | rotas de ação em lote |
| `check.logged` | 265–344 | `/cms` | exige login (resource `revisoes`, `respostas`, `questions`, `options`) |
| `datatable` | 396–470 | `/cms/datatable` | endpoints JSON das DataTables |

Rotas do módulo **fora** do grupo `check.logged` (apenas `check.route.permission` quando o
controller o declara): `revisoes/delete-por-lote` (linha 149), `revisoes/relatorios`
(linha 221), `listagem/revisoes/graficos/{id}` (linha 225) e `data/dashboard/envios`
(linha 226).

## 2. Rotas CMS do módulo

### 2.1 Avaliação (`ratings`) — `Prefecture\RatingsController`

| Método | URI | Nome | Linha | Middleware |
|---|---|---|---|---|
| GET | `/cms/revisoes` | `revisoes.index` | 267 | `check.logged` + `check.route.permission` |
| GET | `/cms/revisoes/create` | `revisoes.create` | 267 | idem |
| POST | `/cms/revisoes` | `revisoes.store` | 267 | idem |
| GET | `/cms/revisoes/{id}/edit` | `revisoes.edit` | 267 | idem |
| PUT/PATCH | `/cms/revisoes/{id}` | `revisoes.update` | 267 | idem |
| DELETE | `/cms/revisoes/{id}` | `revisoes.destroy` | 267 | idem |
| GET | `/cms/revisoes/{id}` | `revisoes.show` | 267 (default do resource) | idem — **controller não implementa `show`** |
| GET | `/cms/copiar_revisao/{id}` | `revisoes.paste` | 276 | `check.logged` |
| GET | `/cms/download_revisao/{id}` | `revisoes.download` | 277 | `check.logged` |
| POST | `/cms/import_revisao` | `revisoes.import` | 278 | `check.logged` |
| POST | `/cms/setStatus` | `revisoes.setStatus` | 279 | `check.logged` |
| POST | `/cms/ajax/revisoes/delete-por-lote` | `ajax.ratings.deleteByLote` | 149 | grupo `ajax` |

### 2.2 Relatórios do "cliente" — `Prefecture\RatingsClientsController`

| Método | URI | Nome | Linha | Middleware |
|---|---|---|---|---|
| GET | `/cms/revisoes/relatorios` | `revisoes/relatorios.index` | 221 | — |
| GET | `/cms/revisoes/relatorios/create` | `revisoes/relatorios.create` | 221 | — |
| POST | `/cms/revisoes/relatorios` | `revisoes/relatorios.store` | 221 | — |
| GET | `/cms/revisoes/relatorios/{id}` | `revisoes/relatorios.show` | 221 | — |
| GET | `/cms/revisoes/relatorios/{id}/edit` | `revisoes/relatorios.edit` | 221 | — |
| PUT/PATCH | `/cms/revisoes/relatorios/{id}` | `revisoes/relatorios.update` | 221 | — |
| DELETE | `/cms/revisoes/relatorios/{id}` | `revisoes/relatorios.destroy` | 221 | — |
| GET | `/cms/listagem/revisoes/graficos/{id}` | *(sem nome)* | 225 | — |
| GET | `/cms/data/dashboard/envios` | *(sem nome)* | 226 | — |

`RatingsClientsController` estende `App\Http\Controllers\Admin\Controller` e **não** declara
nenhum middleware: o resource `revisoes/relatorios` expõe `create`, `store`, `update` e
`destroy` para controllers que não implementam esses métodos (só `index`, `show` e `edit`
existem) — rotas mortas.

### 2.3 Respostas e envios — `Prefecture\QuestionAnswersController`

| Método | URI | Nome | Linha | Middleware |
|---|---|---|---|---|
| GET | `/cms/respostas` | `respostas.index` | 282 (resource) **e** 291 | `check.logged` |
| POST | `/cms/respostas` | `respostas.store` | 282 | `check.logged` |
| GET | `/cms/respostas/create` | `respostas.create` | 282 | `check.logged` |
| GET | `/cms/respostas/{id}` | `respostas.show` | 282 | `check.logged` |
| GET | `/cms/respostas/{id}/edit` | `respostas.edit` | 282 | `check.logged` |
| PUT/PATCH | `/cms/respostas/{id}` | `respostas.update` | 282 | `check.logged` |
| DELETE | `/cms/respostas/{id}` | `respostas.destroy` | 282 | `check.logged` |
| GET | `/cms/resposta/enviadas` | `resposta_enviada.index` | 286 | `check.logged` |
| GET | `/cms/respostas/create/{id}` | `send.create` | 287 | `check.logged` |
| GET | `/cms/respostasByRatings/{id}` | `respostasByRatings.get` | 288 | `check.logged` |
| GET | `/cms/resposta/getEnvio/{id}` | `respostas.getEnvio` | 292 | `check.logged` |
| GET | `/cms/resposta/getEmails/{id}` | `respostas.getEmails` | 293 | `check.logged` |
| POST | `/cms/resposta/enviar_email` | `respostas.email` | 294 | `check.logged` |
| GET | `/cms/respostas/pdf/{id}` | `questions.pdf` | 323 | `check.logged` |
| GET | `/cms/resposta/enviadas/{id}` | `relatorio.show` | 330 | `check.logged` |
| GET | `/cms/respostas/enviadas/anuais` | `relatorio.anuais` | 331 | `check.logged` |
| GET | `/cms/respostas/get/{ano}` | *(sem nome)* | 332 | `check.logged` |

### 2.4 Perguntas — `Prefecture\QuestionController`

| Método | URI | Nome | Linha |
|---|---|---|---|
| POST | `/cms/questions/saveQuestion` | `questions.save` | 317 |
| GET | `/cms/questions/getQuestion/{id}` | `questions.get` | 318 |
| POST | `/cms/questions/editQuestion` | `questions.edit` | 319 |
| POST | `/cms/questions/deleteQuestion` | `questions.delete` | 320 |
| POST | `/cms/reorder` | `questions.reorder` | 326 |
| POST | `/cms/categories-reorder` | `categories.reorder` | 327 |

### 2.5 Categorias e opções — `Prefecture\OptionsController`

| Método | URI | Nome | Linha | Action |
|---|---|---|---|---|
| GET | `/cms/options/getCategories` | `categories.get` | 297 | `get_categories` |
| POST | `/cms/options/saveCategories` | `categories.save` | 298 | `save_categories` |
| POST | `/cms/options/deleteCategories` | `categories.delete` | 299 | `delete_categories` |
| GET | `/cms/options/editCategories/{id}` | `categories.edit` | 300 | `edit_categories` |
| POST | `/cms/options/updateCategories/{id}` | `categories.update` | 301 | `update_categories` |
| GET | `/cms/options/getCategoryOptions` | `category_options.get` | 304 | `get_category_options` |
| GET | `/cms/options/getAllOptions` | `all_options.get` | 305 | `get_all_options` |
| GET | `/cms/options/getRelation/{id}` | `relation.get` | 306 | `relationIsFather` |
| POST | `/cms/options/saveOptions` | `options.save` | 307 | `save_options` |
| POST | `/cms/options/deleteOption` | `options.delete` | 308 | `delete_options` |
| POST | `/cms/options/saveOptionsCategories` | `optionCategory.save` | 311 | `save_options_categories` |
| POST | `/cms/options/deleteOptionsCategories` | `optionCategory.delete` | 312 | `delete_options_categories` |
| POST | `/cms/options/updateOptionsCategories` | `optionCategory.update` | 313 | `update_options_categories` |
| POST | `/cms/options/deleteOptionOfCategory` | `deleteOptionCategory.save` | 314 | `delete_options_of_category` |

### 2.6 DataTables — `Prefecture\DatatableController`

| Método | URI | Action | Linha | View SQL |
|---|---|---|---|---|
| GET | `/cms/datatable/formulario` | `get_revisoes_formulario` | 446 | `formulario` |
| GET | `/cms/datatable/envios` | `get_revisoes_envios` | 444 | `envios` |
| GET | `/cms/datatable/respostas` | `get_respostas` | 437 | `respostas` |
| GET | `/cms/datatable/listagem_revisoes` | `get_listagem_revisoes` | 456 | `listagem_clientes` |

`struct_views($data, $permission)` (`v6/app/Http/Controllers/Prefecture/DatatableController.php:504-520`)
adiciona `edit`, `delete`, `active` e `inactivate` a cada linha, com base em
`has_access("<permission>.<ação>")`. Para o módulo, `get_revisoes_envios` e
`get_revisoes_formulario` usam a permissão `revisoes`, mas `get_listagem_revisoes` usa
`pagina-estatica` (copy/paste) — ver `08-GAPS-E-DIVIDAS.md`.

## 3. Form Requests e validação

| Request | Regras | Usado em |
|---|---|---|
| `v6/app/Http/Requests/RatingRequest.php` | `title`, `subtitle`, `description` obrigatórios | `RatingsController@store` / `@update` |
| `v6/app/Http/Requests/RevisoesRepostas.php` | `dataDeEnvio`, `revisor` obrigatórios | `QuestionAnswersController@store` |

Não há validação em:

- `QuestionController` (`save_question`, `edit_question`, `question_order`, `categories_order`);
- `OptionsController` (todas as actions);
- `QuestionAnswersController@enviar_email` (e-mail das revisões);
- `RatingsController@importar_revisao` (JSON importado).

As mensagens de `RevisoesRepostas` estão **trocadas** (`dataDeEnvio.required` diz "O campo
revisor é obrigatório") — bug de texto.

## 4. Formato das respostas (sem API Resource)

| Endpoint | Retorno |
|---|---|
| `POST /cms/questions/saveQuestion` | model `Questions` serializado (com `question_type`, `question_categories`, `ratings`, `options_categories` carregados) |
| `GET /cms/questions/getQuestion/{id}` | model `Questions` serializado |
| `POST /cms/questions/editQuestion` | model `Questions` serializado |
| `POST /cms/questions/deleteQuestion` | booleano do `delete()` |
| `POST /cms/reorder`, `POST /cms/categories-reorder` | string `"true"` / `"false"` |
| `GET /cms/options/getCategories` | coleção `QuestionCategory` com `parent_id` |
| `GET /cms/options/getCategoryOptions` | coleção `OptionCategory` com `options` |
| `GET /cms/options/getAllOptions` | coleção `Options` com `options_category` |
| `GET /cms/options/getRelation/{id}` | `["true"]` / `["false"]` |
| `POST /cms/options/saveCategories` | id da categoria criada (numérico cru) |
| demais `options/*` | string `"true"` / `"false"` ou array de mensagem |
| `GET /cms/respostasByRatings/{id}` | coleção `AnswerForm` com `ratings`, `questions`, `option` |
| `GET /cms/resposta/getEnvio/{id}` | model `SendRating` |
| `GET /cms/resposta/getEmails/{id}` | coleção `EmailRevisoes` |
| `POST /cms/resposta/enviar_email` | string `"true"` / `"false"` |
| `GET /cms/respostas/get/{ano}` | array `[título da revisão, [{label, pontos, pontos-totais}]]` |
| `GET /cms/data/dashboard/envios` | mesmo formato de `getEnvios` |

Ou seja: **não existe contrato de API versionado**. O JSON é o Eloquent serializado, e o
frontend depende do formato exato.

## 5. Autorização

| Camada | Como funciona |
|---|---|
| Sessão | `check.logged` nas rotas de `revisoes`, `respostas`, `questions`, `options` |
| Permissão por rota | `check.route.permission` (declarado no construtor de `RatingsController`): compara o nome da rota e o segmento da URL com `Sentinel::check()->hasAnyAccess()`; `super-admin` passa direto (`v6/app/Http/Middleware/CheckRoutePermission.php:41-92`) |
| Permissão por botão | `has_access(['revisoes.create'])`, `has_access(['revisoes.delete'])` nas views Blade |

`QuestionAnswersController`, `QuestionController` e `OptionsController` **não** aplicam
`check.route.permission`: o controle é apenas `check.logged`.

## 6. Rotas de portal/API

Nenhuma. O módulo é exclusivamente administrativo. O único contato com o público é o
**e-mail** com o PDF anexado, disparado por `QuestionAnswersController@enviar_email`
(view `prefecture.emails.revisoes.email_user`).
