# Outras Configurações — Arquitetura

> Módulo `outras-configuracoes` (`modulos.id = 4`). Sem controller, model,
> tabela, request ou view exclusivos: tudo é compartilhado com
> `configuracoes-da-instituicao` (`../configuracoes-da-instituicao/`).

---

## 1. Fluxo da requisição

O módulo produz três fluxos distintos, todos nascendo em
`v6/app/Http/Controllers/Prefecture/ConfigurationController.php`.

### 1.1 Fluxo "abrir o módulo" (menu → listagem)

```
[Sidebar CMS]  v6/resources/views/vendor/adminlte/page.blade.php:254
      |  has_access(['outros.index']) && $modulos['outras-configuracoes']
      v
GET /cms/configuracoes/editar/outros        (edit.configuracoes.by.category)
      |  middleware check.logged
      v
ConfigurationController@editByCategory('outros')
      |  $reference = 'outros'; $acess = 'outros'
      |  $configurations = getConfiguration('outros')   -> coleção VAZIA
      |  $category = CategoryConfiguration::where('slug','outros')->first()
      |  $states = DB::table('states')->get()            (consulta não utilizada)
      |  has_access(['outros.edit'])  -> se falso: redirect dashboard.index
      |  switch ($slug): case 'outros' -> return $this->index()
      v
ConfigurationController@index()
      |  has_access(['outros.index'])  -> se falso: redirect dashboard.index
      |  $configurations = getConfiguration('outros')     -> coleção VAZIA
      |  configurationLog('Listou configurações gerais')
      v
view('prefecture.configurations.index')   -> v6/resources/views/prefecture/configurations/index.blade.php
      |  <table id="tabela_configuracoes"> com <tbody> vazio
      v
GET /cms/datatable/configuracoes          (datatable.configuracoes)  [AJAX]
      v
DatatableController@get_configuracoes()
      |  $configuracoes = DB::table("configuracoes")->get()   // VIEW SQL, todas as categorias
      |  struct_views($configuracoes, 'configuracoes')         // injeta edit/delete/active/inactivate
      v
DataTables::of(...)->make(true)  ->  JSON  ->  DataTable no navegador
```

**Ponto central do módulo**: o `<tbody>` é preenchido **exclusivamente** pela
resposta AJAX. A variável `$configurations` (categoria `outros`, vazia) chega
à view mas **não é renderizada** em lugar nenhum de
`v6/resources/views/prefecture/configurations/index.blade.php`. Logo, o operador
vê as 87 configurações de todas as categorias.

### 1.2 Fluxo "criar configuração"

```
GET /cms/configuracoes/create   (configuracoes.create)
      |  middleware check.logged
      v
ConfigurationController@create()
      |  Sentinel::check()          -> se falso: redirect dashboard.index
      |  Sentinel::inRole('super-admin') -> se falso: flash + redirect dashboard.index
      |  $categories = CategoryConfiguration::all()->pluck('name','id')
      |  activity()->performedOn(...)->log('Acesso cadastro de configuração gerais')
      v
view('prefecture.configurations.create')  -> inclui form.blade.php
      |  Form::open(['route' => ['configuracoes.index'], 'files' => true])
      v
POST /cms/configuracoes          (configuracoes.store)
      v
ConfigurationRequest::rules()   (regras estáticas)
      v
ConfigurationController@store()
      |  DB::transaction(...)
      |    key = str_slug($request->get('key'), '_')
      |    upload -> 'configuracoes/' . 'file_' . str_random(4) . nomeOriginal
      |    Configuration::create($configuration)
      |  flash('Configuração cadastrada com sucesso.')
      v
redirect -> configuracoes.index
```

### 1.3 Fluxo "editar / excluir"

```
GET /cms/configuracoes/{id}/edit  (configuracoes.edit)   -> super-admin
PUT /cms/configuracoes/{id}       (configuracoes.update) -> super-admin (via form)
      |  ConfigurationRequest::rules()  (route configuracoes.update)
      |  value opcional quando type == 'file'
      v
ConfigurationController@update()
      |  $configuration = $request->all()   // atualiza TODOS os campos enviados
      |  key = str_slug($configuration['key'], '_')
      |  upload -> 'configuracoes/img_' . date('YmdHi') . str_random(4) . '.' . ext
      |  Storage::delete("/" . $fileOld)
      v
redirect -> configuracoes.edit

DELETE /cms/configuracoes/{id}    (configuracoes.destroy)
      v
ConfigurationController@destroy()
      |  Configuration::destroy($id)   // SoftDeletes
      v
JSON 200 {"success": "Configuração deletada com sucesso."} | JSON 500 {"erro": "..."}
```

## 2. Classes envolvidas

| Classe | Caminho | Papel |
|---|---|---|
| `App\Http\Controllers\Prefecture\ConfigurationController` | `v6/app/Http/Controllers/Prefecture/ConfigurationController.php` | Todo o comportamento do módulo (856 linhas) |
| `App\Http\Controllers\Prefecture\DatatableController` | `v6/app/Http/Controllers/Prefecture/DatatableController.php` | `get_configuracoes()` (linha 384) e `struct_views()` (linha 504) |
| `App\Prefecture\Configuration` | `v6/app/Http/Model/Prefecture/Configuration.php` | Model da tabela `configurations` (classe fora do namespace de pasta, por classmap) |
| `App\Http\Model\Prefecture\CategoryConfiguration` | `v6/app/Http/Model/Prefecture/CategoryConfiguration.php` | Model da tabela `category_configurations` |
| `App\Http\Requests\ConfigurationRequest` | `v6/app/Http/Requests/ConfigurationRequest.php` | Regras estáticas e dinâmicas |
| `App\Http\Traits\GetInformationsPrefectureTrait` | `v6/app/Http/Traits/GetInformationsPrefectureTrait.php` | `getConfiguration($reference)` |
| `App\Http\Traits\FileTrait` | `v6/app/Http/Traits/FileTrait.php` | `getFileName()` |
| `App\Http\Model\Admin\Modulos` | `v6/app/Http/Model/Admin/Modulos.php` | Injetado na sidebar (`@inject('modulos', ...)`) |
| `App\Http\Controllers\Admin\ModulosController` | `v6/app/Http/Controllers/Admin/ModulosController.php` | Tela `/cms/modulos` que liga/desliga o módulo |
| `App\Providers\ModulosServiceProvider` | `v6/app/Providers/ModulosServiceProvider.php` | `Cache::rememberForever('modulos', ...)` e composers parciais |

## 3. Diagrama de dependências

```
            ┌───────────────────────────────┐
            │  modulos (id 4)              │
            │  slug=outras-configuracoes    │
            └───────────┬───────────────────┘
                        │ modulo_id
            ┌───────────▼───────────────────┐
            │  resources (slug=outros)      │
            │  → outros.index / outros.edit │
            └───────────┬───────────────────┘
                        │ permissão (Sentinel)
        ┌───────────────▼──────────────────────────────────┐
        │  page.blade.php (sidebar AdminLTE)              │
        │  has_access(['outros.index'])                   │
        │    && $modulos['outras-configuracoes']          │
        └───────────────┬──────────────────────────────────┘
                        │ route('edit.configuracoes.by.category','outros')
        ┌───────────────▼──────────────────────────────────┐
        │  ConfigurationController@editByCategory          │
        │  → case 'outros' → $this->index()               │
        └───────────────┬──────────────────────────────────┘
                        │
   ┌────────────────────┴────────────────────┐
   │                                         │
┌──▼──────────────────────┐      ┌───────────▼─────────────────────┐
│ index()                  │      │ DatatableController            │
│ getConfiguration('outros')│      │ @get_configuracoes()          │
│ → coleção VAZIA          │      │ DB::table('configuracoes')    │
│ (não usada na view)      │      │ → VIEW SQL (todas categorias) │
└──┬───────────────────────┘      └───────────┬─────────────────────┘
   │ view index.blade.php                      │ JSON
   └───────────────────────────────────────────┘
```

## 4. Dependências externas (composer)

| Pacote | Uso no módulo |
|---|---|
| `laravel/framework` 5.5.50 | Rotas, controller, Eloquent, Form Request, `Storage`, `DB` |
| `yajra/laravel-datatables-oracle` | `DataTables::of(...)->make(true)` em `get_configuracoes()` |
| `cartalyst/sentinel` | `Sentinel::check()`, `Sentinel::inRole('super-admin')`, `hasAnyAccess`/`hasAccess` |
| `spatie/laravel-activitylog` (ou equivalente em uso) | `activity()->performedOn(...)->log(...)` nos métodos do controller |
| `intervention/image` | Importado no controller, mas não usado no caminho de `outros` |

## 5. Onde o módulo se encaixa na plataforma

| Camada | Ponto de integração |
|---|---|
| Autenticação | `check.logged` nas rotas do resource e da edição por categoria |
| Autorização | `has_access()` em `v6/app/Library/Helper/appHelpers.php` (linha 22) |
| Cache | `Cache::rememberForever('modulos', ...)` em `v6/app/Providers/ModulosServiceProvider.php` |
| Storage | Disco `public`, subdiretório `configuracoes/` para arquivos de configuração |
| Logs | `activity()` em `configurationLog()` e nos métodos de CRUD |
| Portal público | Nenhuma rota pública do portal usa a categoria `outros`; o efeito das chaves é indireto, por `ConfigHeaderServiceProvider` (`v6/app/Providers/ConfigHeaderServiceProvider.php`) |

## 6. Ordem real de resolução de dependências

1. `has_access(['outros.index'])` decide a **visibilidade** do menu.
2. `$modulos['outras-configuracoes']` decide a **ativação** do menu (ligado/desligado
   em `/cms/modulos`).
3. `has_access(['outros.edit'])` decide o **acesso ao clique**.
4. `Sentinel::inRole('super-admin')` decide o acesso a **criação e edição** de
   configuração.
5. `has_access(['configuracoes.edit'])` decide o **acesso à gravação** pela rota
   `update.configurations.by.category` — permissão única, compartilhada com
   `configuracoes-da-instituicao` (`../configuracoes-da-instituicao/`).

> A permissão de leitura (`outros.edit`) e a de gravação (`configuracoes.edit`)
> são **assimétricas**: um usuário pode ler "Outras Configurações" e não
> gravar; e um usuário com `configuracoes.edit` grava em qualquer categoria.
> Detalhamento em `05-REGRAS-E-PORTABILIDADE.md`.
