netgescon-day0/docs/07-DATABASE-NETGESCON.md

38 KiB
Executable File
Raw Permalink Blame History

📊 MANUALE 07 - DATABASE NETGESCON

Versione: 1.0 - Data: 03 Agosto 2025 Database di Riferimento: netgescon con credenziali unificate


🎯 INTRODUZIONE

Questo manuale fornisce la documentazione completa della struttura database NetGescon, compresi schemi, tabelle, relazioni e best practices per lo sviluppo di moduli.

🔑 CREDENZIALI UNIFICATE

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=netgescon
DB_USERNAME=netgescon_user
DB_PASSWORD=NetGescon2024!

⚠️ IMPORTANTE: Utilizzare sempre queste credenziali per tutti i moduli e connessioni database.


<EFBFBD> ARCHIVI LEGACY GESCON (SOLO LETTURA)

Per tutte le attività di import legacy utilizziamo direttamente gli archivi storici residenti sul NAS Windows montato in /mnt/gescon-archives/gescon. L'accesso deve rimanere in sola lettura: eventuali correzioni o riconciliazioni vanno gestite copiando i dataset in uno staging MySQL (gescon_import schema) dove possiamo applicare patch e controlli senza contaminare l'originale.

🔐 Policy di accesso

  • Percorso principale: /mnt/gescon-archives/gescon/<id_stabile>/<cartella_gestione>/.
  • Il montaggio è permanente sul server Linux; non serve rsyncare nella repo.
  • Quando servono snapshot per test locali si possono esportare le tabelle direttamente in MySQL o CSV, ma mai scrivere sui file Access originali.

🗂️ Struttura cartelle per stabile/gestione

  1. Ogni stabile è identificato da una cartella numerica a quattro cifre (es. 0021 corrisponde a Viale delle Milizie 3).
  2. All'interno troviamo:
    • Sottocartelle numeriche (0001, 0003, …) che corrispondono ai singoli anni di gestione; ciascuna contiene singolo_anno.mdb.
    • File trasversali come generale_stabile.mdb, generale_stabile_sf.mdb, allegati, documenti, ecc.
  3. Il file generale_stabile.mdb → tabella anni fornisce il mapping fra gestione e cartella:
    • nome_dir: contiene il codice cartella (0001, 0003, …).
    • anno_o / anno_r: indicano periodo di ordinaria e riscaldamento.
    • Campi ordinarie_dal, ordinarie_al, riscald_dal, riscald_al definiscono l'intervallo temporale da salvare dentro le nostre tabelle gestioni.

📑 Tabelle principali da importare (singolo_anno.mdb)

Tabella legacy Contenuto Uso nel nuovo schema
condomine / condomini_totali Anagrafiche complete delle unità con scala, interno, soggetto, riferimenti catastali, flag di attivazione e preferenze di invio Popola unita_immobiliari, soggetti e la pivot proprieta / diritti_reali. Campi chiave: id_cond (ID unità), cod_cond (codice interno), scala, int, nom_cond, subentrato_dal, attivo_fino_al, Internet_cod/pw (eventuali accessi), E_lostesso_di (link pertinenze).
tabelle Definizione delle tabelle millesimali: cod_tab, descr, calcolo, tipo (O=Ordinaria, R=Riscaldamento, S=Straordinaria), Tot_mm, inte_col (colonna stampata), un_mis, nord (posizionamento su prospetto), Num_decimali, Is_Detr Mappa su tabelle_millesimali del dominio NetGescon. Conserviamo cod_tab come codice_tabella, descr come denominazione, tipogestione (O/R/S) e nord/nord2 per la futura generazione di prospetti.
dett_tab Dettaglio millesimi per singola unità (cod_tab + id_cond). Campi mm, prev, cons, cond_inquil (C condomini / I inquilini), n_stra, Proviene_* Alimenta dettaglio_millesimi collegando cod_tab (tabella) e id_cond (unità). Il flag cond_inquil serve per distinguere quote condominiali vs. inquilini durante il riparto.
condomin, cond_detr, rendite_condominiali Informazioni aggiuntive su soggetti e catasto (rendite, diritti reali, detrazioni fiscali) Servono alle prossime iterazioni del modulo gescon-import per completare Rubrica Unica e i collegamenti con tabelle fiscali.

🧩 Processo di import (modulo gescon-import)

  1. Identificazione gestione: leggere generale_stabile.mdbanni per sapere quale cartella (nome_dir) usare per ordinaria/riscaldamento/straz.
  2. Estrazione Access ➜ staging: esportare da singolo_anno.mdb le tabelle condomini_totali, tabelle, dett_tab (tramite mdb-export, mdb-sql o ODBC) e caricarle in tabelle temporanee MySQL (gescon_import.<nome_tabella>).
  3. Normalizzazione unità: trasformare i record di condomini_totali nei nostri modelli stabili, unita_immobiliari, soggetti rispettando mapping scala/piano/interno e mantenendo ID legacy (id_cond) per i join successivi.
  4. Creazione tabelle millesimali: per ogni record di tabelle creare/aggiornare tabelle_millesimali con:
    • codice_tabella = cod_tab
    • denominazione = descr
    • tipo_tabella derivato da tipo (Oordinaria, Rriscaldamento, Sstraordinaria)
    • nord/nord2 conservati per mantenere l'ordinamento nei prospetti.
  5. Assegnazione millesimi: usare dett_tab per compilare dettaglio_millesimi, facendo il join su id_cond → nuova unita_immobiliare.id. Il campo mm va salvato come valore principale; prev/cons possono andare in colonne di audit o JSON per mantenere gli storici.
  6. Gestione read-only continuity: dopo l'import, aggiornamenti e controlli avvengono nella copia MySQL; per riallineare con il legacy si riesegue l'estrazione mantenendo il mapping su id_cond/cod_tab.

Nota operativa: le informazioni appena censite (per esempio lo stabile 0021 di Viale delle Milizie 3) vanno documentate anche dentro il modulo gescon-import così da riusare lo stesso flusso sulle prossime installazioni senza dover esplorare manualmente i file Access.


<EFBFBD>🗄️ SCHEMA PRINCIPALE DATABASE

Tabelle Core Sistema

1. Utenti e Autenticazione

-- Tabella utenti principale
CREATE TABLE users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    email_verified_at TIMESTAMP NULL,
    password VARCHAR(255) NOT NULL,
    is_active BOOLEAN DEFAULT TRUE,
    last_login_at TIMESTAMP NULL,
    profile_photo_path VARCHAR(2048) NULL,
    phone VARCHAR(20) NULL,
    address TEXT NULL,
    remember_token VARCHAR(100) NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    INDEX idx_email (email),
    INDEX idx_active (is_active),
    INDEX idx_last_login (last_login_at)
);

-- Sistema permessi Spatie
CREATE TABLE roles (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    guard_name VARCHAR(255) NOT NULL DEFAULT 'web',
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    UNIQUE KEY unique_role_guard (name, guard_name)
);

CREATE TABLE permissions (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    guard_name VARCHAR(255) NOT NULL DEFAULT 'web',
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    UNIQUE KEY unique_permission_guard (name, guard_name)
);

CREATE TABLE model_has_roles (
    role_id BIGINT UNSIGNED NOT NULL,
    model_type VARCHAR(255) NOT NULL,
    model_id BIGINT UNSIGNED NOT NULL,
    
    PRIMARY KEY (role_id, model_id, model_type),
    FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
    INDEX idx_model_type (model_type),
    INDEX idx_model_id (model_id)
);

CREATE TABLE model_has_permissions (
    permission_id BIGINT UNSIGNED NOT NULL,
    model_type VARCHAR(255) NOT NULL,
    model_id BIGINT UNSIGNED NOT NULL,
    
    PRIMARY KEY (permission_id, model_id, model_type),
    FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE,
    INDEX idx_model_type (model_type),
    INDEX idx_model_id (model_id)
);

CREATE TABLE role_has_permissions (
    permission_id BIGINT UNSIGNED NOT NULL,
    role_id BIGINT UNSIGNED NOT NULL,
    
    PRIMARY KEY (permission_id, role_id),
    FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE,
    FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);

2. Anagrafica Territoriale

-- Comuni italiani (database completo)
CREATE TABLE comuni_italiani (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    codice_catastale VARCHAR(4) NOT NULL UNIQUE,
    denominazione VARCHAR(255) NOT NULL,
    denominazione_tedesca VARCHAR(255) NULL,
    denominazione_altra VARCHAR(255) NULL,
    codice_provincia VARCHAR(2) NOT NULL,
    provincia VARCHAR(255) NOT NULL,
    regione VARCHAR(255) NOT NULL,
    cap VARCHAR(5) NULL,
    prefisso VARCHAR(10) NULL,
    email_pec VARCHAR(255) NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    INDEX idx_codice_catastale (codice_catastale),
    INDEX idx_provincia (codice_provincia),
    INDEX idx_denominazione (denominazione),
    INDEX idx_cap (cap)
);

3. Strutture Immobiliari

-- Stabili/Condomini
CREATE TABLE stabili (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    denominazione VARCHAR(255) NOT NULL,
    indirizzo VARCHAR(255) NOT NULL,
    comune_id BIGINT UNSIGNED NULL,
    cap VARCHAR(10) NULL,
    codice_fiscale VARCHAR(16) NULL,
    partita_iva VARCHAR(11) NULL,
    amministratore_id BIGINT UNSIGNED NULL,
    is_active BOOLEAN DEFAULT TRUE,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (comune_id) REFERENCES comuni_italiani(id) ON DELETE SET NULL,
    FOREIGN KEY (amministratore_id) REFERENCES users(id) ON DELETE SET NULL,
    
    INDEX idx_denominazione (denominazione),
    INDEX idx_amministratore (amministratore_id),
    INDEX idx_comune (comune_id),
    INDEX idx_active (is_active),
    INDEX idx_codice_fiscale (codice_fiscale)
);

-- Unità immobiliari
CREATE TABLE unita_immobiliari (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    stabile_id BIGINT UNSIGNED NOT NULL,
    numero VARCHAR(50) NOT NULL,
    piano VARCHAR(20) NULL,
    scala VARCHAR(20) NULL,
    interno VARCHAR(20) NULL,
    tipo ENUM('appartamento', 'negozio', 'garage', 'cantina', 'altro') NOT NULL DEFAULT 'appartamento',
    categoria_catastale VARCHAR(10) NULL,
    classe_catastale VARCHAR(10) NULL,
    consistenza VARCHAR(20) NULL,
    superficie_catastale DECIMAL(8,2) NULL,
    superficie_commerciale DECIMAL(8,2) NULL,
    rendita_catastale DECIMAL(10,2) NULL,
    millesimi_proprieta DECIMAL(8,4) NULL,
    millesimi_riscaldamento DECIMAL(8,4) NULL,
    millesimi_acqua DECIMAL(8,4) NULL,
    millesimi_ascensore DECIMAL(8,4) NULL,
    is_active BOOLEAN DEFAULT TRUE,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE CASCADE,
    
    INDEX idx_stabile (stabile_id),
    INDEX idx_numero (numero),
    INDEX idx_tipo (tipo),
    INDEX idx_active (is_active),
    UNIQUE KEY unique_stabile_numero (stabile_id, numero)
);

4. Anagrafica Soggetti

-- Soggetti (persone fisiche e giuridiche)
CREATE TABLE soggetti (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tipo_soggetto ENUM('persona_fisica', 'persona_giuridica') NOT NULL,
    nome VARCHAR(255) NULL,
    cognome VARCHAR(255) NULL,
    ragione_sociale VARCHAR(255) NULL,
    codice_fiscale VARCHAR(16) NULL,
    partita_iva VARCHAR(11) NULL,
    data_nascita DATE NULL,
    luogo_nascita VARCHAR(255) NULL,
    indirizzo VARCHAR(255) NULL,
    comune_id BIGINT UNSIGNED NULL,
    cap VARCHAR(10) NULL,
    telefono VARCHAR(20) NULL,
    email VARCHAR(255) NULL,
    is_active BOOLEAN DEFAULT TRUE,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (comune_id) REFERENCES comuni_italiani(id) ON DELETE SET NULL,
    
    INDEX idx_codice_fiscale (codice_fiscale),
    INDEX idx_partita_iva (partita_iva),
    INDEX idx_tipo_soggetto (tipo_soggetto),
    INDEX idx_cognome_nome (cognome, nome),
    INDEX idx_ragione_sociale (ragione_sociale),
    INDEX idx_active (is_active)
);

-- Relazioni soggetti-unità immobiliari
CREATE TABLE diritti_reali (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    soggetto_id BIGINT UNSIGNED NOT NULL,
    unita_immobiliare_id BIGINT UNSIGNED NOT NULL,
    tipo_diritto ENUM('proprietario', 'nudo_proprietario', 'usufruttuario', 'inquilino', 'comodatario') NOT NULL,
    quota_proprieta DECIMAL(8,4) NULL,
    data_inizio DATE NULL,
    data_fine DATE NULL,
    is_active BOOLEAN DEFAULT TRUE,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (soggetto_id) REFERENCES soggetti(id) ON DELETE CASCADE,
    FOREIGN KEY (unita_immobiliare_id) REFERENCES unita_immobiliari(id) ON DELETE CASCADE,
    
    INDEX idx_soggetto (soggetto_id),
    INDEX idx_unita (unita_immobiliare_id),
    INDEX idx_tipo_diritto (tipo_diritto),
    INDEX idx_active (is_active),
    INDEX idx_data_inizio (data_inizio),
    INDEX idx_data_fine (data_fine)
);

💰 MODULO CONTABILITÀ - SCHEMA IMPLEMENTATO

Tabelle Contabili

-- Piano dei conti
CREATE TABLE piano_conti (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    mastro VARCHAR(10) NOT NULL,
    conto VARCHAR(10) NOT NULL,
    sottoconto VARCHAR(10) NOT NULL,
    descrizione VARCHAR(255) NOT NULL,
    tipo ENUM('attivo', 'passivo', 'costo', 'ricavo') NOT NULL,
    attivo BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    INDEX idx_mastro_conto (mastro, conto, sottoconto),
    INDEX idx_tipo (tipo),
    INDEX idx_attivo (attivo),
    INDEX idx_descrizione (descrizione)
);

-- Gestioni contabili
CREATE TABLE gestioni (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    denominazione VARCHAR(255) NOT NULL,
    anno INT NOT NULL,
    data_inizio DATE NOT NULL,
    data_fine DATE NOT NULL,
    attivo BOOLEAN DEFAULT TRUE,
    stabile_id BIGINT UNSIGNED NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE SET NULL,
    
    INDEX idx_anno (anno),
    INDEX idx_attivo (attivo),
    INDEX idx_stabile (stabile_id),
    UNIQUE KEY unique_stabile_anno (stabile_id, anno)
);

-- Registrazioni contabili
CREATE TABLE registrazioni_contabili (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    data_registrazione DATE NOT NULL,
    numero_registrazione VARCHAR(20) NULL,
    descrizione TEXT NOT NULL,
    importo_dare DECIMAL(12,2) DEFAULT 0.00,
    importo_avere DECIMAL(12,2) DEFAULT 0.00,
    piano_conti_id BIGINT UNSIGNED NOT NULL,
    gestione_id BIGINT UNSIGNED NOT NULL,
    user_id BIGINT UNSIGNED NOT NULL,
    documento_riferimento VARCHAR(255) NULL,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (piano_conti_id) REFERENCES piano_conti(id) ON DELETE RESTRICT,
    FOREIGN KEY (gestione_id) REFERENCES gestioni(id) ON DELETE RESTRICT,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT,
    
    INDEX idx_data_registrazione (data_registrazione),
    INDEX idx_piano_conti (piano_conti_id),
    INDEX idx_gestione (gestione_id),
    INDEX idx_user (user_id),
    INDEX idx_numero (numero_registrazione)
);

Dati Base Piano dei Conti

-- Piano dei conti standard per condomini
INSERT INTO piano_conti (mastro, conto, sottoconto, descrizione, tipo, attivo) VALUES
-- CLASSE 1 - CONTI FINANZIARI
('1', '01', '01', 'Cassa contanti', 'attivo', TRUE),
('1', '01', '02', 'Banca c/c ordinario', 'attivo', TRUE),
('1', '01', '03', 'Banca c/c vincolato', 'attivo', TRUE),
('1', '01', '04', 'Poste c/c', 'attivo', TRUE),

-- CLASSE 2 - CREDITI E DEBITI
('2', '01', '01', 'Crediti vs condomini', 'attivo', TRUE),
('2', '01', '02', 'Crediti vs inquilini', 'attivo', TRUE),
('2', '02', '01', 'Debiti vs fornitori', 'passivo', TRUE),
('2', '02', '02', 'Debiti tributari', 'passivo', TRUE),
('2', '02', '03', 'Debiti previdenziali', 'passivo', TRUE),

-- CLASSE 5 - COSTI
('5', '01', '01', 'Spese per energia elettrica', 'costo', TRUE),
('5', '01', '02', 'Spese per riscaldamento', 'costo', TRUE),
('5', '01', '03', 'Spese per acqua', 'costo', TRUE),
('5', '02', '01', 'Spese pulizie', 'costo', TRUE),
('5', '02', '02', 'Spese manutenzione ordinaria', 'costo', TRUE),
('5', '02', '03', 'Spese manutenzione straordinaria', 'costo', TRUE),
('5', '03', '01', 'Compensi amministratore', 'costo', TRUE),
('5', '03', '02', 'Spese legali', 'costo', TRUE),

-- CLASSE 7 - RICAVI
('7', '01', '01', 'Quote condominiali ordinarie', 'ricavo', TRUE),
('7', '01', '02', 'Quote condominiali straordinarie', 'ricavo', TRUE),
('7', '02', '01', 'Interessi attivi bancari', 'ricavo', TRUE),
('7', '02', '02', 'Altri ricavi', 'ricavo', TRUE);

📋 MODULI AGGIUNTIVI - STRUTTURE PREVISTE

Modulo Documenti

-- Gestione documenti
CREATE TABLE documenti (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    stabile_id BIGINT UNSIGNED NOT NULL,
    unita_immobiliare_id BIGINT UNSIGNED NULL,
    soggetto_id BIGINT UNSIGNED NULL,
    user_id BIGINT UNSIGNED NOT NULL,
    titolo VARCHAR(255) NOT NULL,
    descrizione TEXT NULL,
    tipo_documento VARCHAR(100) NULL,
    categoria ENUM('generale', 'amministrativo', 'contabile', 'tecnico', 'legale') NOT NULL DEFAULT 'generale',
    nome_file VARCHAR(255) NOT NULL,
    path_file VARCHAR(500) NOT NULL,
    dimensione_file BIGINT UNSIGNED NULL,
    mime_type VARCHAR(100) NULL,
    is_public BOOLEAN DEFAULT FALSE,
    data_documento DATE NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE CASCADE,
    FOREIGN KEY (unita_immobiliare_id) REFERENCES unita_immobiliari(id) ON DELETE CASCADE,
    FOREIGN KEY (soggetto_id) REFERENCES soggetti(id) ON DELETE CASCADE,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    
    INDEX idx_stabile (stabile_id),
    INDEX idx_unita (unita_immobiliare_id),
    INDEX idx_soggetto (soggetto_id),
    INDEX idx_categoria (categoria),
    INDEX idx_public (is_public),
    INDEX idx_data_documento (data_documento),
    INDEX idx_created_at (created_at),
    
    FULLTEXT idx_titolo_descrizione (titolo, descrizione)
);

Modulo Assemblee

-- Assemblee condominiali
CREATE TABLE assemblee (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    stabile_id BIGINT UNSIGNED NOT NULL,
    titolo VARCHAR(255) NOT NULL,
    data_assemblea DATETIME NOT NULL,
    luogo VARCHAR(255) NULL,
    tipo ENUM('ordinaria', 'straordinaria', 'urgente') NOT NULL DEFAULT 'ordinaria',
    stato ENUM('programmata', 'convocata', 'svolta', 'annullata') NOT NULL DEFAULT 'programmata',
    data_convocazione DATE NULL,
    data_seconda_convocazione DATETIME NULL,
    presidente_assemblea VARCHAR(255) NULL,
    segretario_assemblea VARCHAR(255) NULL,
    note TEXT NULL,
    verbale TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE CASCADE,
    
    INDEX idx_stabile (stabile_id),
    INDEX idx_data_assemblea (data_assemblea),
    INDEX idx_stato (stato),
    INDEX idx_tipo (tipo)
);

-- Ordine del giorno
CREATE TABLE ordine_giorno (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    assemblea_id BIGINT UNSIGNED NOT NULL,
    numero_punto INT NOT NULL,
    argomento TEXT NOT NULL,
    relatore VARCHAR(255) NULL,
    proposta TEXT NULL,
    esito ENUM('approvato', 'respinto', 'rinviato', 'non_discusso') NULL,
    note_discussione TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (assemblea_id) REFERENCES assemblee(id) ON DELETE CASCADE,
    
    INDEX idx_assemblea (assemblea_id),
    INDEX idx_numero_punto (numero_punto),
    UNIQUE KEY unique_assemblea_punto (assemblea_id, numero_punto)
);

-- Partecipazioni assemblee
CREATE TABLE partecipazioni_assemblea (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    assemblea_id BIGINT UNSIGNED NOT NULL,
    soggetto_id BIGINT UNSIGNED NOT NULL,
    unita_immobiliare_id BIGINT UNSIGNED NOT NULL,
    presente BOOLEAN DEFAULT FALSE,
    delegato_a BIGINT UNSIGNED NULL,
    millesimi_rappresentati DECIMAL(8,4) NOT NULL,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (assemblea_id) REFERENCES assemblee(id) ON DELETE CASCADE,
    FOREIGN KEY (soggetto_id) REFERENCES soggetti(id) ON DELETE CASCADE,
    FOREIGN KEY (unita_immobiliare_id) REFERENCES unita_immobiliari(id) ON DELETE CASCADE,
    FOREIGN KEY (delegato_a) REFERENCES soggetti(id) ON DELETE SET NULL,
    
    INDEX idx_assemblea (assemblea_id),
    INDEX idx_soggetto (soggetto_id),
    INDEX idx_unita (unita_immobiliare_id),
    UNIQUE KEY unique_assemblea_unita (assemblea_id, unita_immobiliare_id)
);

-- Votazioni
CREATE TABLE votazioni (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    ordine_giorno_id BIGINT UNSIGNED NOT NULL,
    soggetto_id BIGINT UNSIGNED NOT NULL,
    voto ENUM('favorevole', 'contrario', 'astenuto', 'non_partecipa') NOT NULL,
    millesimi_voto DECIMAL(8,4) NOT NULL,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (ordine_giorno_id) REFERENCES ordine_giorno(id) ON DELETE CASCADE,
    FOREIGN KEY (soggetto_id) REFERENCES soggetti(id) ON DELETE CASCADE,
    
    INDEX idx_ordine_giorno (ordine_giorno_id),
    INDEX idx_soggetto (soggetto_id),
    INDEX idx_voto (voto),
    UNIQUE KEY unique_voto_soggetto (ordine_giorno_id, soggetto_id)
);

Modulo Manutenzioni

-- Fornitori
CREATE TABLE fornitori (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    ragione_sociale VARCHAR(255) NOT NULL,
    codice_fiscale VARCHAR(16) NULL,
    partita_iva VARCHAR(11) NULL,
    indirizzo VARCHAR(255) NULL,
    comune_id BIGINT UNSIGNED NULL,
    cap VARCHAR(10) NULL,
    telefono VARCHAR(20) NULL,
    email VARCHAR(255) NULL,
    email_pec VARCHAR(255) NULL,
    settore VARCHAR(100) NULL,
    specializzazioni TEXT NULL,
    is_active BOOLEAN DEFAULT TRUE,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (comune_id) REFERENCES comuni_italiani(id) ON DELETE SET NULL,
    
    INDEX idx_ragione_sociale (ragione_sociale),
    INDEX idx_partita_iva (partita_iva),
    INDEX idx_settore (settore),
    INDEX idx_active (is_active)
);

-- Manutenzioni programmate
CREATE TABLE manutenzioni (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    stabile_id BIGINT UNSIGNED NOT NULL,
    unita_immobiliare_id BIGINT UNSIGNED NULL,
    fornitore_id BIGINT UNSIGNED NULL,
    titolo VARCHAR(255) NOT NULL,
    descrizione TEXT NOT NULL,
    tipo ENUM('ordinaria', 'straordinaria', 'urgente', 'preventiva') NOT NULL DEFAULT 'ordinaria',
    stato ENUM('programmata', 'in_corso', 'completata', 'annullata', 'sospesa') NOT NULL DEFAULT 'programmata',
    priorita ENUM('bassa', 'media', 'alta', 'urgente') NOT NULL DEFAULT 'media',
    data_programmata DATE NOT NULL,
    data_inizio DATE NULL,
    data_completamento DATE NULL,
    costo_preventivato DECIMAL(10,2) NULL,
    costo_effettivo DECIMAL(10,2) NULL,
    responsabile_id BIGINT UNSIGNED NULL,
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE CASCADE,
    FOREIGN KEY (unita_immobiliare_id) REFERENCES unita_immobiliari(id) ON DELETE CASCADE,
    FOREIGN KEY (fornitore_id) REFERENCES fornitori(id) ON DELETE SET NULL,
    FOREIGN KEY (responsabile_id) REFERENCES users(id) ON DELETE SET NULL,
    
    INDEX idx_stabile (stabile_id),
    INDEX idx_unita (unita_immobiliare_id),
    INDEX idx_fornitore (fornitore_id),
    INDEX idx_stato (stato),
    INDEX idx_tipo (tipo),
    INDEX idx_priorita (priorita),
    INDEX idx_data_programmata (data_programmata),
    INDEX idx_responsabile (responsabile_id)
);

-- Interventi su manutenzioni
CREATE TABLE interventi_manutenzione (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    manutenzione_id BIGINT UNSIGNED NOT NULL,
    data_intervento DATE NOT NULL,
    ora_inizio TIME NULL,
    ora_fine TIME NULL,
    tecnico_nome VARCHAR(255) NULL,
    tecnico_telefono VARCHAR(20) NULL,
    descrizione_intervento TEXT NOT NULL,
    materiali_utilizzati TEXT NULL,
    costo_intervento DECIMAL(10,2) NULL,
    stato ENUM('programmato', 'in_corso', 'completato', 'sospeso') NOT NULL DEFAULT 'programmato',
    note TEXT NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    FOREIGN KEY (manutenzione_id) REFERENCES manutenzioni(id) ON DELETE CASCADE,
    
    INDEX idx_manutenzione (manutenzione_id),
    INDEX idx_data_intervento (data_intervento),
    INDEX idx_stato (stato)
);

🔧 BEST PRACTICES DATABASE

1. Naming Convention

-- ✅ CORRETTO: Nomi italiani senza accenti
CREATE TABLE registrazioni_contabili (...);
CREATE TABLE piano_conti (...);
CREATE TABLE unita_immobiliari (...);

-- ❌ EVITARE: Nomi inglesi o con accenti
CREATE TABLE accounting_records (...);
CREATE TABLE unità_immobiliari (...);

2. Indici per Performance

-- Indici su foreign keys
ALTER TABLE registrazioni_contabili 
ADD INDEX idx_piano_conti (piano_conti_id);

-- Indici su campi di ricerca
ALTER TABLE soggetti 
ADD INDEX idx_codice_fiscale (codice_fiscale);

-- Indici compositi per query frequenti
ALTER TABLE piano_conti 
ADD INDEX idx_mastro_conto (mastro, conto, sottoconto);

-- Fulltext per ricerche testuali
ALTER TABLE documenti 
ADD FULLTEXT idx_titolo_descrizione (titolo, descrizione);

3. Constraint e Validazione

-- Foreign keys con azioni appropriate
FOREIGN KEY (stabile_id) REFERENCES stabili(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT,
FOREIGN KEY (comune_id) REFERENCES comuni_italiani(id) ON DELETE SET NULL,

-- Check constraints per validazione
ALTER TABLE registrazioni_contabili 
ADD CONSTRAINT chk_importi 
CHECK (importo_dare >= 0 AND importo_avere >= 0);

-- Unique constraints per integrità
UNIQUE KEY unique_stabile_numero (stabile_id, numero)

4. Tipi di Dati Corretti

-- Importi: DECIMAL per precisione
importo_dare DECIMAL(12,2) DEFAULT 0.00,

-- Date: DATE per solo data, DATETIME per data+ora
data_registrazione DATE NOT NULL,
created_at TIMESTAMP NULL,

-- Testi: VARCHAR per lunghezza fissa, TEXT per variabile
codice_fiscale VARCHAR(16) NULL,
descrizione TEXT NOT NULL,

-- Boolean: BOOLEAN o TINYINT(1)
is_active BOOLEAN DEFAULT TRUE,

📊 QUERY OTTIMIZZATE COMUNI

1. Contabilità - Bilancio

-- Calcolo totali DARE/AVERE per gestione
SELECT 
    g.denominazione,
    g.anno,
    SUM(rc.importo_dare) as totale_dare,
    SUM(rc.importo_avere) as totale_avere,
    (SUM(rc.importo_dare) - SUM(rc.importo_avere)) as saldo
FROM gestioni g
LEFT JOIN registrazioni_contabili rc ON g.id = rc.gestione_id
WHERE g.attivo = TRUE
GROUP BY g.id, g.denominazione, g.anno
ORDER BY g.anno DESC;

2. Stabili - Statistiche Unità

-- Statistiche unità per stabile
SELECT 
    s.denominazione,
    COUNT(ui.id) as totale_unita,
    SUM(ui.millesimi_proprieta) as totale_millesimi,
    AVG(ui.superficie_catastale) as superficie_media
FROM stabili s
LEFT JOIN unita_immobiliari ui ON s.id = ui.stabile_id
WHERE s.is_active = TRUE
GROUP BY s.id, s.denominazione
ORDER BY s.denominazione;

3. Soggetti - Proprietari per Stabile

-- Lista proprietari attivi per stabile
SELECT 
    s.denominazione as stabile,
    ui.numero as unita,
    COALESCE(
        CONCAT(so.cognome, ' ', so.nome),
        so.ragione_sociale
    ) as proprietario,
    dr.quota_proprieta,
    ui.millesimi_proprieta
FROM stabili s
JOIN unita_immobiliari ui ON s.id = ui.stabile_id
JOIN diritti_reali dr ON ui.id = dr.unita_immobiliare_id
JOIN soggetti so ON dr.soggetto_id = so.id
WHERE s.is_active = TRUE 
    AND ui.is_active = TRUE
    AND dr.is_active = TRUE
    AND dr.tipo_diritto = 'proprietario'
ORDER BY s.denominazione, ui.numero;

🗂️ MIGRATIONS LARAVEL

Migration Base Contabilità

<?php
// database/migrations/2025_08_03_100000_create_contabilita_tables.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        // Piano dei conti
        Schema::create('piano_conti', function (Blueprint $table) {
            $table->id();
            $table->string('mastro', 10);
            $table->string('conto', 10);
            $table->string('sottoconto', 10);
            $table->string('descrizione');
            $table->enum('tipo', ['attivo', 'passivo', 'costo', 'ricavo']);
            $table->boolean('attivo')->default(true);
            $table->timestamps();
            
            $table->index(['mastro', 'conto', 'sottoconto']);
            $table->index(['tipo']);
            $table->index(['attivo']);
            $table->index(['descrizione']);
        });

        // Gestioni
        Schema::create('gestioni', function (Blueprint $table) {
            $table->id();
            $table->string('denominazione');
            $table->integer('anno');
            $table->date('data_inizio');
            $table->date('data_fine');
            $table->boolean('attivo')->default(true);
            $table->foreignId('stabile_id')->nullable()->constrained('stabili')->onDelete('set null');
            $table->timestamps();
            
            $table->index(['anno']);
            $table->index(['attivo']);
            $table->index(['stabile_id']);
            $table->unique(['stabile_id', 'anno']);
        });

        // Registrazioni contabili
        Schema::create('registrazioni_contabili', function (Blueprint $table) {
            $table->id();
            $table->date('data_registrazione');
            $table->string('numero_registrazione', 20)->nullable();
            $table->text('descrizione');
            $table->decimal('importo_dare', 12, 2)->default(0.00);
            $table->decimal('importo_avere', 12, 2)->default(0.00);
            $table->foreignId('piano_conti_id')->constrained('piano_conti')->onDelete('restrict');
            $table->foreignId('gestione_id')->constrained('gestioni')->onDelete('restrict');
            $table->foreignId('user_id')->constrained('users')->onDelete('restrict');
            $table->string('documento_riferimento')->nullable();
            $table->text('note')->nullable();
            $table->timestamps();
            
            $table->index(['data_registrazione']);
            $table->index(['piano_conti_id']);
            $table->index(['gestione_id']);
            $table->index(['user_id']);
            $table->index(['numero_registrazione']);
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('registrazioni_contabili');
        Schema::dropIfExists('gestioni');
        Schema::dropIfExists('piano_conti');
    }
};

Seeder Piano dei Conti

<?php
// database/seeders/PianoContiSeeder.php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class PianoContiSeeder extends Seeder
{
    public function run(): void
    {
        $piano_conti = [
            // CLASSE 1 - CONTI FINANZIARI
            ['1', '01', '01', 'Cassa contanti', 'attivo'],
            ['1', '01', '02', 'Banca c/c ordinario', 'attivo'],
            ['1', '01', '03', 'Banca c/c vincolato', 'attivo'],
            ['1', '01', '04', 'Poste c/c', 'attivo'],
            
            // CLASSE 2 - CREDITI E DEBITI
            ['2', '01', '01', 'Crediti vs condomini', 'attivo'],
            ['2', '01', '02', 'Crediti vs inquilini', 'attivo'],
            ['2', '02', '01', 'Debiti vs fornitori', 'passivo'],
            ['2', '02', '02', 'Debiti tributari', 'passivo'],
            ['2', '02', '03', 'Debiti previdenziali', 'passivo'],
            
            // CLASSE 5 - COSTI
            ['5', '01', '01', 'Spese per energia elettrica', 'costo'],
            ['5', '01', '02', 'Spese per riscaldamento', 'costo'],
            ['5', '01', '03', 'Spese per acqua', 'costo'],
            ['5', '02', '01', 'Spese pulizie', 'costo'],
            ['5', '02', '02', 'Spese manutenzione ordinaria', 'costo'],
            ['5', '02', '03', 'Spese manutenzione straordinaria', 'costo'],
            ['5', '03', '01', 'Compensi amministratore', 'costo'],
            ['5', '03', '02', 'Spese legali', 'costo'],
            
            // CLASSE 7 - RICAVI
            ['7', '01', '01', 'Quote condominiali ordinarie', 'ricavo'],
            ['7', '01', '02', 'Quote condominiali straordinarie', 'ricavo'],
            ['7', '02', '01', 'Interessi attivi bancari', 'ricavo'],
            ['7', '02', '02', 'Altri ricavi', 'ricavo'],
        ];

        foreach ($piano_conti as [$mastro, $conto, $sottoconto, $descrizione, $tipo]) {
            DB::table('piano_conti')->insert([
                'mastro' => $mastro,
                'conto' => $conto,
                'sottoconto' => $sottoconto,
                'descrizione' => $descrizione,
                'tipo' => $tipo,
                'attivo' => true,
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        }

        $this->command->info('Piano dei conti standard caricato: ' . count($piano_conti) . ' conti');
    }
}

🔍 TROUBLESHOOTING DATABASE

1. Errori di Connessione

# Test connessione database
mysql -h 127.0.0.1 -u netgescon_user -p netgescon

# Verifica privilegi utente
SHOW GRANTS FOR 'netgescon_user'@'localhost';

# Reset password se necessario
ALTER USER 'netgescon_user'@'localhost' IDENTIFIED BY 'NetGescon2024!';
FLUSH PRIVILEGES;

2. Problemi Performance

-- Verifica indici mancanti
SELECT TABLE_NAME, COLUMN_NAME 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_SCHEMA = 'netgescon' 
AND COLUMN_NAME LIKE '%_id' 
AND TABLE_NAME NOT IN (
    SELECT DISTINCT TABLE_NAME 
    FROM INFORMATION_SCHEMA.STATISTICS 
    WHERE TABLE_SCHEMA = 'netgescon'
);

-- Analizza query lente
SHOW PROCESSLIST;
SELECT * FROM performance_schema.events_statements_summary_by_digest 
ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;

3. Problemi Integrità

-- Verifica foreign keys orfane
SELECT rc.id, rc.piano_conti_id 
FROM registrazioni_contabili rc 
LEFT JOIN piano_conti pc ON rc.piano_conti_id = pc.id 
WHERE pc.id IS NULL;

-- Ripristina integrità referenziale
SET FOREIGN_KEY_CHECKS = 0;
-- Operazioni di pulizia
SET FOREIGN_KEY_CHECKS = 1;

💾 BACKUP E MANUTENZIONE

Script Backup Strutturale

#!/bin/bash
# backup-netgescon-structure.sh

DB_NAME="netgescon"
DB_USER="netgescon_user"
DB_PASS="NetGescon2024!"
BACKUP_DIR="/var/backups/netgescon"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

# Backup solo struttura (per sviluppo)
mysqldump -h 127.0.0.1 -u $DB_USER -p$DB_PASS \
    --no-data \
    --routines \
    --triggers \
    $DB_NAME > $BACKUP_DIR/netgescon_structure_$DATE.sql

# Backup dati base (lookup tables)
mysqldump -h 127.0.0.1 -u $DB_USER -p$DB_PASS \
    --no-create-info \
    --where="1=1" \
    $DB_NAME \
    comuni_italiani \
    piano_conti \
    roles \
    permissions > $BACKUP_DIR/netgescon_base_data_$DATE.sql

echo "✅ Backup strutturale completato:"
echo "   - Struttura: $BACKUP_DIR/netgescon_structure_$DATE.sql"
echo "   - Dati base: $BACKUP_DIR/netgescon_base_data_$DATE.sql"

Manutenzione Routine

-- Ottimizzazione tabelle
OPTIMIZE TABLE registrazioni_contabili;
OPTIMIZE TABLE piano_conti;
OPTIMIZE TABLE gestioni;

-- Analisi statistiche per optimizer
ANALYZE TABLE registrazioni_contabili;
ANALYZE TABLE piano_conti;

-- Pulizia log binari (attenzione in produzione!)
PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 7 DAY);

📈 MONITORAGGIO E STATISTICHE

Query Statistiche Sistema

-- Statistiche generali database
SELECT 
    TABLE_NAME,
    TABLE_ROWS,
    ROUND(DATA_LENGTH/1024/1024, 2) as 'Dimensione_MB',
    ROUND(INDEX_LENGTH/1024/1024, 2) as 'Indici_MB'
FROM information_schema.TABLES 
WHERE TABLE_SCHEMA = 'netgescon'
ORDER BY DATA_LENGTH DESC;

-- Conteggi record principali
SELECT 'stabili' as tabella, COUNT(*) as records FROM stabili
UNION ALL
SELECT 'unita_immobiliari', COUNT(*) FROM unita_immobiliari
UNION ALL
SELECT 'soggetti', COUNT(*) FROM soggetti
UNION ALL
SELECT 'registrazioni_contabili', COUNT(*) FROM registrazioni_contabili
UNION ALL
SELECT 'users', COUNT(*) FROM users;

CHECKLIST IMPLEMENTAZIONE DATABASE

Setup Iniziale

  • Database 'netgescon' creato
  • Utente 'netgescon_user' configurato
  • Privilegi assegnati correttamente
  • Connessione testata da Laravel

Tabelle Core

  • users, roles, permissions (Spatie)
  • comuni_italiani caricati
  • stabili, unita_immobiliari
  • soggetti, diritti_reali

Modulo Contabilità

  • piano_conti con dati standard
  • gestioni configurate
  • registrazioni_contabili funzionanti
  • Query bilancio testate

Indici e Performance

  • Indici su foreign keys
  • Indici su campi di ricerca
  • Query ottimizzate per pagine principali
  • Performance monitoring attivo

Backup e Sicurezza

  • Script backup automatico
  • Restore procedure testate
  • Accessi database limitati
  • Log delle modifiche attivato

🎯 QUESTO MANUALE È BASATO SULL'IMPLEMENTAZIONE REALE

Tutte le strutture database documentate sono state testate e validate nell'implementazione del modulo Contabilità. Le credenziali unificate garantiscono compatibilità tra tutti i moduli NetGescon.

📞 SUPPORTO DATABASE

  • Utilizzare sempre le credenziali unificate documentate
  • Seguire le naming conventions italiane
  • Implementare indici per performance
  • Mantenere integrità referenziale

🔄 PROSSIMI AGGIORNAMENTI

  • Strutture moduli Assemblee e Manutenzioni
  • Ottimizzazioni performance avanzate
  • Procedure stored per operazioni complesse
  • Replica e alta disponibilità