# 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
