# 🏢 MODULO STABILE - Specifiche Complete

## 📋 OVERVIEW
Il **Modulo Stabile** è il modulo fondamentale di NetGesCon che gestisce l'anagrafica completa degli stabili/condomini e rappresenta il punto di partenza per tutti gli altri moduli del sistema.

---

## 🎯 OBIETTIVI DEL MODULO

### ✅ Funzionalità Core
- **Anagrafica Stabile Completa**: Tutti i dati identificativi e tecnici
- **Codici Univoci**: Sistema di identificazione a 8 caratteri  
- **Multi-Gestione**: Un amministratore può gestire più stabili
- **Configurazioni Personalizzate**: Settings specifici per tipologia stabile
- **Storico Modifiche**: Audit trail completo delle variazioni

### 🔗 Integrazione Sistema
- **Base per tutti i moduli**: Ogni funzionalità parte dal concetto di stabile
- **Permessi Granulari**: Controllo accessi per stabile
- **Dashboard Dedicata**: Vista riassuntiva per ogni stabile
- **API Complete**: Endpoint REST per integrazione

---

## 💾 STRUTTURA DATABASE

### 📊 Tabella: `stabili`
```sql
CREATE TABLE stabili (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    codice_stabile VARCHAR(8) UNIQUE NOT NULL COMMENT 'Codice univoco 8 caratteri',
    denominazione VARCHAR(255) NOT NULL,
    
    -- Dati Legali/Fiscali
    codice_fiscale VARCHAR(16) UNIQUE,
    partita_iva VARCHAR(11),
    natura_giuridica ENUM('condominio', 'cooperativa', 'societa', 'altro') DEFAULT 'condominio',
    
    -- Indirizzo Completo
    indirizzo VARCHAR(255) NOT NULL,
    numero_civico VARCHAR(10),
    cap VARCHAR(5) NOT NULL,
    citta VARCHAR(100) NOT NULL,
    provincia CHAR(2) NOT NULL,
    regione VARCHAR(50) NOT NULL,
    nazione VARCHAR(50) DEFAULT 'Italia',
    
    -- Dati Tecnici Edificio
    anno_costruzione YEAR,
    numero_piani TINYINT UNSIGNED,
    numero_unita SMALLINT UNSIGNED NOT NULL DEFAULT 0,
    superficie_totale DECIMAL(10,2),
    tipologia_edificio ENUM('residenziale', 'commerciale', 'misto', 'industriale') DEFAULT 'residenziale',
    
    -- Dati Catastali
    foglio VARCHAR(10),
    particella VARCHAR(10),
    subalterno VARCHAR(10),
    categoria_catastale VARCHAR(5),
    classe_energetica ENUM('A4', 'A3', 'A2', 'A1', 'B', 'C', 'D', 'E', 'F', 'G'),
    
    -- Gestione Amministrativa
    user_id BIGINT UNSIGNED NOT NULL COMMENT 'Amministratore responsabile',
    data_inizio_gestione DATE NOT NULL,
    data_fine_gestione DATE NULL,
    stato ENUM('attivo', 'sospeso', 'chiuso') DEFAULT 'attivo',
    
    -- Configurazioni
    configurazioni JSON COMMENT 'Settings specifici stabile',
    
    -- Timestamps e Audit
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    created_by BIGINT UNSIGNED,
    updated_by BIGINT UNSIGNED,
    
    -- Indici
    INDEX idx_codice_stabile (codice_stabile),
    INDEX idx_user_id (user_id),
    INDEX idx_stato (stato),
    INDEX idx_citta_provincia (citta, provincia),
    
    -- Foreign Keys
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT,
    FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
    FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

### 📊 Tabella: `stabili_configurazioni`
```sql
CREATE TABLE stabili_configurazioni (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    stabile_id BIGINT UNSIGNED NOT NULL,
    
    -- Configurazioni Contabili
    piano_conti_personalizzato BOOLEAN DEFAULT FALSE,
    gestione_anticipi BOOLEAN DEFAULT TRUE,
    calcolo_interessi_mora BOOLEAN DEFAULT TRUE,
    tasso_interesse_mora DECIMAL(5,2) DEFAULT 0.50,
    
    -- Configurazioni Millesimali
    numero_tabelle_millesimali TINYINT DEFAULT 1,
    aggiornamento_automatico_millesimi BOOLEAN DEFAULT FALSE,
    validazione_matematica_millesimi BOOLEAN DEFAULT TRUE,
    
    -- Configurazioni Comunicazioni
    email_amministratore VARCHAR(255),
    telefono_amministratore VARCHAR(20),
    pec_stabile VARCHAR(255),
    sito_web VARCHAR(255),
    
    -- Configurazioni Fatturazione  
    formato_fattura ENUM('standard', 'semplificata', 'elettronica') DEFAULT 'standard',
    numerazione_fatture VARCHAR(50) DEFAULT 'YYYY/NNNN',
    iva_default DECIMAL(5,2) DEFAULT 22.00,
    
    -- Configurazioni Backup
    backup_automatico BOOLEAN DEFAULT TRUE,
    frequenza_backup ENUM('giornaliero', 'settimanale', 'mensile') DEFAULT 'settimanale',
    retention_backup SMALLINT DEFAULT 12 COMMENT 'Mesi',
    
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE CASCADE,
    UNIQUE KEY uk_stabile_configurazioni (stabile_id)
) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

---

## 🔧 CONTROLLER LARAVEL

### 📝 StabileController
```php
<?php

namespace App\Http\Controllers;

use App\Models\Stabile;
use App\Http\Requests\StabileRequest;
use App\Services\StabileService;
use Illuminate\Http\Request;

class StabileController extends Controller
{
    protected $stabileService;
    
    public function __construct(StabileService $stabileService)
    {
        $this->stabileService = $stabileService;
        $this->middleware('auth');
        $this->middleware('permission:stabili.view')->only(['index', 'show']);
        $this->middleware('permission:stabili.create')->only(['create', 'store']);
        $this->middleware('permission:stabili.edit')->only(['edit', 'update']);
        $this->middleware('permission:stabili.delete')->only(['destroy']);
    }
    
    /**
     * Lista stabili con filtri e ricerca
     */
    public function index(Request $request)
    {
        $stabili = $this->stabileService->getFilteredStabili($request->all());
        
        return view('stabili.index', compact('stabili'));
    }
    
    /**
     * Form creazione nuovo stabile
     */
    public function create()
    {
        return view('stabili.create');
    }
    
    /**
     * Salvataggio nuovo stabile
     */
    public function store(StabileRequest $request)
    {
        try {
            $stabile = $this->stabileService->createStabile($request->validated());
            
            return redirect()->route('stabili.show', $stabile)
                           ->with('success', 'Stabile creato con successo!');
        } catch (\Exception $e) {
            return back()->withInput()
                        ->with('error', 'Errore durante la creazione: ' . $e->getMessage());
        }
    }
    
    /**
     * Visualizzazione dettaglio stabile
     */
    public function show(Stabile $stabile)
    {
        $this->authorize('view', $stabile);
        
        $stabile->load(['unita', 'configurazioni', 'documenti']);
        $statistiche = $this->stabileService->getStatistiche($stabile);
        
        return view('stabili.show', compact('stabile', 'statistiche'));
    }
    
    /**
     * Form modifica stabile
     */
    public function edit(Stabile $stabile)
    {
        $this->authorize('update', $stabile);
        
        return view('stabili.edit', compact('stabile'));
    }
    
    /**
     * Aggiornamento stabile
     */
    public function update(StabileRequest $request, Stabile $stabile)
    {
        $this->authorize('update', $stabile);
        
        try {
            $this->stabileService->updateStabile($stabile, $request->validated());
            
            return redirect()->route('stabili.show', $stabile)
                           ->with('success', 'Stabile aggiornato con successo!');
        } catch (\Exception $e) {
            return back()->withInput()
                        ->with('error', 'Errore durante l\'aggiornamento: ' . $e->getMessage());
        }
    }
    
    /**
     * Eliminazione stabile (soft delete)
     */
    public function destroy(Stabile $stabile)
    {
        $this->authorize('delete', $stabile);
        
        try {
            $this->stabileService->deleteStabile($stabile);
            
            return redirect()->route('stabili.index')
                           ->with('success', 'Stabile eliminato con successo!');
        } catch (\Exception $e) {
            return back()->with('error', 'Errore durante l\'eliminazione: ' . $e->getMessage());
        }
    }
    
    /**
     * Dashboard stabile con statistiche
     */
    public function dashboard(Stabile $stabile)
    {
        $this->authorize('view', $stabile);
        
        $dashboard = $this->stabileService->getDashboardData($stabile);
        
        return view('stabili.dashboard', compact('stabile', 'dashboard'));
    }
}
```

---

## 🎨 INTERFACCE UTENTE

### 📋 Lista Stabili (`stabili/index.blade.php`)
```html
@extends('layouts.app')

@section('content')
<div class="container-fluid">
    <div class="row">
        <div class="col-12">
            <div class="card">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h3>🏢 Gestione Stabili</h3>
                    @can('stabili.create')
                        <a href="{{ route('stabili.create') }}" class="btn btn-primary">
                            <i class="fas fa-plus"></i> Nuovo Stabile
                        </a>
                    @endcan
                </div>
                
                <div class="card-body">
                    <!-- Filtri di Ricerca -->
                    <form method="GET" class="mb-4">
                        <div class="row">
                            <div class="col-md-3">
                                <input type="text" name="search" class="form-control" 
                                       placeholder="Cerca per denominazione..." 
                                       value="{{ request('search') }}">
                            </div>
                            <div class="col-md-2">
                                <select name="stato" class="form-control">
                                    <option value="">Tutti gli stati</option>
                                    <option value="attivo" {{ request('stato') == 'attivo' ? 'selected' : '' }}>Attivo</option>
                                    <option value="sospeso" {{ request('stato') == 'sospeso' ? 'selected' : '' }}>Sospeso</option>
                                    <option value="chiuso" {{ request('stato') == 'chiuso' ? 'selected' : '' }}>Chiuso</option>
                                </select>
                            </div>
                            <div class="col-md-2">
                                <select name="provincia" class="form-control">
                                    <option value="">Tutte le province</option>
                                    @foreach($province as $prov)
                                        <option value="{{ $prov }}" {{ request('provincia') == $prov ? 'selected' : '' }}>
                                            {{ $prov }}
                                        </option>
                                    @endforeach
                                </select>
                            </div>
                            <div class="col-md-2">
                                <button type="submit" class="btn btn-outline-primary">
                                    <i class="fas fa-search"></i> Cerca
                                </button>
                            </div>
                        </div>
                    </form>
                    
                    <!-- Tabella Stabili -->
                    <div class="table-responsive">
                        <table class="table table-striped table-hover">
                            <thead>
                                <tr>
                                    <th>Codice</th>
                                    <th>Denominazione</th>
                                    <th>Indirizzo</th>
                                    <th>Unità</th>
                                    <th>Stato</th>
                                    <th>Azioni</th>
                                </tr>
                            </thead>
                            <tbody>
                                @forelse($stabili as $stabile)
                                    <tr>
                                        <td>
                                            <span class="badge badge-secondary">{{ $stabile->codice_stabile }}</span>
                                        </td>
                                        <td>
                                            <strong>{{ $stabile->denominazione }}</strong>
                                            @if($stabile->tipologia_edificio)
                                                <br><small class="text-muted">{{ ucfirst($stabile->tipologia_edificio) }}</small>
                                            @endif
                                        </td>
                                        <td>
                                            {{ $stabile->indirizzo }} {{ $stabile->numero_civico }}<br>
                                            <small class="text-muted">{{ $stabile->cap }} {{ $stabile->citta }} ({{ $stabile->provincia }})</small>
                                        </td>
                                        <td>
                                            <span class="badge badge-info">{{ $stabile->numero_unita }} unità</span>
                                        </td>
                                        <td>
                                            @switch($stabile->stato)
                                                @case('attivo')
                                                    <span class="badge badge-success">Attivo</span>
                                                    @break
                                                @case('sospeso')
                                                    <span class="badge badge-warning">Sospeso</span>
                                                    @break
                                                @case('chiuso')
                                                    <span class="badge badge-danger">Chiuso</span>
                                                    @break
                                            @endswitch
                                        </td>
                                        <td>
                                            <div class="btn-group" role="group">
                                                @can('view', $stabile)
                                                    <a href="{{ route('stabili.show', $stabile) }}" 
                                                       class="btn btn-sm btn-info" title="Visualizza">
                                                        <i class="fas fa-eye"></i>
                                                    </a>
                                                @endcan
                                                @can('update', $stabile)
                                                    <a href="{{ route('stabili.edit', $stabile) }}" 
                                                       class="btn btn-sm btn-warning" title="Modifica">
                                                        <i class="fas fa-edit"></i>
                                                    </a>
                                                @endcan
                                                @can('delete', $stabile)
                                                    <form method="POST" action="{{ route('stabili.destroy', $stabile) }}" 
                                                          class="d-inline" onsubmit="return confirm('Sei sicuro?')">
                                                        @csrf
                                                        @method('DELETE')
                                                        <button type="submit" class="btn btn-sm btn-danger" title="Elimina">
                                                            <i class="fas fa-trash"></i>
                                                        </button>
                                                    </form>
                                                @endcan
                                            </div>
                                        </td>
                                    </tr>
                                @empty
                                    <tr>
                                        <td colspan="6" class="text-center">
                                            <em>Nessuno stabile trovato</em>
                                        </td>
                                    </tr>
                                @endforelse
                            </tbody>
                        </table>
                    </div>
                    
                    <!-- Paginazione -->
                    {{ $stabili->links() }}
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
```

---

## 🔄 WORKFLOW OPERATIVO

### 📝 Processo Creazione Stabile
1. **Accesso Form**: Admin accede al form di creazione
2. **Validazione Input**: Controllo dati obbligatori e formati
3. **Generazione Codice**: Sistema genera codice univoco 8 caratteri
4. **Salvataggio Database**: Insert in tabella `stabili` con audit
5. **Configurazioni Default**: Creazione configurazioni iniziali
6. **Notifica**: Conferma successo e redirect a dettaglio

### 📊 Dashboard Stabile
1. **Dati Anagrafici**: Visualizzazione completa info stabile
2. **Statistiche**: Numero unità, superfici, millesimi totali
3. **Azioni Rapide**: Link diretti a funzioni principali
4. **Stato Sistema**: Indicatori salute dati e configurazioni
5. **Attività Recenti**: Log ultime modifiche e operazioni

---

## 🔒 SICUREZZA E PERMESSI

### 👥 Livelli Accesso
- **Super Admin**: Accesso totale a tutti gli stabili
- **Amministratore**: Accesso solo ai propri stabili  
- **Collaboratore**: Accesso limitato in base alle assegnazioni
- **Consulente**: Solo visualizzazione dati autorizzati

### 🛡️ Policy Laravel
```php
class StabilePolicy
{
    public function view(User $user, Stabile $stabile)
    {
        return $user->hasPermissionTo('stabili.view') && 
               ($user->hasRole('super-admin') || $user->id === $stabile->user_id);
    }
    
    public function create(User $user)
    {
        return $user->hasPermissionTo('stabili.create');
    }
    
    public function update(User $user, Stabile $stabile)
    {
        return $user->hasPermissionTo('stabili.edit') && 
               ($user->hasRole('super-admin') || $user->id === $stabile->user_id);
    }
    
    public function delete(User $user, Stabile $stabile)
    {
        return $user->hasPermissionTo('stabili.delete') && 
               $user->hasRole('super-admin');
    }
}
```

---

## ✅ TESTING E VALIDAZIONE

### 🧪 Test Unitari
- Validazione creazione stabile
- Verifica unicità codice stabile
- Test configurazioni default
- Controllo permessi accesso

### 🔍 Test Integrazione
- Workflow completo CRUD
- Collegamento con altri moduli
- Test performance query
- Validazione audit trail

---

## 📈 METRICHE E KPI

### 📊 Indicatori Performance
- Tempo risposta liste stabili (< 200ms)
- Accuratezza dati anagrafici (100%)
- Percentuale uptime sistema (99.9%)
- Soddisfazione utenti (> 4.5/5)

### 📋 Reportistica
- Report mensile stabili gestiti
- Statistiche utilizzo funzionalità
- Analisi errori e problematiche
- Trend crescita database

---

## 🚀 PROSSIMI SVILUPPI

### 🔄 Fase 2 - Miglioramenti
- Import massivo da file Excel/CSV
- API REST complete per integrazioni
- Backup automatico differenziale
- Notificazioni push importanti

### 🎯 Fase 3 - Avanzate
- Dashboard analytics avanzate
- Machine learning per previsioni
- Integrazione con servizi esterni
- Mobile app dedicata

---

*Documento tecnico Modulo Stabile | Versione 1.0 | Luglio 2025*
