16 KiB
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