# Resumo de Alterações e Padrões do Projeto Este documento resume as implementações realizadas no módulo de Mídias e estabelece os padrões a serem seguidos na criação de novos módulos. --- ## Padrões para Novos Módulos (Baseado no Módulo de Mídias) **1. Controle de Status (Ativo/Inativo):** - **Coluna:** `status` (TINYINT, default 0). - **Uso:** - `0`: Item **Ativo**. Visível e interage com todo o sistema. - `1`: Item **Inativo**. Visível apenas na listagem principal do seu módulo (com estilo visual atenuado, ex: `text-muted`), não interage com outras partes do sistema. Pode ser reativado. - **Interface:** A troca de status deve ser feita por um ícone de toggle (ligado/desligado) na coluna de ações da listagem principal. **2. Lixeira (Soft Delete):** - **Implementação:** Usar a trait `Illuminate\Database\Eloquent\SoftDeletes` do Laravel. - **Coluna:** A migração deve adicionar a coluna `deleted_at` usando `$table->softDeletes();`. - **Funcionalidade:** A ação de "excluir" um item deve realizar um soft delete. Os itens excluídos só devem ser visíveis em uma "Lixeira", que será implementada como um **modal** na tela de listagem. **3. Auditoria de Usuários (Userstamps):** - **Implementação:** Usar o Trait `App\Traits\Userstamps`. - **Colunas:** A migração deve adicionar as colunas `created_by`, `updated_by`, `deleted_by` (nullable, foreign keys para a tabela `users`). - **Uso:** Ao aplicar o Trait `Userstamps` a um Model, o preenchimento desses campos se torna automático, registrando qual usuário realizou cada ação. - **Relacionamentos:** O model deve conter os métodos de relacionamento `creator()`, `updater()`, e `destroyer()` para facilitar a busca das informações do usuário. --- ## Resumo Detalhado das Alterações no Módulo de Mídias ### Banco de Dados - Adicionada a coluna `status` à tabela `midias`. - Adicionada a coluna `deleted_at` para implementar o Soft Delete. - Adicionada a coluna `views_count` para o futuro contador de visualizações. - Adicionadas as colunas de auditoria `created_by`, `updated_by`, `deleted_by`. ### Backend - **Model `Midia.php`:** - Implementou as traits `SoftDeletes` e `Userstamps`. - Adicionou os relacionamentos `creator`, `updater`, `destroyer`. - **Trait `Userstamps.php`:** - Criado em `app/Traits/` para preencher automaticamente os campos de auditoria em eventos de `creating`, `updating` e `deleting`. - **Controller `MidiaController.php`:** - O método `destroy()` foi ajustado para executar apenas o soft delete. - Adicionado o método `toggleStatus()` para ativar/desativar um item. - O método `trash()` foi refatorado para funcionar como um endpoint de API, retornando um JSON com os itens da lixeira e os usuários que os excluíram. - Adicionado o método `restore()` para restaurar um item da lixeira. - **Rotas `web.php`:** - Adicionadas rotas para `toggleStatus`, `trash`, e `restore`. ### Frontend (`index.blade.php`) - A coluna "Status" foi removida. - Linhas de itens inativos (`status = 1`) agora recebem a classe `text-muted` para diferenciação visual. - O botão "Lixeira" foi convertido para abrir um modal. - Adicionado um modal `#trashModal` que é populado dinamicamente via AJAX: - Ao abrir, faz uma requisição para a rota `midias.trash`. - Exibe uma tabela com a mídia, data da exclusão, nome do usuário que excluiu e um botão para restaurar. - Adicionada a coluna "Views" (anteriormente "Analytics") com um ícone e um contador formatado. - Adicionado um modal `#analyticsModal` para visualização futura de analytics. - Corrigido o layout principal (`master.blade.php`) com a adição de `@stack('scripts')` para garantir que os scripts JavaScript das páginas funcionem corretamente. ### Testes - Criado o arquivo `MidiaModuleTest.php` com testes de feature para todas as novas funcionalidades (soft delete, restore, toggle status, etc.). - Testes antigos que verificavam a exclusão permanente de registros foram atualizados para `assertSoftDeleted`. --- ## Atualizações em 2025-10-12 06:15:00 ### Padronização do Módulo de Empresas Seguindo o padrão estabelecido pelo módulo de Mídias, as seguintes funcionalidades foram replicadas no módulo de Empresas: - **Banco de Dados:** - Adicionadas as colunas `status`, `deleted_at`, `created_by`, `updated_by`, `deleted_by` à tabela `empresas`. - **Backend:** - O model `Empresa` agora utiliza as traits `SoftDeletes` e `Userstamps` e possui os relacionamentos de auditoria. - O `EmpresaController` foi atualizado com os métodos `toggleStatus`, `trash` (endpoint JSON) e `restore`. - As rotas correspondentes foram adicionadas. - **Frontend:** - A view `empresas/index.blade.php` foi refatorada para incluir o botão de Lixeira com modal (via AJAX), o botão de toggle para status e o estilo `text-muted` para itens inativos. - As views de formulário (`create` e `edit`) foram traduzidas para Português (pt-BR). ### Funcionalidade de Busca (Módulo de Mídias) - **Backend:** - O método `index` do `MidiaController` agora aceita um parâmetro de busca (`q`) para filtrar mídias por título. - A paginação foi adicionada ao resultado da busca. - **Frontend:** - Um formulário de busca foi adicionado à tela de listagem de mídias. - Links de paginação foram adicionados e configurados para manter o filtro de busca ao navegar entre as páginas. --- ## Atualizações em 2025-10-12 12:30:00 ### Padronização Visual e Funcional (Módulo de Empresas) Dando continuidade à padronização, foram feitos ajustes visuais e funcionais nos formulários do módulo de Empresas. - **Padronização de Formulários:** - O cabeçalho (título e breadcrumb) das páginas de criação e edição foi atualizado para incluir ícones, seguindo o padrão do módulo de Mídias. - Os botões de submissão ("Salvar", "Cancelar") foram agrupados e receberam ícones para manter a consistência visual com o resto da aplicação. - **Máscara de Entrada para Telefone:** - Foi implementada uma máscara de entrada no campo de telefone para formatar o número dinamicamente, aceitando formatos de telefone fixo e celular do Brasil. - **Tecnologia:** A implementação foi feita com a biblioteca `jquery-mask-plugin` de Igor Escobar. - **Dependências:** Para isso, as bibliotecas `jquery` e `jquery-mask-plugin` foram adicionadas ao projeto, e a biblioteca `imask` foi removida. - **Build:** Os assets do frontend foram recompilados para aplicar as mudanças. --- ## Atualizações em 2025-10-12 13:00:00 ### Correção de Conflito de JavaScript Foi diagnosticado e corrigido um erro de JavaScript (`Uncaught TypeError: $(...).mask is not a function`) que impedia o funcionamento da máscara de telefone. - **Causa Raiz:** O erro foi causado por um conflito entre duas versões do jQuery sendo carregadas na aplicação: uma versão estática (de `public/assets/js`) e uma versão gerenciada pelo `npm`/`Vite`. O plugin de máscara estava sendo associado a uma versão, enquanto o script da página tentava usar a outra. - **Solução Aplicada:** 1. **Remoção de Dependência Duplicada:** A dependência `jquery` do `npm` foi removida do `package.json`. 2. **Centralização do Carregamento:** O carregamento do plugin `jquery-mask-plugin` foi movido do `bootstrap.js` (gerenciado pelo Vite) para o layout principal (`script.blade.php`), sendo carregado como um arquivo estático logo após o jQuery principal do tema. 3. **Organização de Assets:** O arquivo do plugin foi copiado de `node_modules` para `public/assets/vendor/jquery-mask/` para manter a organização dos scripts de terceiros. 4. **Limpeza e Rebuild:** O `bootstrap.js` foi revertido para seu estado original e os assets do frontend foram recompilados para garantir a consistência. --- ## Atualizações em 2025-11-09 - Sistema de Aprovação de Clientes e Empresas ### 1. Middleware de Verificação de Aprovação de Empresas **Arquivo:** `app/Http/Middleware/CheckEmpresaAprovada.php` Criado middleware para bloquear login de usuários cujas empresas não foram aprovadas. **Regras implementadas:** - **SuperAdmin:** sempre pode acessar (bypass total) - **Franquias e Matriz:** sempre podem acessar - **Usuários Multi-Franquia:** (sem empresa_id mas com pivot) podem acessar - **Clientes com status "pendente":** bloqueados com mensagem "Aguardando aprovação" - **Clientes com status "rejeitado":** bloqueados com mensagem mostrando motivo da rejeição - **Clientes com status "aprovado":** acesso liberado normalmente **Integração:** - Middleware registrado em `bootstrap/app.php` com alias `'check.empresa.aprovada'` - Aplicado nas rotas autenticadas em `routes/web.php` junto com `'check.approval'` ### 2. Sistema de Aprovação de Hotspots **Migração:** `database/migrations/2025_11_09_224911_add_aprovacao_fields_to_hotspots_table.php` Adicionados campos de aprovação à tabela `hotspots`: - `status_aprovacao` (enum: pendente, aprovado, rejeitado) - default 'pendente' - `aprovado_por` (foreign key para users) - nullable - `aprovado_em` (timestamp) - nullable - `motivo_rejeicao` (text) - nullable **Controller:** `app/Http/Controllers/HotspotController.php` - Franqueados só podem criar hotspots com situação até "Aguardando Instalação" - Hotspots criados por franqueados ficam com `status_aprovacao = 'pendente'` - Apenas SuperAdmin pode aprovar/rejeitar hotspots - Métodos adicionados: `approve()`, `reject()` ### 3. Sistema de Cadastro Público de Clientes **Migração:** `database/migrations/2025_11_09_225202_add_token_convite_to_empresas_table.php` Adicionado campo `token_convite` à tabela `empresas`: - Campo único gerado via MD5 para cada franquia - Usado para criar link público de cadastro **Controller:** `app/Http/Controllers/PublicClienteRegisterController.php` (NOVO) Controlador para registro público de clientes via link de convite: - `showRegistrationForm()`: exibe formulário público - `register()`: processa cadastro e cria empresa + usuário com status 'pendente' **View:** `resources/views/public/register-cliente.blade.php` (NOVA) Formulário público de cadastro com: - Dados da empresa (nome, email, telefone, endereço) - Dados do usuário (nome, email, senha, confirmação) - Design Bootstrap 5 responsivo - Validação client-side **Rotas públicas:** `routes/web.php` ```php Route::get('/cadastro/cliente/{franquiaToken}', [PublicClienteRegisterController::class, 'showRegistrationForm'])->name('public.register.form'); Route::post('/cadastro/cliente/{franquiaToken}', [PublicClienteRegisterController::class, 'register'])->name('public.register.submit'); ``` ### 4. Sistema de Aprovação de Empresas Clientes **Migração:** `database/migrations/2025_11_09_225950_add_aprovacao_fields_to_empresas_table.php` Adicionados campos de aprovação à tabela `empresas`: - `status_aprovacao` (enum: pendente, aprovado, rejeitado) - default 'aprovado' - `aprovado_por` (foreign key para users) - nullable - `aprovado_em` (timestamp) - nullable - `motivo_rejeicao` (text) - nullable **Model:** `app/Models/Empresa.php` Campos adicionados ao `$fillable` array para mass assignment. **Controller:** `app/Http/Controllers/ClienteController.php` Métodos adicionados: - `approve()`: aprova cliente (Franqueado OU SuperAdmin) - `reject()`: rejeita cliente com motivo (Franqueado OU SuperAdmin) **View:** `resources/views/clientes/index.blade.php` Seção destacada para clientes pendentes: - Card amarelo no topo da página - Contador de clientes pendentes - Tabela com botões "Aprovar" e "Rejeitar" - Modal para inserir motivo de rejeição - Botão "Link de Convite" para copiar URL de cadastro público **JavaScript:** Função `copiarLinkConvite()` para copiar link com feedback visual ### 5. Melhorias no Dashboard da Franquia **View:** `resources/views/dashboard-franquia.blade.php` **Cards com gradientes modernos:** - **Seção WiFi:** Gradiente roxo (#667eea → #764ba2) - **Seção Receita:** Gradiente verde (#11998e → #38ef7d) - Ícones decorativos em opacity reduzida - Subtítulos informativos **Correção do gráfico "Top 10 Clientes por Receita":** - **Problema:** Canvas com altura fixa causava loop infinito de renderização - **Solução:** Container com altura dinâmica baseada no número de itens - Fórmula: `height: {{ max(300, $receitaPorCliente->count() * 50) }}px` - Console logs para debugging - Animation callback para monitoramento **Script de diagnóstico:** `diagnostic_dashboard.php` (NOVO) Script CLI para testar backend do dashboard: - Testa conexão com banco - Verifica franquias e clientes - Executa query principal de receita - Valida dados para Chart.js - Detecta valores NULL - Gera relatório completo ### 6. Atualização de Policies para Multi-Franquia **Policy:** `app/Policies/EmpresaPolicy.php` Atualizada para suportar usuários multi-franquia: - `view()`: verifica se cliente pertence a alguma franquia do usuário via pivot - `update()`: permite edição de clientes de todas as franquias do usuário - `delete()`: permite exclusão de clientes de todas as franquias do usuário **Lógica implementada:** ```php if ($user->isFranchiseUser()) { $franquiasIds = $user->empresas()->where('tipo_empresa', 'franquia') ->pluck('empresas.id')->toArray(); return in_array($empresa->empresa_pai_id, $franquiasIds); } ``` ### 7. Compatibilidade com Laravel 11 **Removido uso deprecado de `$this->middleware()` nos Controllers:** - Removido construtor com middleware em `ClienteController` - Removido construtor com middleware em `EmpresaController` - Middlewares agora aplicados apenas nas rotas (`web.php`) **Substituído `$this->authorize()` por `Gate::authorize()`:** - Atualizado em todos os métodos do `ClienteController`: - `show()`, `edit()`, `update()`, `destroy()` - Importado `use Illuminate\Support\Facades\Gate;` ### 8. Correções em Controllers **ClienteController:** - Corrigido método `show()` para obter franquia via `$cliente->empresaPai` - Corrigido método `edit()` para obter franquia via `$cliente->empresaPai` - Isso resolve o problema de usuários multi-franquia (sem empresa_id) ### 9. Card de Usuários na Página de Detalhes do Cliente **View:** `resources/views/clientes/show.blade.php` **Novo card implementado:** - Header com gradiente roxo matching o dashboard - Badge com total de usuários - 3 cards de estatísticas rápidas: - ✅ Usuários Ativos (verde) - ⏰ Usuários Pendentes (amarelo) - 👥 Total de Usuários (azul) **Tabela de usuários:** - Avatar circular com inicial do nome (gradiente roxo) - Nome completo (com indicação se excluído) - E-mail clicável (mailto:) - Status com badges coloridos - Data de criação - Suporte para soft deleted users (fundo cinza) **Botão "Link de Convite":** - Localizado no header do card de usuários - Copia link de cadastro público para clipboard - Toast animado com feedback visual - Gradiente roxo matching o design - Auto-remove após 3 segundos - Fallback para alert em navegadores antigos **Controller:** `app/Http/Controllers/ClienteController.php` Método `show()` atualizado para incluir: - Lista de usuários do cliente (incluindo soft deleted) - Estatísticas: `$totalUsuarios`, `$usuariosAtivos`, `$usuariosPendentes` ### 10. Fluxo Completo de Aprovação **Diagrama do fluxo:** ``` Cliente acessa link público → Preenche formulário → Empresa criada (pendente) ↓ Cliente tenta login → Bloqueado pelo middleware CheckEmpresaAprovada ↓ Franqueado acessa /clientes → Vê seção "Aguardando Aprovação" ↓ Franqueado aprova → status_aprovacao = 'aprovado' ↓ Cliente faz login novamente → Acesso liberado ✅ ``` ### 11. Segurança e OWASP Todas as implementações seguem os padrões OWASP: - **A01:2021 – Broken Access Control:** Policies e middlewares verificando permissões - **A03:2021 – Injection Prevention:** Validação de inputs com Laravel Validator - **A05:2021 – Security Misconfiguration:** CSP headers e Blade escaping automático - **A07:2021 – Rate Limiting:** Throttling nas rotas de criação/edição/exclusão ### 12. Configuração de Ambiente **Arquivo `.env`:** - Configurado para ambiente Docker: `DB_HOST=mysql8-3308`, `DB_PORT=3306` - Feature flags para emails: `FEATURE_EMAIL_*=true` **Nota:** Para comandos CLI (artisan tinker), usar `DB_HOST=127.0.0.1`, `DB_PORT=3308` --- ## Comandos Úteis ### Limpar caches após mudanças: ```bash docker exec freefi-8082 php artisan config:clear docker exec freefi-8082 php artisan cache:clear docker exec freefi-8082 php artisan view:clear ``` ### Executar diagnóstico do dashboard: ```bash php diagnostic_dashboard.php ``` ### Testar fluxo de aprovação: ```bash # Cliente pendente Login: cliente.pendente@teste.com / 123456 # Cliente rejeitado Login: cliente.rejeitado@teste.com / 123456 # Franqueado multi-franquia Login: joao.multi@teste.com / 123456 ``` --- ## Atualizações em 2025-11-09 (Tarde) - Restrição de Criação de Usuários ### 1. UserPolicy - Controle de Criação de Usuários **Arquivo:** `app/Policies/UserPolicy.php` (NOVO) Implementada Policy completa para controle de acesso às operações de usuários. **Regras de Criação de Usuários:** - **SuperAdmin:** ÚNICO perfil que pode criar usuários manualmente via `/users/create` - **Outros usuários:** NÃO podem criar usuários manualmente - **Cadastro público:** Usuários normais devem ser criados via link de convite público (`/cadastro/cliente/{token}`) **Métodos implementados:** ```php public function create(User $user): bool { // Apenas SuperAdmin pode criar usuários manualmente return $user->is_superadmin; } public function update(User $user, User $model): bool { // SuperAdmin pode editar qualquer usuário // Usuário pode editar a si mesmo // Franqueado gestor pode editar usuários da sua franquia } public function delete(User $user, User $model): bool { // SuperAdmin pode excluir (exceto a si mesmo) // Franqueado gestor pode excluir usuários da franquia (exceto a si mesmo) } public function approve(User $user): bool { // Apenas SuperAdmin pode aprovar usuários } public function reject(User $user): bool { // Apenas SuperAdmin pode rejeitar usuários } ``` ### 2. Atualização do UserController **Arquivo:** `app/Http/Controllers/UserController.php` Métodos atualizados com autorização via `Gate::authorize()`: - `create()`: Verifica permissão antes de exibir formulário - `store()`: Verifica permissão antes de criar usuário - `edit()`: Verifica permissão antes de editar - `update()`: Verifica permissão antes de salvar alterações - `destroy()`: Verifica permissão antes de excluir - `restore()`: Verifica permissão antes de restaurar - `approve()`: Verifica permissão antes de aprovar - `reject()`: Verifica permissão antes de rejeitar **Importação adicionada:** ```php use Illuminate\Support\Facades\Gate; ``` ### 3. Atualização da View de Listagem **Arquivo:** `resources/views/users/index.blade.php` Botão "Novo Usuário" agora é exibido apenas para usuários autorizados: ```blade @can('create', App\Models\User::class) Novo Usuário @endcan ``` ### 4. Auto-Discovery de Policies No Laravel 11, Policies são auto-descobertas quando seguem a convenção: - Model: `User` → Policy: `UserPolicy` - Localização: `app/Policies/UserPolicy.php` Não é necessário registro manual no AuthServiceProvider. ### 5. Fluxo Completo de Cadastro **Cadastro Manual (Interno):** ``` SuperAdmin → /users/create → Formulário → Cria usuário ✅ Outros usuários → /users/create → 403 Forbidden ❌ ``` **Cadastro por Convite (Público):** ``` Qualquer pessoa → /cadastro/cliente/{token} → Formulário público ↓ Cria: Empresa Cliente (pendente) + Usuário ↓ Franqueado/SuperAdmin aprova → Cliente ativo ✅ ``` ### 6. Testes Realizados ```bash # Teste via Tinker ✅ SuperAdmin: Ivandro (can create users: YES) ❌ Normal User: Anannda (can create users: NO) ``` **Comandos executados:** - Cache limpo: `php artisan optimize:clear` - Teste de permissões via tinker ### 7. Hierarquia de Permissões Implementada ``` SuperAdmin (is_superadmin = true) ├─ Criar usuários manualmente ✅ ├─ Editar qualquer usuário ✅ ├─ Excluir qualquer usuário ✅ ├─ Aprovar/Rejeitar usuários ✅ └─ Restaurar usuários da lixeira ✅ Franqueado Gestor (role = 'gestor') ├─ Editar usuários da sua franquia ✅ ├─ Excluir usuários da sua franquia ✅ └─ Restaurar usuários da sua franquia ✅ Usuário Comum ├─ Editar apenas o próprio perfil ✅ └─ Sem permissões administrativas ❌ ``` ### 8. Segurança OWASP **A01:2021 – Broken Access Control:** - ✅ Policy implementada em todos os métodos críticos - ✅ Autorização via `Gate::authorize()` - ✅ Blade directive `@can` nas views - ✅ Mensagens de erro apropriadas (403 Forbidden) **Proteções implementadas:** - Usuário não pode excluir a si mesmo - Apenas SuperAdmin pode aprovar/rejeitar - Franqueados só acessam usuários da sua franquia - Cadastro público separado do administrativo --- ## Atualizações em 2025-11-09 (Noite) - Filtro de Hierarquia na Listagem de Usuários ### 1. Implementação de Filtro por Hierarquia **Arquivo:** `app/Http/Controllers/UserController.php` Implementado filtro automático na listagem de usuários para respeitar a hierarquia de empresas. **Regras implementadas:** ``` SuperAdmin (is_superadmin = true) └─ Vê TODOS os usuários do sistema Franqueado (tipo_empresa = 'franquia') ├─ Vê usuários da própria franquia └─ Vê usuários de TODOS os clientes da franquia Cliente (tipo_empresa = 'cliente') └─ Vê APENAS usuários da própria empresa Usuário sem empresa └─ Vê APENAS a si mesmo ``` ### 2. Métodos Atualizados **`index()` - Listagem principal:** ```php // Filtro de hierarquia: franqueados veem apenas usuários da sua franquia e clientes if (!auth()->user()->is_superadmin) { $empresaUsuario = auth()->user()->empresa; if ($empresaUsuario) { if ($empresaUsuario->tipo_empresa === 'franquia') { // IDs: franquia + seus clientes $empresasIds = \App\Models\Empresa::where('id', $empresaUsuario->id) ->orWhere('empresa_pai_id', $empresaUsuario->id) ->pluck('id') ->toArray(); $query->whereIn('empresa_id', $empresasIds); } else { // Se for cliente, ver apenas usuários do próprio cliente $query->where('empresa_id', $empresaUsuario->id); } } } ``` **`trash()` - Lixeira:** - Mesmo filtro aplicado aos usuários excluídos (soft deleted) - Franqueados veem apenas lixeira da sua hierarquia ### 3. Suporte a Multi-Franquia Sistema também suporta usuários vinculados a múltiplas franquias via tabela pivot `empresa_user`: ```php // Se não tem empresa, verificar empresas via pivot (multi-franquia) $franquiasIds = auth()->user()->empresas() ->where('tipo_empresa', 'franquia') ->pluck('empresas.id') ->toArray(); if (!empty($franquiasIds)) { // IDs das franquias + clientes dessas franquias $empresasIds = \App\Models\Empresa::whereIn('id', $franquiasIds) ->orWhereIn('empresa_pai_id', $franquiasIds) ->pluck('id') ->toArray(); $query->whereIn('empresa_id', $empresasIds); } ``` ### 4. Testes Realizados **Cenário de teste:** - Franquia: "Freefi Guarabira PB" (ID: 2) - Cliente 1: "Marcellus Bar" (ID: 3) - 1 usuário - Cliente 2: "Fruto de Goiás" (ID: 4) - 0 usuários **Resultados:** ```bash 👑 SuperAdmin: Ivandro Deve ver: TODOS os 15 usuários ✅ 🏢 Franqueado: Hugo Moura (Freefi Guarabira PB) Empresas visíveis: IDs 2, 3, 4 Deve ver: 3 usuários ✅ Usuários visíveis: - Hugo Moura (Freefi Guarabira PB) - Franquia Teste (Freefi Guarabira PB) - Marcellus Bar (Marcellus Bar) 👤 Usuário Cliente: Marcellus Bar Deve ver: 1 usuário (apenas da própria empresa) ✅ ``` ### 5. Integração com Busca O filtro de hierarquia é aplicado **antes** da busca por nome/email, garantindo que: - Usuários só podem buscar dentro da sua hierarquia - Não é possível descobrir usuários de outras franquias via busca ```php // Filtro de hierarquia aplicado primeiro if (!auth()->user()->is_superadmin) { // ... aplicar filtro ... } // Busca aplicada depois (dentro do escopo já filtrado) if ($request->has('q') && $request->q != '') { $query->where(function($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('email', 'like', "%{$search}%"); }); } ``` ### 6. Segurança e Isolamento **Benefícios de segurança:** - ✅ Franquias não podem ver usuários de outras franquias - ✅ Clientes não podem ver usuários de outros clientes - ✅ Isolamento total de dados por hierarquia - ✅ Mesmo na lixeira, filtro é mantido - ✅ Impossível burlar via busca ou manipulação de URL **OWASP A01:2021 – Broken Access Control:** - Filtro implementado a nível de query (não apenas UI) - Aplicado em todos os métodos relevantes - Testado com diferentes perfis de usuário ### 7. Exemplo Prático de Isolamento **Estrutura:** ``` FreeFi (Matriz - ID: 1) ├─ Freefi São Paulo (Franquia - ID: 2) │ ├─ Cliente A (ID: 5) │ └─ Cliente B (ID: 6) └─ Freefi Rio (Franquia - ID: 3) ├─ Cliente C (ID: 7) └─ Cliente D (ID: 8) ``` **Isolamento:** - Franquia São Paulo vê: usuários de IDs 2, 5, 6 - Franquia Rio vê: usuários de IDs 3, 7, 8 - SuperAdmin vê: TODOS --- ## Atualizações em 2025-11-09 (Noite) - Menu de Hierarquia do Negócio ### 1. Nova Funcionalidade: Visualização de Hierarquia **Objetivo:** Criar uma página visual que mostre a estrutura completa da franquia (Franquia → Clientes → Usuários) ### 2. Controller Criado **Arquivo:** `app/Http/Controllers/HierarchyController.php` (NOVO) Implementa visualização hierárquica diferenciada por perfil: ```php class HierarchyController extends Controller { public function index() { // SuperAdmin → Vê todas as franquias if ($user->is_superadmin) { return $this->hierarchySuperAdmin(); } // Franqueado → Vê sua hierarquia if ($user->isFranchiseUser()) { return $this->hierarchyFranquia($user); } // Cliente → Sem acesso (403) abort(403); } } ``` ### 3. Visualização para Franqueados **Estrutura mostrada:** ``` Franquia: Freefi Guarabira PB ├─ Usuários da Franquia (2) │ ├─ Hugo Moura │ └─ Franquia Teste └─ Clientes (2) ├─ Marcellus Bar (1 usuário) │ └─ Marcellus Bar (usuário) └─ Fruto de Goiás (0 usuários) ``` **Cards de Estatísticas:** - Total de Clientes - Total de Usuários - Clientes Ativos - Clientes Pendentes ### 4. Visualização para SuperAdmin **Estrutura mostrada:** - Lista de TODAS as franquias - Para cada franquia: seus clientes - Estatísticas globais: - Total de Franquias - Total de Clientes - Total de Usuários ### 5. View com Design Moderno **Arquivo:** `resources/views/hierarchy/index.blade.php` (NOVO) **Características do design:** ✅ **Cards Hierárquicos com Gradientes:** - Franquia: Roxo (#667eea → #764ba2) - Cliente: Verde (#11998e → #38ef7d) ✅ **Avatares Circulares:** - Primeira letra do nome em destaque - Gradiente personalizado por tipo ✅ **Badges de Status:** - Aprovado (verde) - Pendente (amarelo) - Rejeitado (vermelho) ✅ **Linhas de Conexão:** - Linhas tracejadas mostrando relação hierárquica - Indentação visual clara ✅ **Responsivo:** - Grid adaptável para diferentes tamanhos de tela - Cards se ajustam automaticamente ### 6. Rota Criada **Arquivo:** `routes/web.php` ```php Route::get('/hierarquia', [HierarchyController::class, 'index']) ->middleware(['auth', 'verified', 'check.approval', 'check.empresa.aprovada']) ->name('hierarchy.index'); ``` ### 7. Menu Atualizado **Arquivo:** `resources/views/layouts/sidebar.blade.php` **Menu do SuperAdmin:** ``` Dashboard Hierarquia Global ← NOVO Users Empresas ... ``` **Menu do Franqueado:** ``` Dashboard Hierarquia do Negócio ← NOVO Meus Usuários Meus Clientes ... ``` **Ícone usado:** `ph-tree-structure` (Phosphor Icons) ### 8. Componentes Visuais **Cards de Estatísticas (4 cards):** 1. Clientes - Ícone: buildings (roxo) 2. Total Usuários - Ícone: users (verde) 3. Ativos - Ícone: check-circle (rosa) 4. Pendentes - Ícone: clock (laranja) **Card de Franquia:** - Gradiente roxo claro no fundo - Borda esquerda roxa (4px) - Ícone: building - Informações: email, telefone - Badge "FRANQUIA" - Lista de usuários da franquia **Card de Cliente:** - Gradiente verde claro no fundo - Borda esquerda verde (4px) - Ícone: storefront - Informações: email, telefone, endereço - Badge de status (aprovado/pendente/rejeitado) - Lista de usuários do cliente ### 9. Funcionalidades Implementadas ✅ **Isolamento por perfil:** - Franqueado vê apenas sua estrutura - SuperAdmin vê todas as estruturas - Cliente não tem acesso ✅ **Informações completas:** - Dados da empresa (nome, email, telefone, endereço) - Status de aprovação - Contagem de usuários - Lista detalhada de todos os usuários ✅ **Hover effects:** - Cards se elevam ao passar o mouse - Transições suaves ✅ **Alertas informativos:** - "Nenhum usuário cadastrado" - "Nenhum cliente cadastrado" ### 10. Teste Realizado **Cenário de teste:** ``` Franqueado: Hugo Moura Franquia: Freefi Guarabira PB (ID: 2) ├─ Usuários da Franquia: 2 └─ Clientes: 2 ├─ Marcellus Bar (1 usuário) └─ Fruto de Goiás (0 usuários) Total de Usuários: 3 ✅ Hierarquia carregada com sucesso! ``` ### 11. Benefícios da Funcionalidade **Para Franqueados:** - ✅ Visão completa do negócio em uma única tela - ✅ Identificação rápida de clientes pendentes - ✅ Contagem de usuários por cliente - ✅ Acesso rápido a informações de contato **Para SuperAdmin:** - ✅ Visão global de todas as franquias - ✅ Comparação entre franquias - ✅ Identificação de franquias sem clientes ### 12. Navegação **Acesso:** - URL: `/hierarquia` - Menu: "Hierarquia do Negócio" (franqueados) - Menu: "Hierarquia Global" (superadmin) **Breadcrumb:** ``` Dashboard → Hierarquia ``` ### 13. Segurança ✅ **Autenticação obrigatória** ✅ **Middleware de aprovação aplicado** ✅ **Isolamento de dados por perfil** ✅ **403 Forbidden para clientes** --- ## Próximos Passos Sugeridos 1. Implementar notificações por email quando cliente for aprovado/rejeitado 2. Adicionar badge de notificação no menu para clientes pendentes 3. ~~Implementar aprovação de usuários (similar ao de clientes)~~ ✅ CONCLUÍDO 4. Adicionar logs de auditoria para ações de aprovação/rejeição 5. Criar dashboard específico para clientes aprovados 6. Implementar roles granulares (gestor/operador/visualizador) para franquias