# Perguntas Frequentes — Regras e Portabilidade

> Regras não óbvias, acoplamentos e armadilhas observadas no código da `v6`.

---

## 1. Regras de negócio não óbvias

| # | Regra | Onde está | Efeito observável |
|---|---|---|---|
| R1 | A FAQ **não tem página própria**: é uma categoria de conteúdo servida pelo "Acesso Rápido" | `v6/routes/web.php:88-89` + `v6/app/Http/Controllers/Portal/QuickAccessController.php:29-43` | A URL canônica é `/acesso-rapido/perguntas-frequentes` |
| R2 | `title` = pergunta, `text` = resposta | `v6/resources/views/prefecture/contents/perguntas-frequentes/form.blade.php` | O CMS não tem campos separados |
| R3 | A listagem pública **não filtra por `status`** | `v6/app/Http/Traits/GetInformationsPrefectureTrait.php:28-33` | Itens desativados continuam visíveis ao cidadão |
| R4 | Sem itens na categoria -> a página **estática** assume | `QuickAccessController.php:38-40` | O fallback é `static_pages` com o mesmo slug |
| R5 | A view final é montada por **concatenação de string** com o slug | `QuickAccessController.php:26` | Um slug malformado quebra a view (`view not found`) |
| R6 | O CMS lista pela **view SQL** `perguntas_frequentes`; o portal usa Eloquent | `DatatableController.php:218` vs `GetInformationsPrefectureTrait.php:28` | As duas telas podem mostrar conjuntos diferentes |
| R7 | A view SQL expõe apenas `value`, `titulo`, `id` (não a resposta) | migration `2023_04_10_151038_create_view_to_perguntas_frequentes.php` | No CMS, o operador precisa abrir o item para ler a resposta |
| R8 | A exclusão é soft delete | `v6/app/Http/Model/Prefecture/Content.php:16` | Itens excluídos somem da view e da listagem |
| R9 | A pergunta aparece na busca global | `v6/app/Http/Controllers/Portal/PortalController.php:251,265` | `perguntas-frequentes` é um dos slugs buscáveis |
| R10 | O módulo do CMS (`modulos` id 25) e a categoria (`category_contents` id 12) têm o mesmo slug | migration `2024_11_01_150206_create_modulos_table.php:172-177` | A permissão `perguntas-frequentes.*` controla o CRUD |

## 2. Acoplamentos

| Depende de | Onde | Natureza |
|---|---|---|
| `Portal\QuickAccessController` | rota `acesso-rapido.index` | A FAQ não sobrevive sem o "acesso rápido" |
| `GetInformationsPrefectureTrait::getContentByCategory` | listagem pública | Sem filtro de status (R3) |
| `GetInformationsPrefectureTrait::getTemplateActived` | escolha do layout | Lê `configurations.key = 'layout'` |
| `static_pages` | fallback do `QuickAccessController` | Página estática com o mesmo slug |
| `links` (seed `AcessoRapidoSeeder`) | atalho do menu | Aponta para `/acesso-rapido/perguntas-frequentes` |
| `FilterSearchAllSite` | busca global | Inclui a categoria e a resposta no texto indexado |
| `PortalController@getViewToBeReturned` | página do item | Mapa por id de categoria (`12 => 'perguntas-frequentes.show'`) |
| Tabela `contents` | dados | Herança do conteúdo genérico |

## 3. Armadilhas

| Armadilha | Evidência | Impacto |
|---|---|---|
| `CommonQuestionsController` órfão | `v6/app/Http/Controllers/Portal/CommonQuestionsController.php` sem rota; view `portal.layouts.default.pages.common-questions` inexistente | Código morto; se a rota for criada, resposta 500 |
| CMS `show.blade.php` órfão | `v6/resources/views/prefecture/contents/perguntas-frequentes/show.blade.php` sem rota que a renderize | Arquivo de manutenção enganosa |
| View do layout `default` órfã | `v6/resources/views/portal/layouts/default/pages/contents/perguntas-frequentes/index.blade.php` | Implementação divergente do filtro que nunca roda |
| `str_limit` no breadcrumb | `v6/routes/breadcrumbs.php:259-261` | Helper removido no Laravel 6+: quebra ao abrir a página do item |
| Filtro com `RegExp` não escapado | view morta do layout `default` | `RegExp` inválido lança erro no navegador |
| Variável global `currentName` | JS do modelo1 | Vazamento de escopo |
| Resposta renderizada sem escape | `{!!$content->text!!}` | XSS se o CMS gravar HTML malicioso |
| Sem paginação | `QuickAccessController` -> `->get()` | Todas as perguntas são entregues em uma página |
| `has_access()` por linha | `DatatableController.php:504-520` | N+1 de verificações de permissão |
| `catch (\Throwable $th) {}` no `contentList` | `PortalController.php:367` | Erros engolidos com HTTP 200 vazio |
| `getContentByCategory` sem `byStatus()` | `GetInformationsPrefectureTrait.php:28-33` | Questão desativada continua pública |
| Views `perguntas-frequentes/show.blade.php` ausentes em `default`/`newsbit` | `v6/resources/views/portal/layouts/` | Resultado da busca quebra nesses layouts |

## 4. Código duplicado entre v5 e v6

| Arquivo | v5 | v6 | Diferença |
|---|---|---|---|
| `Portal/QuickAccessController.php` | presente | presente | Estrutura equivalente; a v6 usa `informacoes-instituicao` (a v5 usava `informacoes-prefeitura`) |
| `Portal/CommonQuestionsController.php` | presente (morto) | presente (morto) | Idêntico |
| `Prefecture/DatatableController::get_perguntas_frequentes` | presente | presente | Idêntico |
| Migration da view `perguntas_frequentes` | `v5/database/migrations/2023_04_10_151038_create_view_to_perguntas_frequentes.php` | `v6/database/migrations/2023_04_10_151038_create_view_to_perguntas_frequentes.php` | Mesmo SQL |
| JS do DataTable | `v5/public/assets/js/custom/contents/perguntas-frequentes/datatable.js` | `v6/public/assets/js/custom/contents/perguntas-frequentes/datatable.js` | Idêntico |

## 5. Onde a v6 divergiu da v5 (visível na FAQ)

| Aspecto | v5 | v6 |
|---|---|---|
| Pasta do portal | `informacoes-prefeitura/acesso-rapido/perguntas-frequentes.blade.php` | `informacoes-instituicao/acesso-rapido/perguntas-frequentes.blade.php` (renomeada) |
| Layout `newsbit` | presente | presente |
| Controller público dedicado | não existia | continua não existindo |
| Registry de módulos (`modulos`, `resources`, `menu_orders`) | inexistente | criado (id 25) |

A v6 **trocou o nome da pasta** do portal e adicionou a camada de registry; a lógica da FAQ
permaneceu igual.

## 6. Pontos de atenção para a v7

1. Criar um `FaqController` dedicado (o `QuickAccessController` genérico esconde a rota real
   e força o nome do arquivo de view a ser igual ao slug).
2. Filtrar por status na listagem pública (ou criar o campo de status no formulário).
3. Unificar o filtro client-side em um único componente (hoje há duas implementações).
4. Remover `CommonQuestionsController` e a view morta do layout `default`.
5. Substituir `str_limit` por `Str::limit`.
6. Escapar/sanitizar o HTML da resposta na entrada e na saída.

## 7. Checklist de portabilidade

| Item | Estado na v6 | Situação na v7 (decisão) |
|---|---|---|
| Slug do módulo e da categoria | `perguntas-frequentes` (id 25 / id 12) | Manter o slug como chave de permissão e de rota |
| URL pública | `/acesso-rapido/perguntas-frequentes` | Manter (alias) + criar `/perguntas-frequentes` |
| Controller | `QuickAccessController` (genérico) | `FaqController@index` dedicado |
| Origem dos dados no CMS | view SQL `perguntas_frequentes` | Consulta Eloquent sobre `faq_questions` |
| Origem dos dados no portal | `getContentByCategory` (sem status) | `FaqQuestion::published()` |
| Filtro client-side | 2 implementações divergentes | 1 componente de filtro |
| Página do item (busca) | `perguntas-frequentes.show` (modelo1..6) | Componente único `faq.item` |
| Fallback de página estática | `QuickAccessController::getIndexStatic` | Manter ou remover, conforme decisão do negócio |
| Permissões | `perguntas-frequentes.*` | Manter o nome |
| Seed de demonstração (LAI) | `ContentsTableSeeder` | `FaqQuestionSeeder` na v7 |
| API | inexistente | `GET /api/v1/perguntas-frequentes` |

## 8. Regras que NÃO podem mudar (equivalência funcional)

1. A FAQ continua acessível por `/acesso-rapido/perguntas-frequentes` sem autenticação.
2. A pergunta é o **título** do item e a resposta é o **corpo** do texto, renderizado como HTML.
3. Cada pergunta continua exibida com o prefixo "**R.**" antes da resposta.
4. O card "Perguntas Frequentes" e o campo "Digite para filtrar:" continuam presentes.
5. A FAQ continua incluída na busca global do portal.
6. A edição pelo CMS continua exigindo permissão específica do módulo (`perguntas-frequentes.edit`).
7. A ausência de perguntas não pode gerar erro: a página deve degradar para a página estática.
