# 6. SISTEMA MULTI-RUOLO - GUIDA COMPLETA ## πŸ“‹ **INDICE CAPITOLO** - [6.1 Architettura Ruoli e Permessi](#61-architettura-ruoli-e-permessi) - [6.2 Configurazione Spatie Permission](#62-configurazione-spatie-permission) - [6.3 Modelli e Relazioni](#63-modelli-e-relazioni) - [6.4 Seeder Ruoli e Permessi](#64-seeder-ruoli-e-permessi) - [6.5 Middleware di Protezione](#65-middleware-di-protezione) - [6.6 Controllers per Ruoli](#66-controllers-per-ruoli) - [6.7 Dashboard Condizionali](#67-dashboard-condizionali) - [6.8 Gestione Utenti](#68-gestione-utenti) - [6.9 Esempi Pratici](#69-esempi-pratici) --- ## 6.1 Architettura Ruoli e Permessi ### Gerarchia Ruoli NetGescon ``` SuperAdmin β”œβ”€β”€ Accesso completo sistema β”œβ”€β”€ Gestione utenti e ruoli β”œβ”€β”€ Configurazione globale β”œβ”€β”€ Archivi base (comuni) └── Monitoring e logs Admin β”œβ”€β”€ Gestione completa stabili assegnati β”œβ”€β”€ CRUD completo tutti i dati β”œβ”€β”€ ContabilitΓ  e documenti β”œβ”€β”€ Comunicazioni condomini └── Backup e reports Amministratore β”œβ”€β”€ Gestione stabili assegnati β”œβ”€β”€ CRUD limitato (no delete critici) β”œβ”€β”€ ContabilitΓ  base β”œβ”€β”€ Documenti e comunicazioni └── Reports stabili Condomino β”œβ”€β”€ Visualizzazione dati personali β”œβ”€β”€ Documenti unitΓ  di proprietΓ  β”œβ”€β”€ Comunicazioni con amministratore β”œβ”€β”€ Consultazione movimenti └── Modifica profilo personale ``` ### Matrice Permessi Dettagliata ``` FUNZIONALITΓ€ | SuperAdmin | Admin | Amministratore | Condomino -----------------------|------------|-------|----------------|---------- Gestione Utenti | βœ… | ❌ | ❌ | ❌ Comuni Italiani | βœ… | ❌ | ❌ | ❌ Stabili (CRUD) | βœ… | βœ… | βœ… | ❌ UnitΓ  Immobiliari | βœ… | βœ… | βœ… | πŸ‘οΈ Soggetti (CRUD) | βœ… | βœ… | βœ… | ❌ Documenti (Upload) | βœ… | βœ… | βœ… | ❌ Documenti (Download) | βœ… | βœ… | βœ… | βœ… ContabilitΓ  (CRUD) | βœ… | βœ… | ⚠️ | πŸ‘οΈ Tickets (Gestione) | βœ… | βœ… | βœ… | πŸ“ Backup Sistema | βœ… | βœ… | ❌ | ❌ Reports Avanzati | βœ… | βœ… | ⚠️ | ❌ ``` *Legenda: βœ… = Completo, ⚠️ = Limitato, πŸ‘οΈ = Solo visualizzazione, πŸ“ = Creazione/Risposta, ❌ = Negato* --- ## 6.2 Configurazione Spatie Permission ### Installazione Package ```bash composer require spatie/laravel-permission php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" php artisan migrate ``` ### Configurazione **File**: `config/permission.php` ```php [ 'permission' => Spatie\Permission\Models\Permission::class, 'role' => Spatie\Permission\Models\Role::class, ], 'table_names' => [ 'roles' => 'roles', 'permissions' => 'permissions', 'model_has_permissions' => 'model_has_permissions', 'model_has_roles' => 'model_has_roles', 'role_has_permissions' => 'role_has_permissions', ], 'column_names' => [ 'role_pivot_key' => null, 'permission_pivot_key' => null, 'model_morph_key' => 'model_id', 'team_foreign_key' => 'team_id', ], 'register_permission_check_method' => true, 'teams' => false, 'use_passport_client_credentials' => false, 'display_permission_in_exception' => false, 'display_role_in_exception' => false, 'enable_wildcard_permission' => false, 'cache' => [ 'expiration_time' => \DateInterval::createFromDateString('24 hours'), 'key' => 'spatie.permission.cache', 'store' => 'default', ], ]; ``` ### Registrazione Middleware **File**: `app/Http/Kernel.php` ```php protected $routeMiddleware = [ // ...existing middleware... 'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class, 'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class, 'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class, ]; ``` --- ## 6.3 Modelli e Relazioni ### Modello User Esteso **File**: `app/Models/User.php` ```php 'datetime', 'last_login_at' => 'datetime', 'is_active' => 'boolean', ]; // Relazioni public function stabiliAmministrati() { return $this->hasMany(Stabile::class, 'amministratore_id'); } public function unitaImmobiliari() { return $this->belongsToMany(UnitaImmobiliare::class, 'diritti_reali') ->withPivot('tipo_diritto', 'quota_proprieta', 'data_inizio', 'data_fine') ->withTimestamps(); } public function tickets() { return $this->hasMany(Ticket::class); } // Helper methods public function isSuperAdmin(): bool { return $this->hasRole('super-admin'); } public function isAdmin(): bool { return $this->hasRole('admin'); } public function isAmministratore(): bool { return $this->hasRole('amministratore'); } public function isCondomino(): bool { return $this->hasRole('condomino'); } public function canManageStabile(Stabile $stabile): bool { if ($this->isSuperAdmin()) { return true; } if ($this->isAdmin() || $this->isAmministratore()) { return $this->stabiliAmministrati()->where('id', $stabile->id)->exists(); } return false; } public function canAccessUnita(UnitaImmobiliare $unita): bool { if ($this->isSuperAdmin()) { return true; } if ($this->isAdmin() || $this->isAmministratore()) { return $this->canManageStabile($unita->stabile); } if ($this->isCondomino()) { return $this->unitaImmobiliari()->where('id', $unita->id)->exists(); } return false; } public function getDisplayRoleName(): string { $roleNames = [ 'super-admin' => 'Super Amministratore', 'admin' => 'Amministratore', 'amministratore' => 'Amministratore Condominio', 'condomino' => 'Condomino', ]; $role = $this->getRoleNames()->first(); return $roleNames[$role] ?? 'Utente'; } public function getRoleColor(): string { $roleColors = [ 'super-admin' => 'danger', 'admin' => 'primary', 'amministratore' => 'warning', 'condomino' => 'success', ]; $role = $this->getRoleNames()->first(); return $roleColors[$role] ?? 'secondary'; } } ``` ### Modello Stabile con Controlli Accesso **File**: `app/Models/Stabile.php` ```php 'boolean', ]; // Relazioni public function amministratore(): BelongsTo { return $this->belongsTo(User::class, 'amministratore_id'); } public function comune(): BelongsTo { return $this->belongsTo(ComuneItaliano::class, 'comune_id'); } public function unitaImmobiliari(): HasMany { return $this->hasMany(UnitaImmobiliare::class); } public function documenti(): HasMany { return $this->hasMany(Documento::class); } public function tickets(): HasMany { return $this->hasMany(Ticket::class); } public function movimentiBancari(): HasMany { return $this->hasMany(MovimentoBancario::class); } // Scope per filtri di accesso public function scopeAccessibleBy($query, User $user) { if ($user->isSuperAdmin()) { return $query; } if ($user->isAdmin() || $user->isAmministratore()) { return $query->where('amministratore_id', $user->id); } if ($user->isCondomino()) { return $query->whereHas('unitaImmobiliari.soggetti', function($q) use ($user) { $q->where('users.id', $user->id); }); } return $query->whereRaw('1 = 0'); // Nessun accesso } // Helper methods public function getIndirizzoCompleto(): string { $indirizzo = $this->indirizzo; if ($this->comune) { $indirizzo .= ', ' . $this->comune->denominazione; } if ($this->cap) { $indirizzo .= ' (' . $this->cap . ')'; } return $indirizzo; } public function getTotalUnita(): int { return $this->unitaImmobiliari()->count(); } public function getTotalMillesimi(): float { return $this->unitaImmobiliari()->sum('millesimi_proprieta'); } } ``` --- ## 6.4 Seeder Ruoli e Permessi ### Seeder Completo **File**: `database/seeders/RolesAndPermissionsSeeder.php` ```php forgetCachedPermissions(); // Definizione permessi organizzati per area $permissions = [ // Gestione Utenti 'users.view', 'users.create', 'users.edit', 'users.delete', 'users.assign-roles', 'users.toggle-status', // Gestione Stabili 'stabili.view', 'stabili.create', 'stabili.edit', 'stabili.delete', 'stabili.assign-admin', // Gestione UnitΓ  Immobiliari 'unita.view', 'unita.create', 'unita.edit', 'unita.delete', 'unita.assign-soggetti', // Gestione Soggetti 'soggetti.view', 'soggetti.create', 'soggetti.edit', 'soggetti.delete', 'soggetti.merge', // Gestione Documenti 'documenti.view', 'documenti.upload', 'documenti.download', 'documenti.delete', 'documenti.share', // Gestione ContabilitΓ  'contabilita.view', 'contabilita.create', 'contabilita.edit', 'contabilita.delete', 'contabilita.reports', 'contabilita.export', // Gestione Tickets 'tickets.view', 'tickets.create', 'tickets.edit', 'tickets.delete', 'tickets.assign', 'tickets.close', // Configurazione Sistema 'system.config', 'system.backup', 'system.logs', 'system.maintenance', // Archivi Base 'comuni.view', 'comuni.edit', 'comuni.import', ]; // Crea tutti i permessi foreach ($permissions as $permission) { Permission::create(['name' => $permission]); } // Creazione ruoli $superAdmin = Role::create(['name' => 'super-admin']); $admin = Role::create(['name' => 'admin']); $amministratore = Role::create(['name' => 'amministratore']); $condomino = Role::create(['name' => 'condomino']); // SuperAdmin: tutti i permessi $superAdmin->givePermissionTo(Permission::all()); // Admin: tutti tranne configurazione sistema $admin->givePermissionTo([ 'stabili.view', 'stabili.create', 'stabili.edit', 'stabili.delete', 'unita.view', 'unita.create', 'unita.edit', 'unita.delete', 'unita.assign-soggetti', 'soggetti.view', 'soggetti.create', 'soggetti.edit', 'soggetti.delete', 'soggetti.merge', 'documenti.view', 'documenti.upload', 'documenti.download', 'documenti.delete', 'documenti.share', 'contabilita.view', 'contabilita.create', 'contabilita.edit', 'contabilita.delete', 'contabilita.reports', 'contabilita.export', 'tickets.view', 'tickets.create', 'tickets.edit', 'tickets.delete', 'tickets.assign', 'tickets.close', 'system.backup', 'system.logs', ]); // Amministratore: gestione limitata $amministratore->givePermissionTo([ 'stabili.view', 'stabili.edit', 'unita.view', 'unita.create', 'unita.edit', 'unita.assign-soggetti', 'soggetti.view', 'soggetti.create', 'soggetti.edit', 'documenti.view', 'documenti.upload', 'documenti.download', 'documenti.share', 'contabilita.view', 'contabilita.create', 'contabilita.edit', 'contabilita.reports', 'tickets.view', 'tickets.create', 'tickets.edit', 'tickets.assign', 'tickets.close', ]); // Condomino: solo visualizzazione e interazione limitata $condomino->givePermissionTo([ 'unita.view', 'documenti.view', 'documenti.download', 'contabilita.view', 'tickets.view', 'tickets.create', ]); } } ``` ### Seeder Utenti Base **File**: `database/seeders/UserSeeder.php` ```php 'Super Amministratore', 'email' => 'superadmin@netgescon.it', 'password' => Hash::make('password'), 'is_active' => true, 'email_verified_at' => now(), ]); $superAdmin->assignRole('super-admin'); // Admin $admin = User::create([ 'name' => 'Amministratore Principale', 'email' => 'admin@netgescon.it', 'password' => Hash::make('password'), 'is_active' => true, 'email_verified_at' => now(), ]); $admin->assignRole('admin'); // Amministratore Condominio $amministratore = User::create([ 'name' => 'Mario Rossi', 'email' => 'mario.rossi@netgescon.it', 'password' => Hash::make('password'), 'is_active' => true, 'email_verified_at' => now(), ]); $amministratore->assignRole('amministratore'); // Condomino $condomino = User::create([ 'name' => 'Luigi Bianchi', 'email' => 'luigi.bianchi@netgescon.it', 'password' => Hash::make('password'), 'is_active' => true, 'email_verified_at' => now(), ]); $condomino->assignRole('condomino'); } } ``` --- ## 6.5 Middleware di Protezione ### Middleware Personalizzato **File**: `app/Http/Middleware/RoleAccessMiddleware.php` ```php route('login'); } $user = Auth::user(); // Verifica se utente Γ¨ attivo if (!$user->is_active) { Auth::logout(); return redirect()->route('login') ->with('error', 'Account disattivato. Contatta l\'amministratore.'); } // Verifica ruoli if (!$user->hasAnyRole($roles)) { abort(403, 'Accesso non autorizzato per questo ruolo.'); } // Aggiorna ultimo login $user->update(['last_login_at' => now()]); return $next($request); } } ``` ### Middleware Permessi Specifici **File**: `app/Http/Middleware/PermissionMiddleware.php` ```php route('login'); } $user = Auth::user(); if (!$user->can($permission)) { if ($request->ajax()) { return response()->json([ 'error' => 'Permesso negato', 'message' => "Non hai i permessi per: {$permission}" ], 403); } abort(403, "Permesso negato: {$permission}"); } return $next($request); } } ``` --- ## 6.6 Controllers per Ruoli ### Controller SuperAdmin **File**: `app/Http/Controllers/SuperAdmin/SuperAdminDashboardController.php` ```php middleware(['auth', 'role:super-admin']); } public function index() { $stats = [ 'users_total' => User::count(), 'users_active' => User::where('is_active', true)->count(), 'stabili_total' => Stabile::count(), 'stabili_active' => Stabile::where('is_active', true)->count(), 'comuni_loaded' => ComuneItaliano::count(), 'tickets_open' => Ticket::where('stato', 'aperto')->count(), 'users_by_role' => User::join('model_has_roles', 'users.id', '=', 'model_has_roles.model_id') ->join('roles', 'model_has_roles.role_id', '=', 'roles.id') ->selectRaw('roles.name, COUNT(*) as count') ->groupBy('roles.name') ->pluck('count', 'name') ->toArray(), ]; return view('superadmin.dashboard', [ 'pageTitle' => 'Dashboard Super Amministratore', 'stats' => $stats, ]); } } ``` ### Controller Admin **File**: `app/Http/Controllers/Admin/AdminDashboardController.php` ```php middleware(['auth', 'role:admin|amministratore']); } public function index() { $user = Auth::user(); $stabiliIds = $user->stabiliAmministrati()->pluck('id'); $stats = [ 'stabili_count' => $stabiliIds->count(), 'stabili_attivi' => $user->stabiliAmministrati()->where('is_active', true)->count(), 'unita_total' => UnitaImmobiliare::whereIn('stabile_id', $stabiliIds)->count(), 'documenti_count' => Documento::whereIn('stabile_id', $stabiliIds)->count(), 'documenti_mese' => Documento::whereIn('stabile_id', $stabiliIds) ->whereMonth('created_at', now()->month) ->count(), 'tickets_aperti' => Ticket::whereIn('stabile_id', $stabiliIds) ->where('stato', 'aperto')->count(), 'tickets_totali' => Ticket::whereIn('stabile_id', $stabiliIds)->count(), 'saldo_totale' => MovimentoBancario::whereIn('stabile_id', $stabiliIds) ->sum('importo'), 'condomini_count' => UnitaImmobiliare::whereIn('stabile_id', $stabiliIds) ->has('soggetti')->count(), 'proprietari_count' => UnitaImmobiliare::whereIn('stabile_id', $stabiliIds) ->whereHas('soggetti', function($q) { $q->where('tipo_diritto', 'proprietario'); })->count(), 'movimenti_count' => MovimentoBancario::whereIn('stabile_id', $stabiliIds)->count(), ]; return view('admin.dashboard', [ 'pageTitle' => 'Dashboard Amministrazione', 'stats' => $stats, 'user' => $user, ]); } } ``` ### Controller Condomino **File**: `app/Http/Controllers/Condomino/CondominoDashboardController.php` ```php middleware(['auth', 'role:condomino']); } public function index() { $user = Auth::user(); $unitaIds = $user->unitaImmobiliari()->pluck('unita_immobiliari.id'); $stabiliIds = $user->unitaImmobiliari()->pluck('stabile_id'); $stats = [ 'unita_count' => $unitaIds->count(), 'documenti_count' => Documento::whereIn('stabile_id', $stabiliIds)->count(), 'tickets_aperti' => Ticket::where('user_id', $user->id) ->where('stato', 'aperto')->count(), 'tickets_totali' => Ticket::where('user_id', $user->id)->count(), 'movimenti_mese' => MovimentoBancario::whereIn('stabile_id', $stabiliIds) ->whereMonth('data_movimento', now()->month) ->count(), ]; $unita = $user->unitaImmobiliari() ->with(['stabile', 'stabile.comune']) ->get(); return view('condomino.dashboard', [ 'pageTitle' => 'Area Condomino', 'stats' => $stats, 'unita' => $unita, 'user' => $user, ]); } } ``` --- ## 6.7 Dashboard Condizionali ### Router Principale **File**: `app/Http/Controllers/DashboardController.php` ```php middleware('auth'); } public function index() { $user = Auth::user(); // Redirect in base al ruolo if ($user->hasRole('super-admin')) { return redirect()->route('superadmin.dashboard'); } if ($user->hasAnyRole(['admin', 'amministratore'])) { return redirect()->route('admin.dashboard'); } if ($user->hasRole('condomino')) { return redirect()->route('condomino.dashboard'); } // Fallback per utenti senza ruolo return view('dashboard.no-role', [ 'pageTitle' => 'Accesso Negato', 'message' => 'Nessun ruolo assegnato. Contatta l\'amministratore.', ]); } } ``` --- ## 6.8 Gestione Utenti ### Form Assegnazione Ruoli **File**: `resources/views/superadmin/users/edit-roles.blade.php` ```blade
@csrf @method('PUT')
Gestione Ruoli: {{ $user->name }}
@foreach($roles as $role)
hasRole($role->name) ? 'checked' : '' }}>
@endforeach
``` ### Controller Gestione Ruoli **File**: `app/Http/Controllers/SuperAdmin/UserRoleController.php` ```php middleware(['auth', 'role:super-admin']); } public function editRoles(User $user) { $roles = Role::all(); $roleDescriptions = [ 'super-admin' => 'Accesso completo al sistema', 'admin' => 'Gestione completa stabili assegnati', 'amministratore' => 'Gestione limitata stabili assegnati', 'condomino' => 'Visualizzazione dati personali', ]; return view('superadmin.users.edit-roles', compact('user', 'roles', 'roleDescriptions')); } public function updateRoles(Request $request, User $user) { $request->validate([ 'roles' => 'array', 'roles.*' => 'exists:roles,name', ]); $user->syncRoles($request->get('roles', [])); return redirect()->route('superadmin.users.index') ->with('success', "Ruoli aggiornati per {$user->name}"); } } ``` --- ## 6.9 Esempi Pratici ### Verifica Permessi in Blade ```blade @can('stabili.create') Nuovo Stabile @endcan @role('super-admin')
ModalitΓ  Super Amministratore attiva
@endrole @hasrole('admin|amministratore')
Pannello Gestione
@endhasrole ``` ### Controllo Accesso in Controller ```php public function show(Stabile $stabile) { $user = Auth::user(); // Verifica accesso al singolo stabile if (!$user->canManageStabile($stabile)) { abort(403, 'Non puoi accedere a questo stabile'); } return view('admin.stabili.show', compact('stabile')); } ``` ### Policy per Modelli **File**: `app/Policies/StabilePolicy.php` ```php can('stabili.view'); } public function view(User $user, Stabile $stabile): bool { return $user->can('stabili.view') && $user->canManageStabile($stabile); } public function create(User $user): bool { return $user->can('stabili.create'); } public function update(User $user, Stabile $stabile): bool { return $user->can('stabili.edit') && $user->canManageStabile($stabile); } public function delete(User $user, Stabile $stabile): bool { return $user->can('stabili.delete') && $user->canManageStabile($stabile); } } ``` --- --- ## 6.10 CREAZIONE MODULI NETGESCON - GUIDA COMPLETA πŸš€ ### πŸ“‹ PROBLEMI COMUNI E SOLUZIONI DEFINITIVE #### πŸ”₯ **ERRORI CRITICI DA EVITARE** 1. **Layout NON NetGescon** ```php // ❌ SBAGLIATO @extends('modules.layouts.base') // βœ… CORRETTO @extends('admin.layouts.netgescon') ``` 2. **Database Columns Inesistenti** ```php // ❌ SBAGLIATO - Campo 'codice' non esiste $piano_conti = DB::table('piano_conti')->select('codice', 'descrizione')->get(); // βœ… CORRETTO - Campi reali della tabella $piano_conti = DB::table('piano_conti')->select('mastro', 'conto', 'sottoconto', 'descrizione')->get(); ``` 3. **Route Conflicts** ```php // ❌ SBAGLIATO - Conflitti con routes esistenti Route::resource('contabilita', ContabilitaController::class); // βœ… CORRETTO - Prefix specifico per moduli Route::prefix('admin')->name('admin.')->group(function () { Route::resource('contabilita', ContabilitaController::class)->names([ 'index' => 'contabilita.index', 'create' => 'contabilita.create', 'store' => 'contabilita.store', 'show' => 'contabilita.show', 'edit' => 'contabilita.edit', 'update' => 'contabilita.update', 'destroy' => 'contabilita.destroy' ]); }); ``` ### πŸ—οΈ **STRUTTURA MODULO STANDARD** ``` app/Modules/[NomeModulo]/ β”œβ”€β”€ Controllers/ β”‚ └── [NomeModulo]Controller.php β”œβ”€β”€ Models/ β”‚ └── [NomeModulo].php β”œβ”€β”€ Routes/ β”‚ └── web.php └── Views/ β”œβ”€β”€ index.blade.php β”œβ”€β”€ create.blade.php β”œβ”€β”€ edit.blade.php └── show.blade.php resources/views/modules/[nomemodulo]/ β”œβ”€β”€ index.blade.php β”œβ”€β”€ create.blade.php β”œβ”€β”€ edit.blade.php └── show.blade.php ``` ### 🎨 **TEMPLATE BASE NETGESCON** #### Index.blade.php Standard ```php @extends('admin.layouts.netgescon') @section('title', '[Nome Modulo]') @section('content')

[Nome Modulo]

Elenco [Nome Modulo]

@endsection ``` #### Create.blade.php Standard ```php @extends('admin.layouts.netgescon') @section('title', 'Nuovo [Nome Modulo]') @section('content')

Nuovo [Nome Modulo]

Nuovo [Nome Modulo]

@csrf
@endsection ``` ### �️ **CONTROLLER STANDARD** ```php get(); return view('modules.[nomemodulo].index', compact('items')); } public function create() { // Carica dati necessari per il form // ATTENZIONE: Usa SEMPRE i nomi colonne reali del DB return view('modules.[nomemodulo].create'); } public function store(Request $request) { $request->validate([ // Validazioni ]); DB::table('[nome_tabella]')->insert([ // Campi corretti del database 'created_at' => now(), 'updated_at' => now() ]); return redirect()->route('admin.[nomemodulo].index') ->with('success', '[Nome Modulo] creato con successo!'); } public function show($id) { $item = DB::table('[nome_tabella]')->where('id', $id)->first(); if (!$item) { abort(404); } return view('modules.[nomemodulo].show', compact('item')); } public function edit($id) { $item = DB::table('[nome_tabella]')->where('id', $id)->first(); if (!$item) { abort(404); } return view('modules.[nomemodulo].edit', compact('item')); } public function update(Request $request, $id) { $request->validate([ // Validazioni ]); DB::table('[nome_tabella]') ->where('id', $id) ->update([ // Campi da aggiornare 'updated_at' => now() ]); return redirect()->route('admin.[nomemodulo].index') ->with('success', '[Nome Modulo] aggiornato con successo!'); } public function destroy($id) { DB::table('[nome_tabella]')->where('id', $id)->delete(); return redirect()->route('admin.[nomemodulo].index') ->with('success', '[Nome Modulo] eliminato con successo!'); } } ``` ### πŸ—„οΈ **STRUTTURA DATABASE STANDARD** #### Credenziali Database NetGescon ```env DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=netgescon DB_USERNAME=netgescon_user DB_PASSWORD=NetGescon2024! ``` #### Convenzioni Naming Database ```sql -- βœ… CORRETTO - Nomi italiani senza accenti CREATE TABLE piano_conti ( id INT PRIMARY KEY AUTO_INCREMENT, mastro VARCHAR(10) NOT NULL, conto VARCHAR(10) NOT NULL, sottoconto VARCHAR(10) NOT NULL, descrizione VARCHAR(255) NOT NULL, tipo ENUM('DARE', 'AVERE') NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); -- Esempio tabella contabilita CREATE TABLE registrazioni_contabili ( id INT PRIMARY KEY AUTO_INCREMENT, data_registrazione DATE NOT NULL, numero_documento VARCHAR(50), descrizione TEXT NOT NULL, totale_dare DECIMAL(10,2) DEFAULT 0, totale_avere DECIMAL(10,2) DEFAULT 0, stabile_id INT NOT NULL, gestione_id INT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (stabile_id) REFERENCES stabili(id), FOREIGN KEY (gestione_id) REFERENCES gestioni(id) ); -- Tabella movimenti contabili CREATE TABLE movimenti_contabili ( id INT PRIMARY KEY AUTO_INCREMENT, registrazione_id INT NOT NULL, piano_conti_id INT NOT NULL, dare DECIMAL(10,2) DEFAULT 0, avere DECIMAL(10,2) DEFAULT 0, descrizione VARCHAR(255), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (registrazione_id) REFERENCES registrazioni_contabili(id) ON DELETE CASCADE, FOREIGN KEY (piano_conti_id) REFERENCES piano_conti(id) ); ``` ### πŸ”§ **ROUTES CONFIGURATION** #### File: routes/web.php - Sezione Moduli ```php // ===== MODULI AMMINISTRATIVI ===== Route::prefix('admin')->name('admin.')->middleware(['auth', 'role:Admin|SuperAdmin'])->group(function () { // ContabilitΓ  Module Route::resource('contabilita', App\Modules\Contabilita\Controllers\ContabilitaController::class)->names([ 'index' => 'contabilita.index', 'create' => 'contabilita.create', 'store' => 'contabilita.store', 'show' => 'contabilita.show', 'edit' => 'contabilita.edit', 'update' => 'contabilita.update', 'destroy' => 'contabilita.destroy' ]); // Altri moduli... }); ``` ### 🎨 **SUB-MENU STYLE COME STABILI** Per implementare il sub-menu come nella pagina stabili, aggiungi questa sezione dopo il content-header: ```php
``` ### οΏ½πŸ“ **CHECKLIST MODULO COMPLETO** #### Pre-Sviluppo - [ ] Verificare struttura database esistente - [ ] Controllare credenziali database (netgescon_user/NetGescon2024!) - [ ] Verificare nomi tabelle e colonne reali - [ ] Pianificare routes senza conflitti #### Durante Sviluppo - [ ] Controller con namespace corretto - [ ] Routes con prefix 'admin' e name 'admin.' - [ ] Views che estendono 'admin.layouts.netgescon' - [ ] Query database con colonne esistenti - [ ] Validazioni form corrette - [ ] Breadcrumb navigation funzionante #### Post-Sviluppo - [ ] Test tutte le routes (index, create, store, show, edit, update, destroy) - [ ] Verifica layout NetGescon caricato correttamente - [ ] Test permessi e autorizzazioni - [ ] Validazione form funzionante - [ ] Test CRUD completo - [ ] Verifica responsive design ### 🚨 **PROBLEMI RISOLTI - CASO CONTABILITΓ€** 1. **Layout Wrong**: Cambiato da `modules.layouts.base` a `admin.layouts.netgescon` 2. **Database Columns**: Corretto `codice` inesistente con `mastro`, `conto`, `sottoconto` 3. **Route Conflicts**: Aggiunto prefix `admin` e namespace specifico 4. **Credentials**: Usato `netgescon_user/NetGescon2024!` invece di default 5. **Display Format**: Piano conti ora mostra `mastro.conto.sottoconto - descrizione` ### 🎯 **TEMPLATE RAPIDO NUOVO MODULO** Usa questo comando per creare rapidamente la struttura: ```bash # Crea directories mkdir -p app/Modules/[NomeModulo]/Controllers mkdir -p app/Modules/[NomeModulo]/Models mkdir -p resources/views/modules/[nomemodulo] # Copia template files dal modulo ContabilitΓ  funzionante cp -r app/Modules/Contabilita/* app/Modules/[NomeModulo]/ cp -r resources/views/modules/contabilita/* resources/views/modules/[nomemodulo]/ # Sostituisci tutti i riferimenti find app/Modules/[NomeModulo] -type f -name "*.php" -exec sed -i 's/Contabilita/[NomeModulo]/g' {} \; find resources/views/modules/[nomemodulo] -type f -name "*.php" -exec sed -i 's/contabilita/[nomemodulo]/g' {} \; ``` --- **πŸ“ COMPLETATO: Capitolo 6 - Sistema Multi-Ruolo + Creazione Moduli** Questo capitolo fornisce una guida completa per: - βœ… Configurare architettura ruoli e permessi - βœ… Implementare Spatie Permission - βœ… Creare modelli con controlli accesso - βœ… Configurare seeder ruoli e permessi - βœ… Implementare middleware protezione - βœ… Creare controllers per ogni ruolo - βœ… Gestire dashboard condizionali - βœ… Amministrare utenti e ruoli - βœ… Esempi pratici implementazione - βœ… **GUIDA COMPLETA CREAZIONE MODULI NETGESCON** - βœ… **RISOLUZIONE ERRORI COMUNI** - βœ… **TEMPLATE STANDARD E CHECKLIST** **πŸ”„ Prossimo capitolo: Database e Strutture Avanzate**