# Usuários — Arquitetura

> Módulo CMS que administra operadores do painel, seus perfis (roles) e a
> matriz de permissões. Todo o resto do CMS consulta este módulo para decidir
> o que renderizar.

---

## 1. Fluxo da requisição

```
Navegador
   │  (sessão + CSRF via grupo 'web' — v6/app/Http/Kernel.php:31-39)
   ▼
Route::resource('usuario'|'perfil'|'permissao'|'recurso', ...)
   │  v6/routes/basepro.php:58-64
   ▼
Middleware
   ├─ check.logged            (opcional por rota; exige Sentinel::check())
   ├─ check.route.permission  (injetado no construtor de RoleController /
   │                           PermissionController; padrão de todo
   │                           Prefecture\Controller)
   └─ check.site.manutention  (não usado neste módulo)
   ▼
Admin\UserController | Admin\RoleController | Admin\PermissionController |
Admin\ResourceController
   ├─ has_access('usuario.create')  → redireciona + flash se negado
   ├─ FormRequest / $this->validate()
   └─ DB::transaction(...)
   ▼
Sentinel (cartalyst/sentinel 2.0.*)
   ├─ Sentinel::registerAndActivate() / Sentinel::update()
   ├─ Sentinel::findRoleById()->users()->attach()
   └─ Role::addPermission()
   ▼
Eloquent
   ├─ App\Admin\User      → users
   ├─ App\Admin\Role      → roles
   ├─ App\Admin\Permissions → permissions
   ├─ App\Admin\Resource  → resources
   └─ App\Admin\Modulos   → modulos
   ▼
PostgreSQL (prefeituras_v5)
```

Para as **listagens** o caminho é diferente: a view Blade só desenha a
`<table>`; o JavaScript (Yajra DataTables) consome endpoints AJAX que leem
**views SQL** diretamente via `DB::table()`.

```
DataTables JS
   ▼  GET /cms/datatable/listar_usuarios
Prefecture\DatatableController@get_listar_usuarios
   ▼  DB::table('listar_usuarios')->get()   (view SQL)
struct_views($data,'usuario')  → injeta flags edit/delete/active/inactivate
   ▼  Yajra DataTables JSON
```

---

## 2. Diagrama do fluxo de autorização

```
                       ┌─────────────────────────────┐
  View / Controller ──►│  has_access('usuario.index') │
                       └──────────────┬──────────────┘
                                      │
                    Sentinel::check() é falso? ──► false
                                      │
                    Sentinel::inRole('super-admin')? ──► true
                                      │
                    é array? ──► hasAnyAccess($array)
                    é string? ──► hasAccess([$string])
                                      │
                        PermissibleTrait::hasAccess()
                          ├─ permissões do próprio usuário (users.permissions)
                          └─ permissões dos papéis (roles.permissions)
```

## 3. Camadas e classes envolvidas

### 3.1 Controllers

| Classe | Caminho | Papel |
|---|---|---|
| `Admin\UserController` | `v6/app/Http/Controllers/Admin/UserController.php` | CRUD de usuários, ativação/inativação, listagens filtradas, atribuição de perfis |
| `Admin\RoleController` | `v6/app/Http/Controllers/Admin/RoleController.php` | CRUD de perfis e gravação do JSON de permissões |
| `Admin\PermissionController` | `v6/app/Http/Controllers/Admin/PermissionController.php` | CRUD do catálogo de permissões atômicas (restrito a `super-admin`) |
| `Admin\ResourceController` | `v6/app/Http/Controllers/Admin/ResourceController.php` | CRUD de recursos (módulos do sistema) |
| `Admin\LoginController` | `v6/app/Http/Controllers/Admin/LoginController.php` | Autenticação (`Sentinel::authenticate`) e log de "Login no sistema" |
| `Admin\ActivationController` | `v6/app/Http/Controllers/Admin/ActivationController.php` | Conclusão de ativação via link `/{email}/{activation_code}` |
| `Admin\ForgotPasswordController` | `v6/app/Http/Controllers/Admin/ForgotPasswordController.php` | Envio do link de recuperação de senha |
| `Admin\ResetPasswordController` | `v6/app/Http/Controllers/Admin/ResetPasswordController.php` | Troca de senha por token |
| `Admin\ModulosController` | `v6/app/Http/Controllers/Admin/ModulosController.php` | Liga/desliga módulos do CMS (novo na v6) |
| `Prefecture\DatatableController` | `v6/app/Http/Controllers/Prefecture/DatatableController.php` | Servidor AJAX das listagens (usuários, perfis, permissões, recursos) |

### 3.2 Models

| Classe | Caminho | Papel |
|---|---|---|
| `App\Admin\User` | `v6/app/Http/Model/Admin/User.php` | Usuário Sentinel + `SoftDeletes` + `Notifiable`; implementa `RoleableInterface`, `PermissibleInterface` |
| `App\Admin\Role` | `v6/app/Http/Model/Admin/Role.php` | Perfil; `permissions` é texto JSON |
| `App\Admin\Permissions` | `v6/app/Http/Model/Admin/Permissions.php` | Catálogo de permissões atômicas |
| `App\Admin\Resource` | `v6/app/Http/Model/Admin/Resource.php` | Recursos (módulos do sistema); relação `modulo()` |
| `App\Admin\Modulos` | `v6/app/Http/Model/Admin/Modulos.php` | Registro de módulos; `status` liga/desliga |
| `App\Admin\Person` | `v6/app/Http/Model/Admin/Person.php` | Dados pessoais do usuário (CPF/CNPJ), opcional |

### 3.3 Middleware, helpers e providers

| Item | Caminho | Papel |
|---|---|---|
| `has_access()` | `v6/app/Library/Helper/appHelpers.php:22-43` | Helper global de autorização; curto-circuita para `super-admin` |
| `menuClicks()` | `v6/app/Helpers/functions.php:865-871` | Incrementa `menu_orders.clicks` para ordenar o menu |
| `CheckRoutePermission` | `v6/app/Http/Middleware/CheckRoutePermission.php` | Autorização por nome de rota + segmento de URL |
| `CheckLogged` | `v6/app/Http/Middleware/CheckLogged.php` | Exige sessão autenticada; redireciona ao dashboard |
| `App\Http\Kernel` | `v6/app/Http/Kernel.php` | Registro dos aliases de middleware |
| `MenuServiceProvider` | `v6/app/Providers/MenuServiceProvider.php:336-356` | Monta o submenu "Usuários" do AdminLTE |
| `ModulosServiceProvider` | `v6/app/Providers/ModulosServiceProvider.php` | Injeta `$modulos` (slug => status) nas views do portal e do dashboard |
| `SentinelFilter` | `v6/app/Library/Menu/Filters/SentinelFilter.php` | Filtro do AdminLTE que oculta itens sem permissão |
| `ActivityObserver` | `v6/app/Observers/ActivityObserver.php` | Preenche `ip_address` e `browser` em cada `activity_log` |

### 3.4 Requisições (Form Requests)

| Classe | Caminho | Regras |
|---|---|---|
| `UserRequest` | `v6/app/Http/Requests/UserRequest.php` | `name` e `email` obrigatórios; `password`/`password_confirmation` só se a senha foi enviada; `selectProfiles` obrigatório quando o ator tem `perfil.create`/`perfil.edit` ou está no `usuario.store` |

`RoleController`, `PermissionController` e `ResourceController` **não** usam
Form Request: validam com `$this->validate()` dentro do controller
(`_validate()` / `getRules()` / `customAttributes()`).

---

## 4. Dependências externas

| Pacote | Versão | Uso no módulo |
|---|---|---|
| `cartalyst/sentinel` | `2.0.*` | Autenticação, papéis, permissões, ativações |
| `spatie/laravel-activitylog` | `^2.8` | Trilha de auditoria (`activity_log`) |
| `yajra/laravel-datatables` | `^1.5` | JSON das listagens AJAX |
| `laravelcollective/html` | `^5.5` | `Form::` nos Blades |
| `laralabs/toaster` | `^2.0` | Mensagens `flash()` |

---

## 5. Onde o módulo é consumido (acoplamento)

| Consumidor | Dependência | Onde |
|---|---|---|
| Todos os controllers do CMS | `has_access()` | `v6/app/Http/Controllers/**` |
| Todos os Blades do CMS | `has_access()` | `v6/resources/views/**` |
| Menu lateral do AdminLTE | `SentinelFilter` + `has_access('usuario.*')` | `v6/app/Providers/MenuServiceProvider.php` |
| Matriz de permissões | `resources` x `permissions` x `roles.permissions` | `v6/resources/views/admin/role/form.blade.php` |
| Auditoria | `activity()->performedOn($user)` | `v6/app/Http/Controllers/Admin/UserController.php` |

O módulo é a **dependência de maior criticidade** do CMS: uma alteração no
formato da chave de permissão (`recurso.acao`) quebra silenciosamente a
autorização de todos os outros módulos.

---

## 6. Mapa de arquivos

```
app/Http/Controllers/Admin/
├── UserController.php          (531 linhas)
├── RoleController.php          (226 linhas)
├── PermissionController.php    (227 linhas)
├── ResourceController.php
├── LoginController.php
├── ActivationController.php
├── ForgotPasswordController.php
├── ResetPasswordController.php
└── ModulosController.php

app/Http/Model/Admin/
├── User.php        (479 linhas)
├── Role.php
├── Permissions.php
├── Resource.php
├── Modulos.php
└── Person.php

app/Http/Requests/UserRequest.php
app/Http/Middleware/CheckRoutePermission.php
app/Http/Middleware/CheckLogged.php
app/Library/Helper/appHelpers.php
app/Providers/MenuServiceProvider.php
app/Providers/ModulosServiceProvider.php
app/Library/Menu/Filters/SentinelFilter.php
app/Observers/ActivityObserver.php

resources/views/admin/
├── user/{index,list,create,edit,form,active,inactive}.blade.php
├── role/{index,create,edit,form}.blade.php
├── permission/{index,create,edit,form,show}.blade.php
├── resource/
├── modulos/{index,form}.blade.php
└── user_new/**              (órfão — ver 08-GAPS-E-DIVIDAS.md)

public/assets/js/custom/contents/usuarios/
├── listar/datatable.js
├── listar_inativos/datatable.js
├── listar_todos/datatable.js
└── perfis/datatable.js
public/assets/js/custom/contents/permissoes/datatable.js
public/assets/js/custom/contents/recursos/datatable.js
public/assets/js/custom/utilities/table.js
```
