netgescon-day0/docs/07-struttura-amministratori/02-MODELLO-DATABASE.md

16 KiB

💾 MODELLO DATABASE MULTI-TENANT

Strutture e Relazioni Complete

📅 Data: 07 Agosto 2025

🎯 Implementazione: Database separati per amministratore/stabile


📊 DATABASE PRINCIPALE (netgescon)

🎯 Scopo: Registry centrale e autenticazione

🗄️ Schema Principale

👥 users - Utenti Sistema

CREATE TABLE users (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    email_verified_at TIMESTAMP NULL,
    password VARCHAR(255) NOT NULL,
    remember_token VARCHAR(100) NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    -- Campi aggiuntivi NetGescon
    role ENUM('super_admin', 'admin', 'user') DEFAULT 'user',
    attivo BOOLEAN DEFAULT TRUE,
    ultimo_accesso TIMESTAMP NULL,
    ip_ultimo_accesso VARCHAR(45) NULL
);

🏢 amministratori - Registry Amministratori

CREATE TABLE amministratori (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    codice_univoco VARCHAR(20) UNIQUE NOT NULL,
    user_id BIGINT UNSIGNED NULL,
    nome VARCHAR(100) NOT NULL,
    cognome VARCHAR(100) NOT NULL,
    denominazione_studio VARCHAR(255) NULL,
    codice_fiscale VARCHAR(20) UNIQUE NULL,
    partita_iva VARCHAR(20) NULL,
    indirizzo VARCHAR(255) NULL,
    cap VARCHAR(10) NULL,
    citta VARCHAR(100) NULL,
    provincia VARCHAR(5) NULL,
    telefono VARCHAR(20) NULL,
    email VARCHAR(255) NULL,
    pec VARCHAR(255) NULL,
    
    -- Campi tecnici multi-tenant
    database_attivo VARCHAR(100) NULL,          # netgescon_admin_[codice]
    cartella_base VARCHAR(255) NULL,            # path filesystem dedicato
    data_attivazione DATE NULL,
    data_scadenza DATE NULL,
    stato ENUM('attivo', 'sospeso', 'scaduto') DEFAULT 'attivo',
    
    -- Configurazione
    configurazione JSON NULL,                   # Settings amministratore
    limiti JSON NULL,                          # Limiti operativi (stabili max, etc)
    
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    deleted_at TIMESTAMP NULL,
    
    FOREIGN KEY (user_id) REFERENCES users(id),
    INDEX idx_codice (codice_univoco),
    INDEX idx_user (user_id),
    INDEX idx_stato (stato)
);

🏘️ stabili - Registry Stabili (riferimenti)

CREATE TABLE stabili (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    codice_stabile VARCHAR(8) UNIQUE NOT NULL,
    amministratore_id BIGINT UNSIGNED NOT NULL,
    denominazione VARCHAR(255) NOT NULL,
    indirizzo VARCHAR(255) NOT NULL,
    cap VARCHAR(10) NOT NULL,
    citta VARCHAR(60) NOT NULL,
    provincia VARCHAR(2) NOT NULL,
    
    -- Dati fiscali
    codice_fiscale VARCHAR(20) UNIQUE NULL,
    
    -- Campi tecnici multi-tenant
    database_dedicato VARCHAR(100) NULL,        # netgescon_stabile_[codice]
    cartella_dedicata VARCHAR(255) NULL,        # path filesystem stabile
    
    -- Configurazione base
    modalita_rateizzazione ENUM('mensile','bimestrale','trimestrale','quadrimestrale','semestrale','annuale') DEFAULT 'trimestrale',
    inizio_esercizio DATE NULL,
    fine_esercizio DATE NULL,
    
    -- Stato
    attivo BOOLEAN DEFAULT TRUE,
    stato VARCHAR(50) DEFAULT 'attivo',
    
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    deleted_at TIMESTAMP NULL,
    
    FOREIGN KEY (amministratore_id) REFERENCES amministratori(id),
    INDEX idx_codice (codice_stabile),
    INDEX idx_amministratore (amministratore_id),
    INDEX idx_stato (stato)
);

🔐 permissions - Permessi Sistema

CREATE TABLE permissions (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT UNSIGNED NOT NULL,
    amministratore_id BIGINT UNSIGNED NULL,
    stabile_id BIGINT UNSIGNED NULL,
    
    permesso ENUM('read', 'write', 'admin', 'super_admin') NOT NULL,
    risorsa VARCHAR(100) NOT NULL,              # 'amministratore', 'stabile', 'unita'
    
    attivo BOOLEAN DEFAULT TRUE,
    data_inizio DATE NULL,
    data_fine DATE NULL,
    
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (amministratore_id) REFERENCES amministratori(id),
    FOREIGN KEY (stabile_id) REFERENCES stabili(id),
    
    INDEX idx_user_risorsa (user_id, risorsa),
    INDEX idx_admin_user (amministratore_id, user_id)
);

🏢 DATABASE AMMINISTRATORE (netgescon_admin_[CODICE])

🎯 Scopo: Gestione amministratore e overview stabili

🏘️ stabili - Stabili Amministrati (dettaglio)

CREATE TABLE stabili (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    codice_stabile VARCHAR(20) NOT NULL,
    denominazione VARCHAR(255) NOT NULL,
    indirizzo VARCHAR(255) NOT NULL,
    cap VARCHAR(10) NOT NULL,
    citta VARCHAR(100) NOT NULL,
    provincia VARCHAR(5) NOT NULL,
    database_dedicato VARCHAR(100) NULL,
    
    -- Dati amministrativi dettagliati
    numero_unita INT DEFAULT 0,
    numero_proprietari INT DEFAULT 0,
    millesimi_totali DECIMAL(10,3) DEFAULT 1000.000,
    
    -- Economici
    fondo_riserva DECIMAL(12,2) DEFAULT 0.00,
    rata_standard DECIMAL(8,2) DEFAULT 0.00,
    
    -- Stato gestionale
    ultimo_bilancio DATE NULL,
    prossima_assemblea DATE NULL,
    stato_gestionale ENUM('attivo', 'inattivo', 'completato') DEFAULT 'attivo',
    
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    UNIQUE KEY stabili_codice_unique (codice_stabile)
);

🏢 fornitori_admin - Fornitori Studio

CREATE TABLE fornitori_admin (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    codice_fornitore VARCHAR(20) UNIQUE NOT NULL,
    ragione_sociale VARCHAR(255) NOT NULL,
    partita_iva VARCHAR(20) NULL,
    codice_fiscale VARCHAR(20) NULL,
    indirizzo VARCHAR(255) NULL,
    cap VARCHAR(10) NULL,
    citta VARCHAR(100) NULL,
    provincia VARCHAR(5) NULL,
    telefono VARCHAR(20) NULL,
    email VARCHAR(100) NULL,
    
    -- Specializzazione
    categoria VARCHAR(100) NULL,               # 'manutenzioni', 'pulizie', 'legale', etc
    servizi_offerti JSON NULL,
    
    note TEXT NULL,
    attivo BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL
);

📑 documenti_admin - Documenti Studio

CREATE TABLE documenti_admin (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    tipo_documento VARCHAR(50) NOT NULL,       # 'contratto', 'certificazione', 'comunicazione'
    numero_documento VARCHAR(50) NOT NULL,
    data_documento DATE NOT NULL,
    oggetto VARCHAR(255) NOT NULL,
    
    -- File
    file_path VARCHAR(500) NULL,               # path relativo in filesystem
    file_size BIGINT NULL,
    mime_type VARCHAR(100) NULL,
    
    -- Categorizzazione
    categoria VARCHAR(100) NULL,
    tags JSON NULL,
    
    -- Scadenze
    data_scadenza DATE NULL,
    giorni_preavviso INT DEFAULT 30,
    
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    INDEX idx_tipo (tipo_documento),
    INDEX idx_data (data_documento),
    INDEX idx_scadenza (data_scadenza)
);

📊 log_operazioni - Log Amministratore

CREATE TABLE log_operazioni (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT UNSIGNED NULL,
    operazione VARCHAR(100) NOT NULL,          # 'create', 'update', 'delete', 'view'
    tabella VARCHAR(100) NOT NULL,
    record_id BIGINT UNSIGNED NULL,
    
    -- Contesto
    stabile_codice VARCHAR(20) NULL,
    descrizione TEXT NULL,
    
    -- Dati operazione
    dati_prima JSON NULL,
    dati_dopo JSON NULL,
    
    -- Audit
    ip_address VARCHAR(45) NULL,
    user_agent TEXT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    INDEX idx_user (user_id),
    INDEX idx_data (created_at),
    INDEX idx_operazione (operazione),
    INDEX idx_stabile (stabile_codice)
);

🏘️ DATABASE STABILE (netgescon_stabile_[CODICE])

🎯 Scopo: Gestione completa singolo stabile

📋 stabili_ref - Riferimento Stabile

CREATE TABLE stabili_ref (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    codice_stabile VARCHAR(20) UNIQUE NOT NULL,
    denominazione VARCHAR(255) NOT NULL,
    amministratore_codice VARCHAR(20) NOT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL
);

🏢 condomini - Info Condominio

CREATE TABLE condomini (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    codice_condominio VARCHAR(20) UNIQUE NOT NULL,
    denominazione VARCHAR(255) NOT NULL,
    numero_unita INT DEFAULT 0,
    millesimi_totali DECIMAL(10,3) DEFAULT 1000.000,
    
    -- Struttura fisica
    numero_palazzine INT DEFAULT 1,
    numero_scale_per_palazzina INT DEFAULT 1,
    numero_piani INT DEFAULT 3,
    piano_seminterrato BOOLEAN DEFAULT FALSE,
    piano_sottotetto BOOLEAN DEFAULT FALSE,
    
    -- Servizi
    presenza_ascensore BOOLEAN DEFAULT FALSE,
    riscaldamento_centralizzato BOOLEAN DEFAULT FALSE,
    acqua_centralizzata BOOLEAN DEFAULT FALSE,
    servizio_portineria BOOLEAN DEFAULT FALSE,
    
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL
);

🏠 unita - Unità Immobiliari

CREATE TABLE unita (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    condominio_id BIGINT UNSIGNED NOT NULL,
    numero_unita VARCHAR(10) NOT NULL,
    piano VARCHAR(10) NULL,
    scala VARCHAR(10) NULL,
    interno VARCHAR(10) NULL,
    
    -- Metrature
    superficie DECIMAL(8,2) NULL,
    vani DECIMAL(4,1) NULL,
    
    -- Millesimi
    millesimi_proprieta DECIMAL(8,3) NULL,
    millesimi_riscaldamento DECIMAL(8,3) NULL,
    millesimi_ascensore DECIMAL(8,3) NULL,
    millesimi_scala DECIMAL(8,3) NULL,
    
    -- Destinazione
    destinazione_uso ENUM('abitazione', 'ufficio', 'negozio', 'magazzino', 'garage', 'cantina') DEFAULT 'abitazione',
    
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (condominio_id) REFERENCES condomini(id),
    INDEX idx_condominio (condominio_id),
    INDEX idx_numero (numero_unita)
);

👥 proprietari - Proprietari

CREATE TABLE proprietari (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    codice_proprietario VARCHAR(20) UNIQUE NOT NULL,
    tipo_proprietario ENUM('persona_fisica', 'persona_giuridica') NOT NULL,
    
    -- Dati persona fisica
    nome VARCHAR(100) NULL,
    cognome VARCHAR(100) NULL,
    codice_fiscale VARCHAR(20) UNIQUE NULL,
    data_nascita DATE NULL,
    luogo_nascita VARCHAR(100) NULL,
    
    -- Dati persona giuridica  
    ragione_sociale VARCHAR(255) NULL,
    partita_iva VARCHAR(20) NULL,
    
    -- Dati comuni
    indirizzo_residenza VARCHAR(255) NULL,
    cap_residenza VARCHAR(10) NULL,
    citta_residenza VARCHAR(100) NULL,
    provincia_residenza VARCHAR(5) NULL,
    telefono VARCHAR(20) NULL,
    cellulare VARCHAR(20) NULL,
    email VARCHAR(255) NULL,
    pec VARCHAR(255) NULL,
    
    -- Stato
    attivo BOOLEAN DEFAULT TRUE,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    INDEX idx_codice_fiscale (codice_fiscale),
    INDEX idx_nome_cognome (nome, cognome),
    INDEX idx_ragione_sociale (ragione_sociale)
);

🔗 proprieta - Relazioni Proprietà

CREATE TABLE proprieta (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    unita_id BIGINT UNSIGNED NOT NULL,
    proprietario_id BIGINT UNSIGNED NOT NULL,
    percentuale_proprieta DECIMAL(5,2) DEFAULT 100.00,
    data_inizio DATE NOT NULL,
    data_fine DATE NULL,
    tipo_diritto ENUM('proprietà','usufrutto','uso','abitazione','nuda_proprietà') DEFAULT 'proprietà',
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (unita_id) REFERENCES unita(id),
    FOREIGN KEY (proprietario_id) REFERENCES proprietari(id),
    INDEX idx_unita (unita_id),
    INDEX idx_proprietario (proprietario_id),
    INDEX idx_data (data_inizio, data_fine)
);

💰 movimenti - Contabilità Stabile

CREATE TABLE movimenti (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    numero_movimento VARCHAR(20) UNIQUE NOT NULL,
    data_movimento DATE NOT NULL,
    tipo_movimento ENUM('entrata','uscita') NOT NULL,
    fornitore_id BIGINT UNSIGNED NULL,
    causale VARCHAR(255) NOT NULL,
    
    -- Importi
    importo DECIMAL(12,2) NOT NULL,
    iva DECIMAL(12,2) DEFAULT 0.00,
    ritenuta DECIMAL(12,2) DEFAULT 0.00,
    totale DECIMAL(12,2) NOT NULL,
    
    -- Classificazione
    categoria VARCHAR(100) NULL,               # 'ordinaria', 'straordinaria', 'riserva'
    sottocategoria VARCHAR(100) NULL,
    conto VARCHAR(50) NULL,
    
    -- Ripartizione
    ripartizione_tipo ENUM('millesimi','importo_fisso','personalizzata') DEFAULT 'millesimi',
    ripartizione_data JSON NULL,
    
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    INDEX idx_data (data_movimento),
    INDEX idx_tipo (tipo_movimento),
    INDEX idx_categoria (categoria),
    INDEX idx_fornitore (fornitore_id)
);

📅 rate - Rate Condominiali

CREATE TABLE rate (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    unita_id BIGINT UNSIGNED NOT NULL,
    numero_rata VARCHAR(20) NOT NULL,
    anno INT NOT NULL,
    trimestre INT NULL,
    data_scadenza DATE NOT NULL,
    
    -- Importi
    ordinaria DECIMAL(8,2) DEFAULT 0.00,
    straordinaria DECIMAL(8,2) DEFAULT 0.00,
    riscaldamento DECIMAL(8,2) DEFAULT 0.00,
    totale DECIMAL(8,2) NOT NULL,
    
    -- Stato pagamento
    stato ENUM('non_pagata','pagata','parziale','scaduta') DEFAULT 'non_pagata',
    data_pagamento DATE NULL,
    importo_pagato DECIMAL(8,2) DEFAULT 0.00,
    
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (unita_id) REFERENCES unita(id),
    INDEX idx_unita (unita_id),
    INDEX idx_scadenza (data_scadenza),
    INDEX idx_anno_trimestre (anno, trimestre),
    INDEX idx_stato (stato)
);

🔗 RELAZIONI TRA DATABASE

🌐 Cross-Database References

// Nel modello Laravel
class Amministratore extends Model {
    public function getDatabaseName(): string {
        return "netgescon_admin_{$this->codice_univoco}";
    }
    
    public function getStabiliConnection() {
        return DB::connection('mysql')->statement("USE {$this->getDatabaseName()}");
    }
}

class Stabile extends Model {
    public function getDatabaseName(): string {
        return "netgescon_stabile_{$this->codice_stabile}";
    }
    
    public function getConnection() {
        config(["database.connections.stabile_{$this->codice_stabile}" => [
            'driver' => 'mysql',
            'database' => $this->getDatabaseName(),
            // ... other config
        ]]);
        
        return DB::connection("stabile_{$this->codice_stabile}");
    }
}

📊 Queries Cross-Database

-- Statistiche amministratore (dal DB principale)
SELECT 
    a.codice_univoco,
    a.nome_completo,
    COUNT(s.id) as stabili_count,
    SUM(s.numero_unita) as unita_totali
FROM amministratori a
LEFT JOIN stabili s ON a.id = s.amministratore_id
WHERE a.attivo = 1
GROUP BY a.id;

-- Accesso diretto a DB amministratore
USE netgescon_admin_00000000;
SELECT COUNT(*) as stabili_amministrati FROM stabili WHERE stato = 'attivo';

-- Accesso diretto a DB stabile
USE netgescon_stabile_ROM00123;
SELECT COUNT(*) as unita_totali FROM unita;
SELECT SUM(totale) as entrate_anno FROM movimenti 
WHERE tipo_movimento = 'entrata' AND YEAR(data_movimento) = 2025;

💾 STRUTTURA DATABASE COMPLETA E SCALABILE
🔗 Relazioni ottimizzate per performance
🛡️ Isolamento garantito tra tenant