# Database Engine Aanbeveling - Azure Productie ## Huidige Situatie De applicatie gebruikt momenteel **SQLite** via `better-sqlite3`: - **cmdb-cache.db**: ~20MB - CMDB object cache - **classifications.db**: Classification history ## Aanbeveling: PostgreSQL > **Belangrijk**: Azure Database for MariaDB wordt afgeschaft (retirement september 2025). > De keuze is daarom tussen **PostgreSQL** en **MySQL** (niet MariaDB). ### PostgreSQL vs MySQL Vergelijking | Feature | PostgreSQL | MySQL (Azure) | |---------|------------|---------------| | **Azure Support** | ✅ Flexible Server | ✅ Flexible Server | | **Kosten (B1ms)** | ~€20-30/maand | ~€20-30/maand | | **JSON Support** | ✅ JSONB (superieur) | ✅ JSON (basis) | | **Performance** | ✅ Uitstekend | ✅ Goed | | **Concurrency** | ✅ MVCC (zeer goed) | ✅ Goed | | **SQL Standards** | ✅ Zeer compliant | ⚠️ Eigen dialect | | **Full-Text Search** | ✅ Ingebouwd | ⚠️ Basis | | **Community** | ✅ Groot & actief | ✅ Groot & actief | | **Development Tools** | ✅ Uitstekend | ✅ Goed | **Voor jouw use case (JSON data, 20 gebruikers):** ✅ **PostgreSQL heeft voordeel:** - **JSONB**: Betere JSON performance en querying (gebruikt in huidige schema) - **MVCC**: Betere concurrency voor 20 gelijktijdige gebruikers - **SQL Standards**: Makkelijker migreren van SQLite - **Full-Text Search**: Ingebouwd (handig voor toekomstige zoekfuncties) ✅ **MySQL is ook goed:** - Vergelijkbare kosten - Goede performance - Veel gebruikt (bekende technologie) **Conclusie**: Beide zijn goede keuzes. PostgreSQL heeft lichte voordelen voor JSON-heavy workloads en betere SQLite compatibiliteit. ### Waarom PostgreSQL? ✅ **Identieke Dev/Prod Stack** - Lokaal: PostgreSQL via Docker (gratis) - Azure: Azure Database for PostgreSQL Flexible Server - Zelfde database engine, zelfde SQL syntax ✅ **Azure Integratie** - Native ondersteuning in Azure - Managed service (geen server management) - Betaalbaar: Basic tier ~€20-30/maand voor 20 gebruikers ✅ **Performance** - Betere concurrency dan SQLite (20 gebruikers) - Connection pooling (nodig voor web apps) - Betere query performance bij groei ✅ **Features** - JSON support (gebruikt in huidige schema) - Transactions - Foreign keys - Full-text search (toekomstig) ✅ **Development Experience** - Docker setup identiek aan productie - Migraties mogelijk (Prisma, Knex, etc.) - Betere tooling ### Alternatief: SQLite Blijven **Voordelen:** - ✅ Geen migratie nodig - ✅ Werkt in Azure App Service (file storage) - ✅ Gratis - ✅ Eenvoudig **Nadelen:** - ❌ Beperkte concurrency (kan problemen geven met 20 gebruikers) - ❌ Geen connection pooling - ❌ File-based (moeilijker backup/restore) - ❌ Beperkte query performance bij groei **Conclusie**: SQLite kan werken voor 20 gebruikers, maar PostgreSQL is beter voor productie. --- ## Migratie naar PostgreSQL ### Stappenplan #### 1. Database Abstraction Layer Maak een database abstraction layer zodat we kunnen wisselen tussen SQLite (dev) en PostgreSQL (prod): ```typescript // backend/src/services/database/interface.ts export interface DatabaseAdapter { query(sql: string, params?: any[]): Promise; execute(sql: string, params?: any[]): Promise; transaction(callback: (db: DatabaseAdapter) => Promise): Promise; close(): Promise; } ``` #### 2. PostgreSQL Adapter ```typescript // backend/src/services/database/postgresAdapter.ts import { Pool } from 'pg'; export class PostgresAdapter implements DatabaseAdapter { private pool: Pool; constructor(connectionString: string) { this.pool = new Pool({ connectionString }); } async query(sql: string, params?: any[]): Promise { const result = await this.pool.query(sql, params); return result.rows; } // ... implement other methods } ``` #### 3. SQLite Adapter (voor backward compatibility) ```typescript // backend/src/services/database/sqliteAdapter.ts import Database from 'better-sqlite3'; export class SqliteAdapter implements DatabaseAdapter { private db: Database.Database; constructor(dbPath: string) { this.db = new Database(dbPath); } async query(sql: string, params?: any[]): Promise { const stmt = this.db.prepare(sql); return stmt.all(...(params || [])) as any[]; } // ... implement other methods } ``` #### 4. Schema Migratie **SQLite → PostgreSQL verschillen:** - `INTEGER PRIMARY KEY AUTOINCREMENT` → `SERIAL PRIMARY KEY` - `TEXT` → `TEXT` of `VARCHAR` - `JSON` → `JSONB` (beter in PostgreSQL) - `ON CONFLICT` → `ON CONFLICT` (werkt in beide) **SQLite → MySQL verschillen:** - `INTEGER PRIMARY KEY AUTOINCREMENT` → `INT AUTO_INCREMENT PRIMARY KEY` - `TEXT` → `TEXT` of `VARCHAR(255)` - `JSON` → `JSON` (basis support) - `ON CONFLICT` → `ON DUPLICATE KEY UPDATE` (andere syntax) --- ## Azure Setup ### Optie 1: Azure Database for PostgreSQL Flexible Server **Basic Tier (aanbevolen voor 20 gebruikers):** - **Burstable B1ms**: 1 vCore, 2GB RAM - **Storage**: 32GB (meer dan genoeg voor 20MB database) - **Kosten**: ~€20-30/maand - **Backup**: 7 dagen retention (gratis) **Configuratie:** ```bash # Azure CLI az postgres flexible-server create \ --resource-group rg-cmdb-gui \ --name psql-cmdb-gui \ --location westeurope \ --admin-user cmdbadmin \ --admin-password \ --sku-name Standard_B1ms \ --tier Burstable \ --storage-size 32 \ --version 15 ``` **Connection String:** ``` postgresql://cmdbadmin:@psql-cmdb-gui.postgres.database.azure.com:5432/cmdb?sslmode=require ``` ### Optie 2: Azure Database for MySQL Flexible Server **Basic Tier (aanbevolen voor 20 gebruikers):** - **Burstable B1ms**: 1 vCore, 2GB RAM - **Storage**: 32GB (meer dan genoeg voor 20MB database) - **Kosten**: ~€20-30/maand - **Backup**: 7 dagen retention (gratis) **Configuratie:** ```bash # Azure CLI az mysql flexible-server create \ --resource-group rg-cmdb-gui \ --name mysql-cmdb-gui \ --location westeurope \ --admin-user cmdbadmin \ --admin-password \ --sku-name Standard_B1ms \ --tier Burstable \ --storage-size 32 \ --version 8.0.21 ``` **Connection String:** ``` mysql://cmdbadmin:@mysql-cmdb-gui.mysql.database.azure.com:3306/cmdb?ssl-mode=REQUIRED ``` **MySQL vs PostgreSQL voor jouw schema:** - **JSON**: MySQL heeft JSON type, maar PostgreSQL JSONB is sneller voor queries - **AUTOINCREMENT**: MySQL gebruikt `AUTO_INCREMENT`, PostgreSQL gebruikt `SERIAL` (beide werken) - **ON CONFLICT**: MySQL gebruikt `ON DUPLICATE KEY UPDATE`, PostgreSQL gebruikt `ON CONFLICT` (beide werken) --- ## Local Development Setup ### Optie 1: Docker Compose voor PostgreSQL Voeg toe aan `docker-compose.yml`: ```yaml services: postgres: image: postgres:15-alpine environment: POSTGRES_DB: cmdb POSTGRES_USER: cmdb POSTGRES_PASSWORD: cmdb-dev ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U cmdb"] interval: 10s timeout: 5s retries: 5 volumes: postgres_data: ``` ### Optie 2: Docker Compose voor MySQL Voeg toe aan `docker-compose.yml`: ```yaml services: mysql: image: mysql:8.0 environment: MYSQL_DATABASE: cmdb MYSQL_USER: cmdb MYSQL_PASSWORD: cmdb-dev MYSQL_ROOT_PASSWORD: root-dev ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 volumes: mysql_data: ``` **Environment variabelen (lokaal - PostgreSQL):** ```bash # .env.local DATABASE_URL=postgresql://cmdb:cmdb-dev@localhost:5432/cmdb # of DATABASE_TYPE=postgres DATABASE_HOST=localhost DATABASE_PORT=5432 DATABASE_NAME=cmdb DATABASE_USER=cmdb DATABASE_PASSWORD=cmdb-dev ``` **Environment variabelen (Azure):** ```bash # Azure App Service Configuration DATABASE_TYPE=postgres DATABASE_HOST=psql-cmdb-gui.postgres.database.azure.com DATABASE_PORT=5432 DATABASE_NAME=cmdb DATABASE_USER=cmdbadmin DATABASE_PASSWORD= DATABASE_SSL=true ``` **Environment variabelen (lokaal - MySQL):** ```bash # .env.local DATABASE_URL=mysql://cmdb:cmdb-dev@localhost:3306/cmdb # of DATABASE_TYPE=mysql DATABASE_HOST=localhost DATABASE_PORT=3306 DATABASE_NAME=cmdb DATABASE_USER=cmdb DATABASE_PASSWORD=cmdb-dev ``` **Environment variabelen (Azure - MySQL):** ```bash # Azure App Service Configuration DATABASE_TYPE=mysql DATABASE_HOST=mysql-cmdb-gui.mysql.database.azure.com DATABASE_PORT=3306 DATABASE_NAME=cmdb DATABASE_USER=cmdbadmin DATABASE_PASSWORD= DATABASE_SSL=true ``` --- ## Kosten Vergelijking | Optie | Lokaal | Azure (maandelijks) | Totaal | |-------|--------|---------------------|--------| | **PostgreSQL** | Gratis (Docker) | €20-30 | €20-30 | | **MySQL** | Gratis (Docker) | €20-30 | €20-30 | | **SQLite** | Gratis | €0 (in App Service) | €0 | | **Azure SQL** | SQL Server Express | €50-100 | €50-100 | **Aanbeveling**: PostgreSQL - beste balans tussen kosten, performance en identieke stack. MySQL is ook een goede keuze met vergelijkbare kosten en performance. --- ## Migratie Script ### SQLite naar PostgreSQL Converter ```typescript // scripts/migrate-sqlite-to-postgres.ts import Database from 'better-sqlite3'; import { Pool } from 'pg'; async function migrate() { // Connect to SQLite const sqlite = new Database('./data/cmdb-cache.db'); // Connect to PostgreSQL const pg = new Pool({ connectionString: process.env.DATABASE_URL }); // Migrate cached_objects const objects = sqlite.prepare('SELECT * FROM cached_objects').all(); for (const obj of objects) { await pg.query( `INSERT INTO cached_objects (id, object_key, object_type, label, data, jira_updated_at, jira_created_at, cached_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (id) DO NOTHING`, [obj.id, obj.object_key, obj.object_type, obj.label, obj.data, obj.jira_updated_at, obj.jira_created_at, obj.cached_at] ); } // Migrate relations, metadata, etc. // ... sqlite.close(); await pg.end(); } ``` --- ## Implementatie Plan ### Fase 1: Database Abstraction (1-2 dagen) 1. Maak `DatabaseAdapter` interface 2. Implementeer `PostgresAdapter` en `SqliteAdapter` 3. Update `CacheStore` en `DatabaseService` om adapter te gebruiken ### Fase 2: Local PostgreSQL Setup (0.5 dag) 1. Voeg PostgreSQL toe aan docker-compose.yml 2. Test lokaal met PostgreSQL 3. Update environment configuratie ### Fase 3: Schema Migratie (1 dag) 1. Converteer SQLite schema naar PostgreSQL 2. Maak migratie script 3. Test migratie lokaal ### Fase 4: Azure Setup (1 dag) 1. Maak Azure Database for PostgreSQL 2. Configureer connection string in Key Vault 3. Test connectiviteit ### Fase 5: Productie Migratie (0.5 dag) 1. Migreer data van SQLite naar PostgreSQL 2. Update App Service configuratie 3. Test in productie **Totaal**: ~3-4 dagen werk --- ## Aanbeveling ### 🏆 PostgreSQL (Aanbevolen) **Gebruik PostgreSQL** voor: - ✅ Identieke dev/prod stack - ✅ Betere JSON performance (JSONB) - ✅ Betere concurrency (MVCC) - ✅ Azure native ondersteuning - ✅ Toekomstbestendig - ✅ Betaalbaar (~€20-30/maand) - ✅ Makkelijker migratie van SQLite (SQL syntax) ### ✅ MySQL (Ook goed) **MySQL is ook een goede keuze** als: - Je team meer ervaring heeft met MySQL - Je voorkeur geeft aan MySQL ecosystem - Vergelijkbare kosten en performance acceptabel zijn - Je JSON queries niet te complex zijn **Nadelen t.o.v. PostgreSQL:** - ⚠️ Minder geavanceerde JSON support (geen JSONB) - ⚠️ Minder SQL standards compliant - ⚠️ Iets andere syntax voor conflicten ### 💰 SQLite (Minimale kosten) **SQLite blijft optie** als: - Je snel moet deployen zonder migratie - Kosten kritiek zijn (€0 vs €20-30) - Je accepteert beperkingen (concurrency, performance) **Conclusie**: Voor jouw use case (JSON data, 20 gebruikers) is **PostgreSQL de beste keuze**, maar MySQL is ook prima. Beide zijn veel beter dan SQLite voor productie. --- ## Next Steps 1. **Beslissing**: PostgreSQL of SQLite blijven? 2. **Als PostgreSQL**: Start met Fase 1 (Database Abstraction) 3. **Als SQLite**: Documenteer beperkingen en overweeg toekomstige migratie