# Servidor — Arquitetura

> **Módulo:** `servidor` (tabela `modulos`, id 35)
> **Escopo:** cadastro de servidores públicos (funcionários/prestadores) no CMS;
> consumo indireto pelo portal via Requerimento de Diárias.

---

## 1. Fluxo da requisição

### 1.1 Listagem (CMS)

```
GET /cms/servidor                        (Route::resource, v6/routes/basepro.php:204)
  └─ grupo ['prefix' => 'cms', 'before' => 'csrf'] + middleware web
     └─ Preface\ServidorController@index
        ├─ $this->table->all()   ← Servidor::all()   (consulta COMPLETA, não usada pela view)
        └─ view('prefecture.contents.servidor.index', ['title' => 'Servidor', 'content' => $this->table->all()])
           └─ <table id="tabela_servidor">    (só o esqueleto)
              └─ JS assets/js/custom/contents/servidor/datatable.js
                 └─ runDatatables('servidor', colunas, true, 'ASC', null, true)
                    └─ AJAX GET /cms/datatable/servidor
                       └─ Preface\DatatableController@get_servidor
                          ├─ DB::table('servidores')->get()   ← VIEW SQL, não a tabela
                          ├─ struct_views($data, 'servidor') → has_access('servidor.edit' / 'servidor.delete')
                          └─ Yajra DataTables::of($servidor)->make(true) → JSON
```

### 1.2 Cadastro / edição (CMS)

```
POST /cms/servidor          (servidor.store)   ─┐
PUT  /cms/servidor/{id}     (servidor.update)  ─┤
                                                 ▼
              Preface\ServidorController@store / @update
                ├─ ServidorRequest  → FormRequest: authorize() = true
                │    rules(): name, cpf (Validate_cpf), identidade, matricula, cargo
                ├─ $this->repository->upInsert($request [, $id])
                │    └─ App\Repositories\Repository::upInsert()
                │         ├─ DB::transaction(fn => $this->structureUpInsert($this->dataTrait($request)))
                │         │    └─ ServidorRepository::structureUpInsert()
                │         │         ├─ $fields = array_keys($request)
                │         │         └─ filter_request($request, $fields)  → vazios viram null
                │         └─ $this->getModel()->updateOrCreate(['id' => $id], $data)
                │              └─ App\Http\Model\Prefecture\Servidor  →  tabela `servidor`
                └─ flash('Registro cadastrado com sucesso.')->success()
                   redirect()->route('servidor.index')
```

> Observação: `Repository::upInsert` envolve o `updateOrCreate` em `catch (\Throwable $th) { dd($th); }`
> (`v6/app/Repositories/Repository.php:66-72`). Uma exceção **não** chega ao
> `catch (Exception $exception)` do controller: o usuário vê um dump de debug.

### 1.3 Exclusão individual

```
DELETE /cms/servidor/{id}      (servidor.destroy)
  └─ Preface\ServidorController@destroy
     ├─ $this->table->destroy($id)   → soft delete (deleted_at)
     └─ JSON {success: 'Servidor deletado com sucesso.'} | 500 {erro: 'Ocorreu um erro! Por favor entre em contato com o suporte técnico.'}
```

### 1.4 Exclusão em lote

```
POST /cms/servidor/destroyAll      (servidor.destroyAll)
  └─ Preface\ServidorController@destroyAll
     ├─ $this->repository->destroyAll($request->toDelete)
     │    └─ Repository::destroyAll()  → whereIn('id', $array)->delete()  (soft delete)
     └─ JSON {success: 'Servidores deletados com sucesso.'}
```

### 1.5 Consumo pelo portal (busca de diárias)

```
GET/POST /requerimento-de-diarias    (v6/routes/web.php:211, rota pública)
  └─ Portal\BuscaDiariasController@index
     ├─ RequerimentoDiarias::with('servidor', 'archives')
     ├─ if ($request->req_name): Servidor::whereRaw("translate(lower(name), 'àáâãäéèëêíìïîóòõöôúùüûçÇ', 'aaaaaeeeeiiiiooooouuuucc') ilike '%'.$request->req_name."%'")->pluck('id')
     ├─ if ($request->cpf):      Servidor::whereRaw("translate(lower(cpf), 'àáâãäéèëêíìïîóòõöôúùüûçÇ', 'aaaaaeeeeiiiiooooouuuucc') ilike '%'.$request->cpf."%'")->pluck('id')
     └─ view('portal.layouts.busca-diarias.show', ['diarias' => $diarias->paginate(10), 'lei_padrao' => $lei_padrao, 'model' => $this->getTemplateActived()])
```

### 1.6 Consumo pelo CMS de Requerimento de Diárias

```
GET /cms/requerimento-diarias/create
  └─ Preface\RequerimentoDiariasController@create
     ├─ $this->servidor = app(Servidor::class)
     ├─ 'servidores' => $this->servidor->all()      ← todos os servidores, sem paginação
     └─ view('prefecture.contents.requerimento-diarias.form')
            └─ @include('components.inputs.select', ['data' => $servidores, 'id' => 'id_servidor'])
```

## 2. Classes envolvidas

| Classe / arquivo | Papel |
|---|---|
| `v6/app/Http/Model/Prefecture/Servidor.php` | Model Eloquent do servidor. `SoftDeletes`, `protected $table = 'servidor'`, `$fillable` com 9 campos, relação `secretarias()` (`hasOne` para `App\Prefecture\Content`). |
| `v6/app/Http/Controllers/Prefecture/ServidorController.php` | Controller do CMS: `index`, `create`, `store`, `edit`, `update`, `destroy`, `destroyAll`. Usa `GetInformationsPrefectureTrait`. |
| `v6/app/Http/Controllers/Prefecture/Controller.php` | Controller base; registra `check.route.permission` (o `ServidorController` também o registra explicitamente). |
| `v6/app/Http/Requests/ServidorRequest.php` | Form Request com as regras de obrigatoriedade e a regra `Validate_cpf`. |
| `v6/app/Rules/Validate_cpf.php` | Regra de validação do CPF (usa `AppTrait::validar_cpf`). |
| `v6/app/Http/Traits/AppTrait.php` | `validar_cpf()` (linha 80) e `filter_request()` (linha 523), usados pelo repository. |
| `v6/app/Repositories/Eloquent/Prefecture/Servidor/ServidorRepository.php` | Implementação concreta do contrato; define apenas `structureUpInsert`. |
| `v6/app/Repositories/Contracts/IServidorRepository.php` | Contrato do repository — **interface vazia**, sem métodos. |
| `v6/app/Repositories/Repository.php` | Base com `upInsert`, `destroy`, `destroyAll`, `destroyWithRelation`. |
| `v6/app/Http/Controllers/Prefecture/DatatableController.php` | `get_servidor()` (linha 128) serve o JSON da listagem a partir da view `servidores`. |
| `v6/app/Http/Controllers/Prefecture/RequerimentoDiariasController.php` | Consumidor: monta o select de servidores no formulário de requerimento. |
| `v6/app/Http/Model/Prefecture/RequerimentoDiarias.php` | Relação `servidor` (`hasOne(Servidor::class, 'id', 'id_servidor')`). |
| `v6/app/Http/Controllers/Portal/BuscaDiariasController.php` | Consumidor público: filtra requerimentos por nome/CPF do servidor. |
| `v6/app/Http/Traits/GetInformationsPrefectureTrait.php` | `getContentByCategoryWith()` (linha 48) — carrega as secretarias. |
| `v6/app/Http/Model/Prefecture/Content.php` | Model de `contents` (usado como "secretaria" e como destino da relação). |
| `v6/app/Http/Model/Prefecture/MenuOrder.php` | `menu_orders` — alvo de `menuClicks('servidor')`. |
| `v6/app/Providers/MenuServiceProvider.php` | Cria o item de menu "Servidores" (`case 'servidor'`). |
| `v6/app/Library/Helper/appHelpers.php` | `has_access()` — controla os botões da listagem. |
| `v6/app/Http/Middleware/CheckRoutePermission.php` | Autorização por nome de rota. |

**Não existem** para este módulo: API Resource, presenter, policy, factory, seed de
servidores de exemplo e testes automatizados.

## 3. Diagrama de fluxo

```mermaid
graph TD
    A[Operador no CMS] -->|GET /cms/servidor| B[ServidorController@index]
    B --> C[view prefecture.contents.servidor.index]
    C --> D[JS contents/servidor/datatable.js]
    D -->|GET /cms/datatable/servidor| E[DatatableController@get_servidor]
    E --> F[(view SQL servidores)]
    E --> G[struct_views: has_access]
    G --> D

    A -->|GET /cms/servidor/create| H[ServidorController@create]
    H --> I[getContentByCategoryWith secretarias]
    I --> J[(contents / categoria secretarias)]
    H --> K[view prefecture.contents.servidor.create]

    A -->|POST /cms/servidor| L[ServidorRequest]
    L --> M[ServidorController@store]
    M --> N[ServidorRepository::upInsert]
    N --> O[filter_request: vazios viram null]
    O --> P[(tabela servidor)]

    A -->|PUT /cms/servidor/id| Q[ServidorController@update]
    Q --> L
    Q --> N

    A -->|DELETE /cms/servidor/id| R[ServidorController@destroy]
    R --> P

    A -->|POST /cms/servidor/destroyAll| S[ServidorController@destroyAll]
    S --> T[Repository::destroyAll]
    T --> P

    U[Cidadão: /requerimento-de-diarias] --> V[BuscaDiariasController@index]
    V -->|whereRaw sobre name/cpf| P
    V --> W[(requerimento_diarias)]
```

## 4. Dependências externas

| Pacote | Uso no módulo |
|---|---|
| `cartalyst/sentinel` | sessão, papel `super-admin`, permissões (`has_access`, `CheckRoutePermission`) |
| `yajra/laravel-datatables-oracle` | `DataTables::of($servidor)->make(true)` na listagem do CMS |
| `laravelcollective/html` | `Form::open` / `Form::close` na view de cadastro |
| `nesbot/carbon` | timestamps (`created_at`, `updated_at`) |
| `jeremygibson/timezone` / `doctrine/dbal` | dependências do framework usadas nas migrations do módulo |

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

- **Menu do CMS:** `MenuServiceProvider` — `case 'servidor'` adiciona
  `['text' => 'Servidores', 'url' => '/cms/servidor', 'icon' => 'users']`.
  O item só aparece com `has_access('servidor.index')` **e** `modulos.status` verdadeiro.
- **Registro de módulos:** `modulos.id = 35` (`slug = 'servidor'`),
  `menu_orders.id = 29` (`slug = 'servidor'`, `modulo_id = 35`),
  `resources.id = 47` (`slug = 'servidor'`, `modulo_id = 35`).
- **Documentação interna:** a migration `v6/database/migrations/2023_02_01_083626_add_itens_to_archives.php`
  cria o "Manual de Servidor" com três áreas ("Campos Obrigatórios", "Secretarias",
  "Dados bancários"), que descrevem exatamente as regras deste módulo.
