# Transparência Fiscal — Arquitetura

> Escopo: módulo `transparencia-fiscal` na `v6` (Laravel 5.5.50).

---

## 1. Visão geral das camadas

O módulo **não possui repository, service ou Form Request próprios** (ao contrário do
módulo Diário Oficial). Ele reaproveita três mecanismos genéricos do CMS:

| Camada | Peça | Caminho |
|---|---|---|
| Rotas (portal) | `routes/web.php` | `v6/routes/web.php:20`, `:70`, `:165-176` |
| Rotas (CMS) | `routes/basepro.php` | `v6/routes/basepro.php:235-241`, `:413` |
| Controller (portal) | `Portal\TransparencyController` | `v6/app/Http/Controllers/Portal/TransparencyController.php` |
| Controller (CMS) | `Prefecture\ContentController`, `Prefecture\CategoryContentController`, `Prefecture\DatatableController` | `v6/app/Http/Controllers/Prefecture/` |
| Service (externo) | `PortalTransparenciaService` | `v6/app/Services/PortalTransparenciaService.php` |
| Models | `Content`, `CategoryContent`, `Link`, `InformationsRequest`, `Answer`, `StaticPage`, `Archive`, `Configuration` | `v6/app/Http/Model/Prefecture/` |
| Views SQL | `transparencia_fiscal` | migrations de 2023-04-11 a 2023-05-04 |
| Views (Blade) | `portal.layouts.{modelo}.transparencia-fiscal.*`, `prefecture.contents.transparencia-fiscal.*` | `v6/resources/views/` |
| Export | `App\Exports\InformationsRequestsExport` | `v6/app/Exports/InformationsRequestsExport.php` |
| Ajuda global | `has_access()`, `clean_slug()` | `v6/app/Library/Helper/appHelpers.php`, `v6/app/Helpers/functions.php` |

---

## 2. Classes envolvidas

### 2.1 Portal (público)

| Classe | Papel |
|---|---|
| `App\Http\Controllers\Portal\TransparencyController` | Controller único do módulo. Herda de `App\Http\Controllers\Admin\Controller` (apenas para herdar `getTemplateActived()` e traits de validação). Métodos: `index`, `subcategoria`, `show`, `relStatitics`, `getAnswers`, `export`, `exportTxt` |
| `App\Http\Controllers\Admin\Controller` | Base com `getTemplateActived()` — lê `configurations.key = 'layout'` e **aborta 404** (`view_inexistente`) se a view `portal.layouts.{layout}.home.index` não existir; também força `pagina_em_manutencao = 1` nesse caso |
| `App\Prefecture\CategoryContent` | Categorias (pastas) e a raiz `transparencia-fiscal` |
| `App\Prefecture\Content` | Itens de transparência (`title`, `icon`, `order`, `status`, `referencia`, `slug`) |
| `App\Prefecture\Link` | URL + `isBlank` do item, relação `hasOne` via `Content::linksUnique` |
| `App\Prefecture\InformationsRequest` | Pedidos de informação do e-SIC (LAI). Usa `DataMaskTrait` e `SoftDeletes` |
| `App\Prefecture\Answer` | Respostas do e-SIC; `belongsToMany` `archives` pela pivot `answer_archives` |
| `App\Prefecture\StaticPage` | Página estática `relatorio-estatistico` (texto, layout, breadcrumbs) |
| `App\Prefecture\Archive` | Anexos da página estática (`highlight IS NULL`) e PDF visualizável (`view_pdf = true`) |
| `App\Prefecture\Configuration` | Chave/valor das configurações do sistema |
| `App\Prefecture\Status` | Status do e-SIC; usa `ContentPresenter` para `present()->textColor` |
| `App\Exports\InformationsRequestsExport` | Export `FromView` (usa `exports.informations-requests`) |

### 2.2 CMS (painel)

| Classe | Papel |
|---|---|
| `App\Http\Controllers\Prefecture\ContentController` | CRUD genérico de conteúdos. `genericIndex`/`genericCreate`/`genericEdit` roteiam pelo `slug` `transparencia-fiscal`; `store`/`update` gravam `contents` + `links` |
| `App\Http\Controllers\Prefecture\CategoryContentController` | CRUD das categorias (subpastas) de transparência |
| `App\Http\Controllers\Prefecture\DatatableController` | `get_transparencia_fiscal()` — lê a view SQL e monta o payload do DataTables |
| `App\Http\Requests\ContentRequest` | Regras de validação do formulário de transparência (case `transparencia-fiscal`) |
| `App\Http\Requests\CategoryContentRequest` | Regra especial: `description` `nullable|max:500` quando o pai é `transparencia-fiscal` |
| `App\Http\Model\Prefecture\Content` | Model de `contents` (fillable, `SoftDeletes`, presenter `ContentPresenter`) |
| `App\Http\Model\Prefecture\CategoryContent` | Model de `category_contents` (auto-relacionamento `category_contents_id`) |

### 2.3 Serviço de integração externa

| Classe | Papel |
|---|---|
| `App\Services\PortalTransparenciaService` | Integra a busca geral do portal com o **Portal da Transparência externo** (provedor fixo `elmar`). Cache de 600 s da configuração, catálogo de 33 páginas (despesas, receitas, licitações, folha, RREO/RGF/PCA/PPA). **Não é usado por `TransparencyController`** — é acionado por `Portal\PortalController@searchContents`/`searchingContents` |

---

## 3. Fluxo de requisição

### 3.1 Portal — índice da transparência

```
GET /transparencia-fiscal
  → Route::middleware(['check.site.manutention'])            (v6/routes/web.php:7)
  → Portal\TransparencyController@index
      → Configuration('layout') via getTemplateActived()
      → CategoryContent::where('slug','transparencia-fiscal')->first()   (fallback id 25)
      → CategoryContent::where('category_contents_id',$id)->orderBy('order')      [pastas]
      → Content::with(['categoryContents','linksUnique'])
            ->where(whereHas categoryContents = $id OR category_contents_id = $id)
            ->where('status',true)->orderBy('order')                             [itens]
      → view portal.layouts.{layout}.transparencia-fiscal.index
```

### 3.2 Portal — item (show)

```
GET /transparencia-fiscal/{slug}
  → TransparencyController@show
      → Content::where('slug',$slug)->with('linksUnique')->first()
      → CategoryContent::where('category_contents_id',$id)->get()
      → view portal.layouts.{layout}.transparencia-fiscal.show
          → <iframe src="{{ $transparencia->linksUnique['link'] }}">
```

### 3.3 Portal — relatório estatístico

```
GET /relatorio-estatistico?ano=2024[&type=xls|csv|pdf|txt]
  → TransparencyController@relStatitics
      → StaticPage::where('slug','relatorio-estatistico')->first()
      → Archive (destaques + view_pdf) da página
      → $content->increment('clicks')
      → InformationsRequest::with('person','status')->byDateBetweenMain($ano)->get()
      → 8 contagens (getByBetweenDate / getByBetweenDateWithAnswer)
      → Configuration('full_list_requests_disabled')
      → se $request->filled('type'): return $this->export($informationRequests, $type)
      → view portal.layouts.{layout}.transparencia-fiscal.relatorio-estatistico.index
```

### 3.4 Portal — Ajax de respostas

```
POST /AjaxGetanswers   {_token, id}
  → TransparencyController@getAnswers
      → InformationsRequest::with('answers')->where('id',$request->id)->first()
      → Answer::with('archives')->where('informations_request_id',$request->id)->get()
      → JSON { request: {protocol, mask_request, status_id}, answers: [...] }
```

### 3.5 CMS — listagem

```
GET /cms/conteudos/transparencia-fiscal
  → ContentController@genericIndex('transparencia-fiscal')   (middleware check.route.permission)
      → generateLog('Transparência Fiscal'); menuClicks('transparencia-fiscal')
      → view prefecture.contents.transparencia-fiscal.index
          → DataTables (assets/js/custom/contents/transparencia-fiscal/datatable.js)
              → GET /cms/datatable/transparencia_fiscal
                  → DatatableController@get_transparencia_fiscal
                      → DB::table('transparencia_fiscal')->get()      [view SQL]
                      → struct_views($data,'transparencia-fiscal')    [flags edit/delete/active/inactivate]
```

### 3.6 CMS — gravação

```
POST /cms/conteudos/... (store)  |  PUT /cms/conteudos/... (update)
  → ContentRequest (case 'transparencia-fiscal')
  → ContentController@store / @update
      → DB::transaction
          → grava contents (title, icon, order, status, referencia, category_contents_id)
          → reordena: incrementa order dos itens com order >= novo order (exceto super-banners)
          → cria/atualiza links (link, isBlank, alt = title)
      → activity()->performedOn(...)
```

---

## 4. Diagrama (Mermaid)

```mermaid
flowchart TD
  subgraph Portal
    W[v6/routes/web.php]
    TC[Portal\TransparencyController]
    BR[Blade portal.layouts.*.transparencia-fiscal.*]
    IR[InformationsRequest / Answer / Archive / StaticPage]
    EX[InformationsRequestsExport + dompdf + Excel]
  end
  subgraph CMS
    B[v6/routes/basepro.php]
    CC[Prefecture\ContentController]
    CCC[Prefecture\CategoryContentController]
    DT[Prefecture\DatatableController]
    CR[ContentRequest / CategoryContentRequest]
    BCMS[Blade prefecture.contents.transparencia-fiscal.*]
  end
  DB[(PostgreSQL<br/>contents, category_contents, links,<br/>informations_requests, answers,<br/>view transparencia_fiscal)]
  W --> TC
  TC --> BR
  TC --> IR
  TC --> EX
  B --> CC
  B --> CCC
  B --> DT
  CC --> CR
  CC --> BCMS
  DT --> BCMS
  IR --> DB
  CC --> DB
  DT --> DB
```

---

## 5. Dependências externas (composer)

| Pacote | Versão em `v6/composer.json` | Uso no módulo |
|---|---|---|
| `maatwebsite/excel` | `^3.1` | Exportação XLS/CSV do relatório (`Excel::download`) |
| `barryvdh/laravel-dompdf` | `^0.8.7` | Exportação PDF (`PDF::loadView('exports.informations-requests')`) |
| `dompdf/dompdf` | `^0.8.3` | Motor do PDF |
| `yajra/laravel-datatables` | `^1.5` | DataTable do CMS |
| `cartalyst/sentinel` | `2.0.*` | Sessão e permissões (`has_access`) |
| `laracasts/presenter` | — | `ContentPresenter` (cores de status, datas) |
| `spatie/laravel-activitylog` | — | Log das alterações no CMS |

---

## 6. Observações de arquitetura

1. **Ausência de repository**: o módulo escreve direto em `contents`/`links` pelo
   `ContentController`, que é genérico e compartilhado com ~25 outros módulos de conteúdo.
   Qualquer mudança no `store`/`update` afeta todos eles.
2. **Ausência de service no portal**: a lógica de listagem está inline no controller,
   duplicada em `index`, `subcategoria`, `show` e em `PortalController` (que refaz a mesma
   busca de categoria raiz para a home).
3. **Duplicação do id da raiz**: o literal `25` aparece como fallback em
   `v6/app/Http/Controllers/Portal/TransparencyController.php` (3×),
   `v6/app/Http/Controllers/Prefecture/CategoryContentController.php` (3×) e
   `v6/app/Http/Controllers/Prefecture/ContentController.php` (3×).
4. **View SQL como contrato de leitura**: o CMS depende da forma exata das colunas
   (`titulo`, `category_name`, `status_name`) consumidas por
   `v6/public/assets/js/custom/contents/transparencia-fiscal/datatable.js`.
