# Perguntas Frequentes — Arquitetura

> Versão analisada: `v6` (idêntico em `v5`). Módulo CMS: `perguntas-frequentes`
> (`modulos`, id 25) | Categoria de conteúdo: `category_contents.id = 12`.

---

## 1. Visão geral

A FAQ é conteúdo genérico (`contents`) na categoria `perguntas-frequentes`. A diferença
para o Glossário está em **quem serve a página pública**: não há controller dedicado; a
rota entra no prefixo `acesso-rapido` e é tratada pelo `QuickAccessController`, um
controller genérico que monta a view pelo slug.

| Fluxo | Entrada | Saída | Quem consome |
|---|---|---|---|
| Portal (público) | `GET /acesso-rapido/perguntas-frequentes` | HTML server-side | Cidadão |
| Busca global | `GET /buscar`, `GET /buscando` | HTML + JSON | Cidadão |
| CMS (admin) | `/cms/conteudos/perguntas-frequentes`, resource `conteudo` | HTML + DataTable JSON | Operador |

## 2. Fluxo da requisição — Portal

```
Cidadão
  │ GET /acesso-rapido/perguntas-frequentes
  ▼
Route::prefix('acesso-rapido') -> group (v6/routes/web.php:88-89)
  │ Route::any('/{slug}', 'Portal\QuickAccessController@index')->name('acesso-rapido.index')
  ▼
QuickAccessController@index($slug1 = 'perguntas-frequentes')
  │ 1) se $slug1 === 'ouvidoria' -> redirect (não se aplica)
  │ 2) $contents = $this->getContentByCategory($slug1)
  │ 3) se count($contents) == 0 -> getIndexStatic($slug1)  (fallback de página estática)
  ▼
GetInformationsPrefectureTrait::getContentByCategory         v6/app/Http/Traits/GetInformationsPrefectureTrait.php:28-33
  │ Content::whereHas('categoryContents', fn($q) => $q->where('slug',$param))->get()
  │ (sem filtro de status, sem filtro de publication_date)
  ▼
view('portal.layouts.{template}.informacoes-instituicao.acesso-rapido.perguntas-frequentes')
  │ @foreach($contents as $content) -> <h5>{{$content->title}}</h5><p><strong>R.</strong> {!!$content->text!!}</p>
  ▼
Filtro client-side no campo #txtBusca (keyup) sobre #ulItens li
```

## 3. Fluxo da requisição — CMS

```
Operador
  │ GET /cms/conteudos/perguntas-frequentes
  ▼
Route::get('conteudos/{slug}') -> ContentController@genericIndex      v6/routes/basepro.php:235
  │ if ($slug === 'perguntas-frequentes') return $this->returnIndex('Perguntas Frequentes', $slug);
  ▼
view('prefecture.contents.perguntas-frequentes.index')  + DataTable AJAX
  │ GET /cms/datatable/perguntas_frequentes
  ▼
DatatableController@get_perguntas_frequentes                          v6/app/Http/Controllers/Prefecture/DatatableController.php:216-220
  │ DB::table("perguntas_frequentes")->get()   ← view SQL
  │ struct_views($dados, 'perguntas-frequentes') → flags de permissão
  ▼
JSON server-side (yajra/laravel-datatables-oracle)
```

Cadastro/edição:

```
POST /cms/conteudo            (Route::resource('conteudo'))           v6/routes/basepro.php:174
PUT  /cms/conteudo/{id}
  ▼
ContentController@store / @update
  │ ContentRequest → slug 'perguntas-frequentes' cai no bloco default:
  │   title required|max:120 ; category_contents_id required|numeric
  ▼
Content::create / update → contents
```

## 4. Classes envolvidas

| Classe | Caminho | Papel |
|---|---|---|
| `Portal\QuickAccessController` | `v6/app/Http/Controllers/Portal/QuickAccessController.php` | Serve `/acesso-rapido/{slug}`; decide entre conteúdo e página estática |
| `Portal\CommonQuestionsController` | `v6/app/Http/Controllers/Portal/CommonQuestionsController.php` | **Código morto**: `index()` renderiza `portal.layouts.default.pages.common-questions`, view inexistente e controller sem rota |
| `App\Http\Traits\GetInformationsPrefectureTrait` | `v6/app/Http/Traits/GetInformationsPrefectureTrait.php` | `getContentByCategory($param)` (linhas 28-33) e `getTemplateActived()` (linhas 92-102) |
| `Prefecture\ContentController` | `v6/app/Http/Controllers/Prefecture/ContentController.php` | CRUD genérico: `genericIndex` (linha 97), `genericGenerate` (linha 170) |
| `Prefecture\DatatableController` | `v6/app/Http/Controllers/Prefecture/DatatableController.php` | `get_perguntas_frequentes` (linhas 216-220) |
| `App\Http\Requests\ContentRequest` | `v6/app/Http/Requests/ContentRequest.php` | Regras (bloco `default:`, linhas 308-314) |
| `App\Prefecture\Content` | `v6/app/Http/Model/Prefecture/Content.php` | Model da pergunta/resposta (`title`, `text`, `categoryContents()`) |
| `App\Prefecture\CategoryContent` | `v6/app/Http/Model/Prefecture/CategoryContent.php` | Categoria da FAQ (`scopeBySlug`, linhas 164-167) |
| `App\Http\Filter\FilterSearchAllSite` | `v6/app/Http/Filter/FilterSearchAllSite.php` | Busca global que inclui `perguntas-frequentes` (linha 29) |
| `Portal\PortalController` | `v6/app/Http/Controllers/Portal/PortalController.php` | `contentList` (linha 323: redireciona para `acesso-rapido.index`), `getViewToBeReturned` (linha 401: `12 => 'perguntas-frequentes.show'`) |

## 5. Dependências externas

| Pacote | Uso |
|---|---|
| `yajra/laravel-datatables-oracle` | DataTable server-side do CMS |
| `laravelcollective/html` | `Form::text` / `Form::textarea` no formulário do CMS |
| `cartalyst/sentinel` | `has_access(['perguntas-frequentes.*'])` |
| jquery | Filtro client-side da lista no portal |
| `laracasts/presenter` | `PresentableTrait` + `ContentPresenter` |

## 6. Diagrama de dependências (Mermaid)

```mermaid
graph TD
  R1["web.php: /acesso-rapido/{slug}"] --> QAC[QuickAccessController]
  QAC --> GIT[GetInformationsPrefectureTrait]
  GIT --> C[App\Prefecture\Content]
  R2["basepro.php: /cms/conteudos/perguntas-frequentes"] --> CTC[ContentController]
  CTC --> CR[ContentRequest]
  CTC --> C
  R3["basepro.php: /cms/datatable/perguntas_frequentes"] --> DTC[DatatableController]
  DTC --> V[(view SQL perguntas_frequentes)]
  R4["basepro.php: resource conteudo"] --> CTC
  R5["web.php: /buscar e /buscando"] --> PC[PortalController]
  PC --> FSA[FilterSearchAllSite]
  FSA --> C
  R6["web.php: /portal/perguntas-frequentes"] -.-> PC
  DEAD["CommonQuestionsController (sem rota)"] -.-> DEADVIEW["view inexistente"]
  C --> T[(contents)]
  V --> T
  V --> T2[(category_contents)]
```

## 7. Observações de arquitetura

- O módulo **não** tem model, service, repository ou policy próprios: é um consumidor
  do CRUD genérico de `contents` e do `QuickAccessController`.
- O mesmo controller serve "acesso rápido", "ouvidoria", "solicitar informação" e FAQ:
  a diferenciação é feita pelo **nome do arquivo de view** igual ao slug.
- A listagem do CMS usa view SQL; a do portal usa Eloquent. As duas fontes podem divergir
  (a view não filtra `status`).
- O `CommonQuestionsController` é a evidência de uma refatorização interrompida: ele
  renderizaria uma tela de FAQ com `$selectQuestions = 'sel-shortcuts'`, mas a view
  `portal.layouts.default.pages.common-questions` foi removida e o controller ficou sem rota.
