# Configurações da Instituição — Arquitetura

> Módulo `configuracoes-da-instituicao` (tabela `modulos`, id 1).
> Sem controller/model/tabela próprios: reuso do `ConfigurationController`.

---

## 1. Camadas envolvidas

### 1.1 Fluxo de leitura (GET)

```
GET /cms/configuracoes/editar/configuracoes
  │
  ├─ Route::group(['prefix' => 'cms', 'before' => 'csrf'])      v6/routes/basepro.php:35
  │    └─ Route::get('configuracoes/editar/{slug}')             v6/routes/basepro.php:241
  │         name: edit.configuracoes.by.category
  │         middleware: check.logged
  │
  ├─ check.logged  → exige sessão Sentinel válida
  │
  └─ Prefecture\ConfigurationController@editByCategory($slug='configuracoes')
       │  v6/app/Http/Controllers/Prefecture/ConfigurationController.php:437
       │
       ├─ $reference = 'site'        (slug 'configuracoes' → categoria 'site')
       ├─ $acess     = 'configuracoes' (permissão exigida: configuracoes.edit)
       │
       ├─ $configurations = GetInformationsPrefectureTrait::getConfiguration('site')
       │      v6/app/Http/Traits/GetInformationsPrefectureTrait.php:65
       │      → Configuration::whereHas('categoryConfiguration', slug=site)
       │                ->orderBy('order')->get()
       │
       ├─ $category = CategoryConfiguration::where('slug','site')->first()
       ├─ $states   = DB::table('states')->get()
       │
       ├─ has_access(['configuracoes.edit'])  → senão redirect dashboard.index
       │
       └─ case 'configuracoes':
            $dashboardConfigs = Configuration::whereIn('key', array(
                'dashboard_enhanced_enabled',
                'google_analytics_property_id',
                'google_analytics_measurement_id',
                'google_analytics_sa_json',
                'dashboard_widget_refresh_minutes',
                'dashboard_widgets_enabled',
            ))->get()->keyBy('key')
            $configRepository = app(ConfigurationRepository::class)
            $enabledWidgets   = $configRepository->getEnabledWidgets()
            $dashboardWidgets = WidgetRegistry::configList()
            $canEditDashboard = has_access(['dashboard-config.edit'])
            → view('prefecture.configurations.configuracoes.edit', compact(
                 'configurations','category','states','dashboardConfigs',
                 'enabledWidgets','dashboardWidgets','canEditDashboard'))
```

### 1.2 Fluxo de gravação (POST)

```
POST /cms/update/configuration
  │  name: update.configurations.by.category     v6/routes/basepro.php:246
  │  (rota NÃO tem middleware 'check.logged'; a proteção é has_access no controller)
  │
  └─ ConfigurationController@updateByCategory(ConfigurationRequest $request)
       v6/app/Http/Controllers/Prefecture/ConfigurationController.php:233
       │
       ├─ has_access(['configuracoes.edit'])  → senão redirect dashboard.index
       ├─ $category = CategoryConfiguration::find($request->category_configurations_id)
       ├─ $dataForm = $request->except('_token','category_configurations_id','display')
       │
       ├─ [categoria 'site']
       │    ├─ converte app_env → 'local'|'prod', app_debug → 'true'|'false'
       │    ├─ monta $array = [0=>mail_*, 1=>recaptcha_*, 2=>app_*]
       │    ├─ file_put_contents(base_path()."/config.json", json_encode(['config'=>$array]))
       │    └─ echo "JSON file created successfully...";   ← saída antes do redirect
       │
       ├─ valida 'layout' ∈ {modelo1..modelo6} (se enviado)
       ├─ [categoria 'site'] extractGaData($request,$dataForm)      → pode abortar
       ├─ [categoria 'site'] extractDashboardData($request,$dataForm) → pode abortar
       │
       ├─ [chave 'selos_institucionais'] grava JSON dos selos + selos_institucionais_url
       │
       └─ foreach ($dataForm as $key => $value)
            ├─ $config = Configuration::where('key',$key)->first()
            ├─ [upload] Intervention Image: resize 275 (largura) ou 75 (altura)
            │            → storage/app/public/configuracoes/<nome>
            ├─ $config->value = 'configuracoes/' . $name;  (upload)  ou  $config->value = $value;
            ├─ $config->save()
            ├─ activity()->performedOn($config)->log('Edição de configuração')
            ├─ Cache::pull('structureType')
            └─ [chave portal_transparencia_*] Cache::pull(PortalTransparenciaService::CACHE_KEY)
       │
       └─ redirect()->back()->with('display', $request->display)
```

### 1.3 Diagrama Mermaid

```mermaid
flowchart TD
    A[GET /cms/configuracoes/editar/configuracoes] --> B[check.logged]
    B --> C[ConfigurationController@editByCategory]
    C --> D[getConfiguration 'site']
    D --> E[(configurations JOIN category_configurations)]
    C --> F[ConfigurationRepository / WidgetRegistry]
    F --> E
    C --> G[View prefecture.configurations.configuracoes.edit]
    G --> H[8 abas por faixa de order]

    I[POST /cms/update/configuration] --> J[ConfigurationRequest rules dinâmicas]
    J --> K[ConfigurationController@updateByCategory]
    K --> L[has_access configuracoes.edit]
    L --> M[grava config.json]
    L --> N[extractGaData / extractDashboardData]
    N --> O[update configurations]
    O --> P[(configurations)]
    O --> Q[Cache::pull structureType / portal_transparencia_config]
    K --> R[redirect back with display]
```

## 2. Classes envolvidas

| Classe / arquivo | Papel |
|---|---|
| `v6/app/Http/Controllers/Prefecture/ConfigurationController.php` | Controller único dos 4 módulos de configuração (`configuracoes`, `temas`, `outros`, `barra-privacidade`). 856 linhas. |
| `v6/app/Http/Requests/ConfigurationRequest.php` | Validação. Regras dinâmicas por chave na rota `update.configurations.by.category`. |
| `v6/app/Http/Model/Prefecture/Configuration.php` | Model `App\Prefecture\Configuration`, tabela `configurations`, `SoftDeletes`, `$fillable` com 14 colunas. |
| `v6/app/Http/Model/Prefecture/CategoryConfiguration.php` | Model `App\Http\Model\Prefecture\CategoryConfiguration`, tabela `category_configurations`. |
| `v6/app/Http/Traits/GetInformationsPrefectureTrait.php` | `getConfiguration($reference)` — carrega as configurações de uma categoria por `whereHas`. |
| `v6/app/Http/Traits/FileTrait.php` | `getFileName($file)` — `uniqid('',false) . str_random(5) . '.' . extensão`, em minúsculas. |
| `v6/app/Http/Traits/DataMaskTrait.php` | `maskTextWithAi()` — usa `gemini_api_key` (configuração `site`) para anonimizar dados pessoais. |
| `v6/app/Services/Dashboard/ConfigurationRepository.php` | Leitura/escrita das chaves do Dashboard e GA; `set()`, `setSecret()`, `secret()`, cache estático por processo. |
| `v6/app/Services/Dashboard/WidgetRegistry.php` | Whitelist de widgets do Dashboard; `available()` e `configList()`. |
| `v6/app/Services/PortalTransparenciaService.php` | Consome `portal_transparencia_*`; `CACHE_KEY = 'portal_transparencia_config'`, cache de 600 s. |
| `v6/app/Providers/ConfigHeaderServiceProvider.php` | Composer que injeta `$configHeader` com 33 chaves (inclui `titulo_site`, `palavras_chaves`, `favicon`, `logo`, `codigo_tempo`) nas views do portal. |
| `v6/app/Providers/FooterServiceProvider.php` | Composer que injeta `$configFoot` (`expediente`, `numero_versao`, `incorporacao_head`, `incorporacao_rodape`). |
| `v6/app/Providers/MenuServiceProvider.php` | Lê `menu_interativo` e `contact_link`. |
| `v6/app/Http/Controllers/Admin/ModulosController.php` | Grava `structure_type` e o status dos módulos. |
| `v6/app/Http/Controllers/Portal/SelosController.php` | Renderiza os selos institucionais no portal (`GET /selos`). |
| `v6/app/Http/Middleware/CheckSiteManutention.php` | Aplica `pagina_em_manutencao` a visitantes não logados. |
| `v6/app/Http/Controllers/Prefecture/DatatableController.php` | `get_configuracoes()` — lista a view SQL `configuracoes` (todas as categorias). |
| `v6/app/Library/Helper/appHelpers.php` | `has_access()` (linha 22) — checagem de permissão base do CMS. |

## 3. Diagrama de dependência (quem lê o que)

| Chave | Consumidor principal |
|---|---|
| `structure_type` | `v6/app/Http/Controllers/Admin/ModulosController.php`, `v6/resources/views/admin/modulos/form.blade.php` |
| `titulo_site` | `v6/app/Http/Controllers/Portal/ContactController.php`, `v6/app/Http/Controllers/Portal/InformationController.php` |
| `palavras_chaves`, `descricao` | `v6/resources/views/portal/layouts/modelo1/layout/head.blade.php`, `v6/resources/views/portal/layouts/default/master.blade.php` |
| `incorporacao_head`, `incorporacao_rodape` | `v6/resources/views/portal/layouts/modelo1/layout/head.blade.php`, `v6/resources/views/portal/layouts/modelo1/layout/scripts.blade.php` |
| `logo`, `favicon`, `background` | `v6/app/Providers/ConfigHeaderServiceProvider.php` |
| `expediente`, `numero_versao` | `v6/app/Providers/FooterServiceProvider.php` |
| `codigo_tempo` | `v6/resources/views/components/weather-box.blade.php` |
| `noticias`, `ultimas_noticias`, `newsletters` | `v6/app/Helpers/functions.php` (`getStatusDisplayNews`, `getStatusDisplayNewsletters`), `v6/app/Http/Controllers/Portal/PortalController.php` |
| `links_rapidos` | `v6/resources/views/portal/layouts/modelo1/home/acesso-rapido.blade.php` e equivalentes |
| `contact_link` | `v6/app/Providers/MenuServiceProvider.php` |
| `menu_interativo` | `v6/app/Providers/MenuServiceProvider.php` |
| `pagina_em_manutencao` | `v6/app/Http/Middleware/CheckSiteManutention.php` |
| `email_lai` | `v6/app/Http/Controllers/Portal/InformationController.php` |
| `nome_prefeito` | `v6/app/Http/Controllers/Prefecture/QuestionAnswersController.php` |
| `response_time` | `v6/app/Http/Controllers/Portal/OmbudsmanController.php` |
| `full_list_requests_disabled` | `v6/app/Http/Controllers/Portal/OmbudsmanController.php`, `v6/app/Http/Controllers/Portal/TransparencyController.php` |
| `gemini_api_key` | `v6/app/Http/Traits/DataMaskTrait.php` |
| `portal_transparencia_*` | `v6/app/Services/PortalTransparenciaService.php` |

## 4. Dependências externas

| Pacote / lib | Uso no módulo |
|---|---|
| `cartalyst/sentinel` | `has_access()`, `Sentinel::check()`, `Sentinel::inRole('super-admin')`. |
| `intervention/image` | Redimensionamento de logo/favicon/aviso (275px largura ou 75px altura). |
| `spatie/laravel-activitylog` | Registro de “Edição de configuração” por chave alterada. |
| `laravel/framework` (`Illuminate\Support\Facades\Crypt`) | Criptografia da Service Account JSON do GA (`setSecret`). |
| `predis` / Redis + APCu | `Cache::rememberForever('modulos')` e `Cache::remember('portal_transparencia_config', 600, ...)`. |

## 5. Onde a v7 precisa divergir

| Ponto legado | Problema | Direção na v7 |
|---|---|---|
| `configurations` genérica | Chave/valor sem tipo real | Tabelas de domínio + `settings` tipada |
| `config.json` em disco | Arquivo gerado pelo CMS lido no boot | `.env` + cache de runtime; nada lido do disco a cada request |
| `order` numérico como taxonomia de UI | Faixas mágicas (`<= 11`, `19..23`) | Aba explicitada por coluna `settings_group` |
| `has_access()` em controller | Sem Policy | `Policy` com `UpdateInstitutionSettings` |
| `Configuration::where('key',$key)->first()` | Índice ausente | `unique` em `key` |
