# Database Schema & Migrations - Sistema Versionato ## Overview Sistema intelligente di migrazioni database con **version tracking**. Applica solo le migrazioni necessarie, velocizzando gli aggiornamenti. ## 🎯 Vantaggi βœ… **Veloce**: Applica solo migrazioni mancanti (non riesegue quelle giΓ  fatte) βœ… **Sicuro**: Traccia versione database, previene errori βœ… **Automatico**: Integrato in `update_from_git.sh` βœ… **Idempotente**: Puoi eseguire piΓΉ volte senza problemi ## πŸ“‹ Come Funziona ### 1. Tabella `schema_version` Traccia la versione corrente del database: ```sql CREATE TABLE schema_version ( id INTEGER PRIMARY KEY DEFAULT 1, -- Sempre 1 (solo 1 riga) version INTEGER NOT NULL, -- Versione corrente (es: 5) applied_at TIMESTAMP, -- Quando Γ¨ stata applicata description TEXT -- Descrizione ultima migrazione ); ``` ### 2. Migrazioni Numerate Ogni migrazione SQL ha un numero sequenziale nel nome: ``` database-schema/migrations/ β”œβ”€β”€ 000_init_schema_version.sql ← Inizializza tracking (sempre eseguita) β”œβ”€β”€ 001_add_missing_columns.sql ← Migrazione 1 β”œβ”€β”€ 002_add_indexes.sql ← Migrazione 2 β”œβ”€β”€ 003_alter_detections.sql ← Migrazione 3 └── ... ``` **Convenzione nome**: `XXX_description.sql` dove XXX Γ¨ numero a 3 cifre (001, 002, 010, 100, etc.) ### 3. Logica Applicazione ```bash # Script legge versione corrente CURRENT_VERSION = SELECT version FROM schema_version WHERE id = 1; # Esempio: 2 # Trova migrazioni con numero > 2 Trova: 003_*.sql, 004_*.sql, 005_*.sql # Applica in ordine Per ogni migrazione: 1. Esegui SQL 2. Aggiorna versione: UPDATE schema_version SET version = 3 3. Prossima migrazione... # Risultato: Database aggiornato da v2 a v5 ``` ## πŸš€ Uso Quotidiano ### Aggiornamento Automatico (Consigliato) ```bash # Sul server AlmaLinux cd /opt/ids sudo ./deployment/update_from_git.sh # Lo script esegue automaticamente: # 1. Git pull # 2. npm install # 3. pip install # 4. ./database-schema/apply_migrations.sh ← Applica migrazioni # 5. npm run db:push ← Sincronizza schema Drizzle # 6. Restart servizi ``` **Output atteso**: ``` πŸ—„οΈ Sistema Migrazioni Database (Versioned) πŸ“‹ Verifica sistema versioning... βœ… Sistema versioning attivo πŸ“Š Versione database corrente: 2 πŸ“‹ Trovate 3 migrazioni da applicare πŸ”„ Applicando migrazione 3: 003_add_indexes.sql βœ… Migrazione 3 applicata con successo πŸ”„ Applicando migrazione 4: 004_alter_table.sql βœ… Migrazione 4 applicata con successo πŸ”„ Applicando migrazione 5: 005_new_feature.sql βœ… Migrazione 5 applicata con successo ╔═══════════════════════════════════════════════╗ β•‘ βœ… MIGRAZIONI COMPLETATE β•‘ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• πŸ“Š Versione database: 2 β†’ 5 ``` Se database giΓ  aggiornato: ``` πŸ“Š Versione database corrente: 5 βœ… Database giΓ  aggiornato (nessuna migrazione da applicare) ``` ### Applicazione Manuale ```bash cd /opt/ids/database-schema ./apply_migrations.sh ``` ### Verifica Versione Corrente ```bash psql $DATABASE_URL -c "SELECT * FROM schema_version;" id | version | applied_at | description ----+---------+----------------------------+----------------------- 1 | 5 | 2025-11-22 14:30:15.123456 | Migration 5: Add indexes ``` ## πŸ”¨ Creare Nuova Migrazione ### STEP 1: Determina Prossimo Numero ```bash # Trova ultima migrazione ls database-schema/migrations/ | grep "^[0-9]" | sort | tail -n 1 # Output: 005_add_indexes.sql # Prossima migrazione: 006 ``` ### STEP 2: Crea File Migrazione ```bash # Formato: XXX_description.sql touch database-schema/migrations/006_add_new_table.sql ``` ### STEP 3: Scrivi SQL ```sql -- ============================================================================ -- Migration 006: Add new table for feature X -- ============================================================================ -- Descrizione: Crea tabella per gestire feature X -- Data: 2025-11-22 -- ============================================================================ CREATE TABLE IF NOT EXISTS my_new_table ( id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, created_at TIMESTAMP DEFAULT NOW() NOT NULL ); -- Crea indici CREATE INDEX IF NOT EXISTS my_new_table_name_idx ON my_new_table(name); -- Inserisci dati iniziali (se necessario) INSERT INTO my_new_table (name) SELECT 'Default Entry' WHERE NOT EXISTS (SELECT 1 FROM my_new_table LIMIT 1); ``` **Best Practices**: - Usa sempre `IF NOT EXISTS` (idempotenza) - Usa `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` - Documenta bene la migrazione - Testa localmente prima di committare ### STEP 4: Testa Localmente (Replit) ```bash # Su Replit cd database-schema ./apply_migrations.sh # Verifica versione aggiornata psql $DATABASE_URL -c "SELECT version FROM schema_version;" ``` ### STEP 5: Commit & Deploy ```bash # Su Replit ./push-gitlab.sh # Sul server cd /opt/ids sudo ./deployment/update_from_git.sh ``` ## πŸ“Š Esempi Migrazioni Comuni ### Aggiungere Colonna ```sql -- Migration XXX: Add email column to users ALTER TABLE users ADD COLUMN IF NOT EXISTS email TEXT; ``` ### Creare Indice ```sql -- Migration XXX: Add index on source_ip CREATE INDEX IF NOT EXISTS network_logs_source_ip_idx ON network_logs(source_ip); ``` ### Modificare Tipo Colonna (ATTENZIONE!) ```sql -- Migration XXX: Change column type -- NOTA: PuΓ² causare perdita dati se incompatibile! ALTER TABLE detections ALTER COLUMN risk_score TYPE DECIMAL(5,2) USING risk_score::DECIMAL(5,2); ``` ### Inserire Dati Iniziali ```sql -- Migration XXX: Add default admin user INSERT INTO users (username, role) SELECT 'admin', 'admin' WHERE NOT EXISTS ( SELECT 1 FROM users WHERE username = 'admin' ); ``` ## πŸ” Troubleshooting ### Errore: Migrazione Fallisce ```bash # Verifica errore psql $DATABASE_URL -c "SELECT version FROM schema_version;" # Se migrazione 5 Γ¨ fallita, il database Γ¨ ancora a v4 # Fix: Correggi file 005_*.sql e riesegui ./apply_migrations.sh ``` ### Reset Completo (ATTENZIONE!) ```bash # ⚠️ DISTRUTTIVO - Cancella tutti i dati! psql $DATABASE_URL << 'EOF' DROP SCHEMA public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO ids_user; GRANT ALL ON SCHEMA public TO public; EOF # Ricrea schema da zero npm run db:push --force ./apply_migrations.sh ``` ### Saltare Migrazione (Avanzato) ```bash # Se migrazione 003 Γ¨ giΓ  applicata manualmente # Aggiorna versione manualmente psql $DATABASE_URL -c " UPDATE schema_version SET version = 3, description = 'Migration 3: Manually applied', applied_at = NOW() WHERE id = 1; " ``` ## 🎯 Workflow Completo ### Sviluppo (Replit) 1. Modifica schema in `shared/schema.ts` 2. Esegui `npm run db:push` (sincronizza Drizzle) 3. Se serve migrazione SQL custom: - Crea `XXX_description.sql` - Testa con `./apply_migrations.sh` 4. Commit: `./push-gitlab.sh` ### Produzione (AlmaLinux) 1. `sudo ./deployment/update_from_git.sh` 2. Script applica automaticamente migrazioni 3. Verifica: `psql $DATABASE_URL -c "SELECT * FROM schema_version;"` ## πŸ“ Note Tecniche - **000_init_schema_version.sql**: Sempre eseguita (idempotente), inizializza tracking - **Constraint**: Tabella `schema_version` ammette solo 1 riga (id=1) - **Formato numeri**: Usa 3 cifre (001, 002, ..., 010, ..., 100) per ordinamento corretto - **Drizzle vs SQL**: `npm run db:push` sincronizza schema TypeScript, migrazioni SQL sono per logica custom ## βœ… Checklist Pre-Commit Quando crei nuova migrazione: - [ ] Numero sequenziale corretto (XXX+1) - [ ] Nome file descrittivo - [ ] Commento header con descrizione - [ ] SQL idempotente (`IF NOT EXISTS`, etc.) - [ ] Testata localmente su Replit - [ ] Versione aggiornata: `SELECT version FROM schema_version;` - [ ] Commit message chiaro