# SPECIFICHE AUTENTICAZIONE - NetGesCon Unified Platform

## 🎯 OBIETTIVO
Implementare un sistema di autenticazione unificato tramite **codice utente unico** che sostituisce il sistema tradizionale username/password, con gestione centralizzata delle sessioni e accesso alle cartelle dati specifiche per utente/ruolo.

## 🔑 SISTEMA AUTENTICAZIONE CODICE UNICO

### STRUTTURA CODICE UTENTE
```
Formato: [PREFISSO]-[IDENTIFICATIVO]-[CHECKSUM]
Esempio: ADM-001234-A7B
         CON-098765-K3Z
         FOR-543210-M9P
```

### PREFISSI RUOLO
- **SUP** - Super Admin
- **ADM** - Amministratore
- **CON** - Condomino  
- **FOR** - Fornitore
- **COL** - Collaboratore

### GENERAZIONE CODICI
- **Algoritmo:** Base su hash di dati utente + timestamp
- **Checksum:** 3 caratteri alfanumerici per validazione
- **Unicità:** Controllo globale su tutti i ruoli
- **Regenerazione:** Possibile in caso di compromissione

## 📂 STRUTTURA CARTELLE DATI

### CARTELLA PRINCIPALE
```
/data/users/
├── SUP-000001-X9Z/          # Super Admin
│   ├── config/              # Configurazioni globali
│   ├── logs/                # Log sistema
│   ├── backups/             # Backup automatici
│   └── reports/             # Report globali
├── ADM-001234-A7B/          # Amministratore Rossi
│   ├── condominii/          # Dati condominii gestiti
│   │   ├── stabile_001/
│   │   ├── stabile_002/
│   │   └── ...
│   ├── documenti/           # Documenti personali
│   ├── templates/           # Template personalizzati
│   └── reports/             # Report specifici
├── CON-098765-K3Z/          # Condomino Bianchi
│   ├── documenti/           # Documenti ricevuti
│   ├── comunicazioni/       # Comunicazioni con admin
│   ├── estratti_conto/      # Estratti conto personali
│   └── pagamenti/           # Storico pagamenti
└── FOR-543210-M9P/          # Fornitore VerdiSrl
    ├── preventivi/          # Preventivi inviati
    ├── fatture/             # Fatture emesse
    ├── ordini/              # Ordini ricevuti
    └── comunicazioni/       # Comunicazioni
```

### PERMESSI CARTELLE
- **Lettura/Scrittura:** Solo proprietario cartella
- **Backup Admin:** Super admin accesso sola lettura
- **Condivisione:** Tramite sistema interno (no accesso diretto)
- **Audit:** Log di tutti gli accessi

## 🔐 IMPLEMENTAZIONE TECNICA

### DATABASE SCHEMA

#### Tabella `users`
```sql
CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_code VARCHAR(20) UNIQUE NOT NULL,  -- Codice utente unico
    email VARCHAR(255) UNIQUE,              -- Email opzionale
    phone VARCHAR(20),                      -- Telefono opzionale
    role_id BIGINT NOT NULL,                -- FK a roles
    status ENUM('active', 'suspended', 'disabled') DEFAULT 'active',
    data_folder VARCHAR(255) NOT NULL,      -- Percorso cartella dati
    last_login TIMESTAMP NULL,
    login_attempts INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_user_code (user_code),
    INDEX idx_role_id (role_id),
    INDEX idx_status (status)
);
```

#### Tabella `user_sessions`
```sql
CREATE TABLE user_sessions (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    session_token VARCHAR(255) NOT NULL,
    ip_address VARCHAR(45),
    user_agent TEXT,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_id (user_id),
    INDEX idx_session_token (session_token),
    INDEX idx_expires_at (expires_at),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
```

#### Tabella `login_logs`
```sql
CREATE TABLE login_logs (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_code VARCHAR(20),
    ip_address VARCHAR(45),
    user_agent TEXT,
    login_success BOOLEAN NOT NULL,
    failure_reason VARCHAR(255) NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_code (user_code),
    INDEX idx_login_success (login_success),
    INDEX idx_created_at (created_at)
);
```

### MIDDLEWARE AUTHENTICATION

#### `CodeAuthMiddleware.php`
```php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use App\Services\AuthService;

class CodeAuthMiddleware
{
    protected $authService;

    public function __construct(AuthService $authService)
    {
        $this->authService = $authService;
    }

    public function handle(Request $request, Closure $next)
    {
        // Verifica presenza codice utente nella sessione
        $userCode = $request->session()->get('user_code');
        
        if (!$userCode) {
            return redirect()->route('login');
        }

        // Valida sessione attiva
        if (!$this->authService->validateSession($userCode)) {
            $request->session()->flush();
            return redirect()->route('login')->with('error', 'Sessione scaduta');
        }

        // Carica dati utente nel request
        $user = $this->authService->getUserByCode($userCode);
        $request->merge(['auth_user' => $user]);

        return $next($request);
    }
}
```

### SERVICE LAYER

#### `AuthService.php`
```php
<?php

namespace App\Services;

use App\Models\User;
use App\Models\UserSession;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;

class AuthService
{
    public function authenticateByCode(string $userCode, string $ipAddress, string $userAgent): ?User
    {
        // Valida formato codice
        if (!$this->validateCodeFormat($userCode)) {
            $this->logFailedLogin($userCode, $ipAddress, $userAgent, 'Invalid code format');
            return null;
        }

        // Cerca utente
        $user = User::where('user_code', $userCode)
                   ->where('status', 'active')
                   ->first();

        if (!$user) {
            $this->logFailedLogin($userCode, $ipAddress, $userAgent, 'User not found');
            return null;
        }

        // Crea sessione
        $sessionToken = $this->createSession($user, $ipAddress, $userAgent);
        
        // Log login riuscito
        $this->logSuccessfulLogin($userCode, $ipAddress, $userAgent);
        
        return $user;
    }

    public function generateUserCode(string $rolePrefix, array $userData): string
    {
        // Genera ID progressivo
        $lastUser = User::where('user_code', 'LIKE', $rolePrefix . '-%')
                       ->orderBy('user_code', 'desc')
                       ->first();
        
        $nextId = 1;
        if ($lastUser) {
            $parts = explode('-', $lastUser->user_code);
            $nextId = intval($parts[1]) + 1;
        }

        $identifier = sprintf('%06d', $nextId);
        
        // Genera checksum
        $checksum = $this->generateChecksum($rolePrefix, $identifier, $userData);
        
        return $rolePrefix . '-' . $identifier . '-' . $checksum;
    }

    private function generateChecksum(string $prefix, string $identifier, array $userData): string
    {
        $data = $prefix . $identifier . json_encode($userData) . config('app.key');
        $hash = hash('sha256', $data);
        
        // Prendi i primi 3 caratteri e convertili in alfanumerico
        $checksum = '';
        for ($i = 0; $i < 6; $i += 2) {
            $hex = substr($hash, $i, 2);
            $dec = hexdec($hex);
            $checksum .= base_convert($dec, 10, 36);
        }
        
        return strtoupper(substr($checksum, 0, 3));
    }

    private function validateCodeFormat(string $code): bool
    {
        // Formato: XXX-NNNNNN-XXX
        $pattern = '/^[A-Z]{3}-\d{6}-[A-Z0-9]{3}$/';
        return preg_match($pattern, $code);
    }

    public function createDataFolder(User $user): bool
    {
        $basePath = config('filesystems.disks.user_data.root', storage_path('app/user_data'));
        $userPath = $basePath . '/' . $user->user_code;

        if (!file_exists($userPath)) {
            return mkdir($userPath, 0755, true) && $this->createUserSubfolders($userPath, $user->role->name);
        }

        return true;
    }

    private function createUserSubfolders(string $userPath, string $roleName): bool
    {
        $subfolders = match($roleName) {
            'super-admin' => ['config', 'logs', 'backups', 'reports'],
            'admin' => ['condominii', 'documenti', 'templates', 'reports'],
            'condomino' => ['documenti', 'comunicazioni', 'estratti_conto', 'pagamenti'],
            'fornitore' => ['preventivi', 'fatture', 'ordini', 'comunicazioni'],
            'collaboratore' => ['documenti', 'task', 'comunicazioni'],
            default => ['documenti', 'comunicazioni']
        };

        foreach ($subfolders as $folder) {
            $path = $userPath . '/' . $folder;
            if (!mkdir($path, 0755, true)) {
                return false;
            }
        }

        return true;
    }
}
```

## 🔄 FLUSSO AUTENTICAZIONE

### LOGIN PROCESS
1. **Input:** Utente inserisce codice unico
2. **Validazione:** Controllo formato e checksum
3. **Ricerca:** Query database per codice
4. **Verifica:** Controllo stato utente attivo
5. **Sessione:** Creazione token sessione
6. **Redirect:** Invio alla dashboard appropriata

### LOGOUT PROCESS
1. **Trigger:** Logout manuale o timeout
2. **Cleanup:** Rimozione token sessione
3. **Audit:** Log dell'operazione
4. **Redirect:** Invio alla pagina login

### SESSION MANAGEMENT
- **Durata:** 8 ore lavorative (configurabile)
- **Refresh:** Automatico su attività
- **Concurrent:** Massimo 3 sessioni attive per utente
- **Cleanup:** Job automatico rimozione sessioni scadute

## 🛡️ SICUREZZA

### PROTEZIONI
- **Rate Limiting:** Max 5 tentativi login/minuto per IP
- **Account Lockout:** Dopo 5 tentativi falliti (15 min block)
- **Session Hijacking:** Controllo IP e User-Agent
- **CSRF Protection:** Token su tutte le form

### AUDIT E MONITORING
- **Login Logs:** Tutti i tentativi di accesso
- **Access Logs:** Accesso a file/cartelle utente
- **Error Logs:** Tentativi non autorizzati
- **Performance:** Tempi di risposta autenticazione

---

**Ultima modifica:** $(Get-Date -Format "dd/MM/yyyy HH:mm")  
**Versione:** 1.0  
**Stato:** Da Implementare
