mitai-jinkendo/.claude/docs/technical/MIGRATIONS.md
Lars 7940dc7560 docs: Struktur .claude/docs versionieren, working/, Gitea-Index, Regeln
- .gitignore: .claude/docs, rules, commands tracken; settings.local weiter ignorieren
- DOCUMENTATION.md: verbindliche Ablage functional/technical/working/issues
- .claude/README.md: Agent-Einstieg; GITEA_ISSUES_INDEX aus MCP (Stand 2026-04-08)
- Arbeitspapiere von docs/ nach .claude/docs/working/ verschoben
- docs/MEMBERSHIP_SYSTEM.md als Stub; kanonisch technical/MEMBERSHIP_SYSTEM.md
- CLAUDE.md Pflichtlektüre und Links angepasst; docs/README.md vereinfacht

Made-with: Cursor
2026-04-08 13:01:49 +02:00

11 KiB

Database Migrations System

Version: v9c Implementiert: 2026-03-21 Dokumentiert: 2026-03-21


Übersicht

Mitai Jinkendo verwendet ein automatisches Migrations-System für strukturierte Schema-Änderungen. Alle Migrationen werden beim Container-Start automatisch ausgeführt.

Architektur

Migration-Tracking

Tabelle: schema_migrations

CREATE TABLE schema_migrations (
    id SERIAL PRIMARY KEY,
    filename VARCHAR(255) UNIQUE NOT NULL,
    applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
)

Diese Tabelle trackt, welche Migrationen bereits angewendet wurden.

Ablauf beim Container-Start

  1. PostgreSQL Connection Check (db_init.py)
  2. Schema-Initialisierung (falls profiles Tabelle nicht existiert)
    • Lädt backend/schema.sql (Basis-Schema)
  3. Migrations-System (run_migrations())
    • Erstellt schema_migrations Tabelle (falls nicht vorhanden)
    • Scannt backend/migrations/ nach .sql Dateien
    • Filtert nur nummerierte Dateien: \d{3}_*.sql (z.B. 001_feature.sql)
    • Sortiert alphabetisch (aufsteigende Reihenfolge)
    • Wendet nur noch nicht angewendete Migrationen an
    • Trackt jede erfolgreich angewendete Migration
  4. SQLite-zu-PostgreSQL Migration (falls vorhanden)

Datei-Konventionen

Naming-Pattern

Format: XXX_descriptive_name.sql

  • XXX = Dreistellige Nummer (001, 002, 003, ...)
  • Unterstrich _ als Trennzeichen
  • Kleinbuchstaben, keine Leerzeichen
  • .sql Extension

Beispiele:

✅ 001_subscription_system.sql
✅ 002_fix_features.sql
✅ 003_add_email_verification.sql

❌ v9c_subscription_system.sql    # Keine Nummer
❌ check_features.sql              # Keine Nummer
❌ 1_feature.sql                   # Nur eine Ziffer
❌ 001-feature.sql                 # Bindestrich statt Unterstrich

Datei-Struktur

Jede Migration sollte folgende Struktur haben:

-- ================================================================
-- Migration XXX: Beschreibung
-- Version: vX.X
-- Date: YYYY-MM-DD
-- ================================================================

-- Beschreibung der Änderung
ALTER TABLE table_name ...

-- Weitere SQL-Statements

-- Kommentare für Dokumentation
COMMENT ON COLUMN table.column IS 'Beschreibung';

SQL-Einschränkungen

Erlaubt:

  • Standard SQL DDL (CREATE, ALTER, DROP)
  • Standard SQL DML (INSERT, UPDATE, DELETE)
  • CREATE INDEX, CREATE FUNCTION, etc.
  • Multi-Statement-Scripts (durch ; getrennt)

Nicht erlaubt:

  • psql Meta-Kommandos (\echo, \set, \connect, etc.)
  • Interactive Commands (\i, \include)
  • Transaktions-Kontrolle (automatisch gehandhabt)

Anwendung

Automatisch (Production/Dev)

Migrationen werden automatisch beim Container-Start angewendet:

# Container startet
docker compose up -d

# db_init.py wird ausgeführt:
# 1. PostgreSQL ready check
# 2. Schema initialisiert (falls nötig)
# 3. Migrationen ausgeführt
# 4. SQLite-Migration (falls nötig)

Log-Output:

═══════════════════════════════════════════════════════════
MITAI JINKENDO - Database Initialization (v9c)
═══════════════════════════════════════════════════════════

Checking PostgreSQL connection...
✓ PostgreSQL ready

Checking database schema...
✓ Schema already exists

Running database migrations...
  Found 2 pending migration(s)...
  ✓ Applied: 001_subscription_system.sql
  ✓ Applied: 003_add_email_verification.sql

✓ Database initialization complete

Manuell (Entwicklung)

Für Testing während der Entwicklung:

# Im laufenden Container
docker exec -it dev-mitai-api python3 /app/db_init.py

# Oder direkt mit psql (für einzelne Migrationen)
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
  -f /path/to/migration.sql

Migration erstellen

Schritt 1: Datei erstellen

# Nächste freie Nummer ermitteln
ls backend/migrations/ | grep -E '^\d{3}_' | sort | tail -1
# → 003_add_email_verification.sql

# Neue Migration mit Nummer 004
touch backend/migrations/004_add_new_feature.sql

Schritt 2: SQL schreiben

-- ================================================================
-- Migration 004: Add New Feature
-- Version: v9d
-- Date: 2026-03-22
-- ================================================================

-- Add new column
ALTER TABLE profiles
ADD COLUMN IF NOT EXISTS new_feature_enabled BOOLEAN DEFAULT TRUE;

-- Create index if needed
CREATE INDEX IF NOT EXISTS idx_profiles_new_feature
ON profiles(new_feature_enabled)
WHERE new_feature_enabled = TRUE;

-- Update existing data if needed
UPDATE profiles
SET new_feature_enabled = TRUE
WHERE tier = 'premium';

COMMENT ON COLUMN profiles.new_feature_enabled IS 'Feature flag for new feature';

Schritt 3: Testen

# Lokal testen (Dev-Container)
git add backend/migrations/004_add_new_feature.sql
git commit -m "feat: add migration for new feature"
git push origin develop

# Container wird neu gebaut und Migration automatisch angewendet

Schritt 4: Verifizieren

# Prüfen ob Migration angewendet wurde
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
  -c "SELECT * FROM schema_migrations ORDER BY applied_at DESC LIMIT 5;"

# Output:
# id | filename                      | applied_at
# ---+------------------------------+------------------------
#  4 | 004_add_new_feature.sql      | 2026-03-22 10:30:15+00
#  3 | 003_add_email_verification.sql| 2026-03-21 15:20:10+00
#  2 | 002_fix_features.sql         | 2026-03-20 12:10:05+00
#  1 | 001_subscription_system.sql  | 2026-03-20 12:10:00+00

Rollback-Strategie

Automatischer Rollback: Nicht implementiert

Manueller Rollback:

  1. Identifizieren der problematischen Migration:

    docker logs dev-mitai-api | grep "Failed to apply"
    
  2. Migration aus Tracking entfernen:

    DELETE FROM schema_migrations
    WHERE filename = '004_broken_migration.sql';
    
  3. Änderungen manuell rückgängig machen:

    -- Beispiel: Spalte entfernen
    ALTER TABLE profiles DROP COLUMN new_feature_enabled;
    
  4. Migration-Datei korrigieren

    vim backend/migrations/004_broken_migration.sql
    
  5. Container neu starten (Migration wird erneut ausgeführt)

    docker compose restart api
    

Best Practices

DO

  • Immer IF NOT EXISTS / IF EXISTS verwenden:

    ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email_verified BOOLEAN;
    CREATE INDEX IF NOT EXISTS idx_profiles_email ON profiles(email);
    
  • Idempotente Migrationen schreiben: Migration kann mehrfach ausgeführt werden ohne Fehler

  • Daten-Migrationen mit Bedacht:

    UPDATE profiles
    SET email_verified = TRUE
    WHERE email IS NOT NULL AND email_verified IS NULL;
    
  • Kommentare für Dokumentation:

    COMMENT ON COLUMN profiles.email_verified IS 'Whether email has been verified';
    
  • Indices für Performance:

    CREATE INDEX IF NOT EXISTS idx_profiles_verification_token
    ON profiles(verification_token)
    WHERE verification_token IS NOT NULL;  -- Partial index
    

DON'T

  • Keine psql Meta-Kommandos:

    \echo "Starting migration"  -- ❌ Funktioniert nicht
    SELECT 'Starting migration';  -- ✅ Funktioniert
    
  • Keine Breaking Changes ohne Staging:

    ALTER TABLE profiles DROP COLUMN tier;  -- ❌ App wird brechen
    
  • Keine Hardcoded Values für produktive Daten:

    INSERT INTO profiles (id, email, ...) VALUES (1, 'admin@example.com', ...);  -- ❌
    
  • Keine Foreign Keys ohne Fallback:

    -- ❌ Ohne ON DELETE Behavior
    ALTER TABLE subscriptions
    ADD CONSTRAINT fk_profile FOREIGN KEY (profile_id) REFERENCES profiles(id);
    
    -- ✅ Mit Cascade
    ALTER TABLE subscriptions
    ADD CONSTRAINT fk_profile FOREIGN KEY (profile_id)
    REFERENCES profiles(id) ON DELETE CASCADE;
    

Troubleshooting

Migration schlägt fehl

Symptom: Container startet nicht, Logs zeigen ✗ Failed to apply XXX.sql

Lösung:

  1. Logs prüfen: docker logs dev-mitai-api | tail -50
  2. Fehlerhafte Migration identifizieren
  3. Aus Tracking entfernen + Schema manuell korrigieren
  4. Migration-Datei fixen
  5. Container neu starten

Migration wurde nicht angewendet

Symptom: Neue Migration-Datei wird ignoriert

Ursachen:

  • Datei entspricht nicht dem Pattern \d{3}_*.sql
  • Datei wurde bereits in schema_migrations getrackt
  • Datei ist nicht im Container (backend/migrations/ Volume gemountet?)

Lösung:

# Prüfen ob Datei gemountet ist
docker exec -it dev-mitai-api ls -la /app/migrations/

# Prüfen ob bereits getrackt
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
  -c "SELECT * FROM schema_migrations WHERE filename = '004_feature.sql';"

# Falls fälschlich getrackt, entfernen
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
  -c "DELETE FROM schema_migrations WHERE filename = '004_feature.sql';"

# Container neu starten
docker compose restart api

Datenbank-Schema inkonsistent

Symptom: schema_migrations zeigt Migration als angewendet, aber Änderungen fehlen

Ursachen:

  • Migration wurde manuell ausgeführt, aber Tracking war kaputt
  • Datenbank wurde zurückgesetzt, aber Tracking-Tabelle nicht

Lösung:

# Schema neu aufbauen (ACHTUNG: Datenverlust!)
docker compose down -v  # Löscht Volumes
docker compose up -d    # Baut alles neu auf

# ODER: Tracking-Tabelle manuell korrigieren
docker exec -it dev-mitai-db psql -U mitai_dev -d mitai_dev \
  -c "TRUNCATE schema_migrations; -- Alle Tracking-Einträge löschen"

# Container neu starten → Alle Migrationen werden erneut angewendet
docker compose restart api

Migrations-Historie

Nr. Datei Version Datum Beschreibung
003 003_add_email_verification.sql v9c 2026-03-21 Email-Verifizierung (verification_token, email_verified, verification_expires)
002 002_fix_features.sql (manuell) v9c 2026-03-20 Feature-System Fixes
001 001_subscription_system.sql (manuell) v9c 2026-03-20 Membership-System (tiers, subscriptions, coupons, access_grants)

Hinweis: Migrationen 001 und 002 wurden vor Einführung des automatischen Systems manuell angewendet und sind nicht nummeriert. Ab Migration 003 läuft alles automatisch.


Referenzen

  • Code: backend/db_init.py (Zeilen 94-200)
  • Migrations-Ordner: backend/migrations/
  • Tracking-Tabelle: schema_migrations
  • Startup-Script: backend/startup.sh (ruft db_init.py auf)
  • Dokumentation: .claude/docs/technical/MIGRATIONS.md (diese Datei)

Dokumentiert: 2026-03-21 Letzte Änderung: 2026-03-21