- .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
393 lines
11 KiB
Markdown
393 lines
11 KiB
Markdown
# 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`
|
|
```sql
|
|
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:
|
|
|
|
```sql
|
|
-- ================================================================
|
|
-- 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:
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```sql
|
|
-- ================================================================
|
|
-- 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
docker logs dev-mitai-api | grep "Failed to apply"
|
|
```
|
|
|
|
2. **Migration aus Tracking entfernen:**
|
|
```sql
|
|
DELETE FROM schema_migrations
|
|
WHERE filename = '004_broken_migration.sql';
|
|
```
|
|
|
|
3. **Änderungen manuell rückgängig machen:**
|
|
```sql
|
|
-- Beispiel: Spalte entfernen
|
|
ALTER TABLE profiles DROP COLUMN new_feature_enabled;
|
|
```
|
|
|
|
4. **Migration-Datei korrigieren**
|
|
```bash
|
|
vim backend/migrations/004_broken_migration.sql
|
|
```
|
|
|
|
5. **Container neu starten** (Migration wird erneut ausgeführt)
|
|
```bash
|
|
docker compose restart api
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### ✅ DO
|
|
|
|
- **Immer `IF NOT EXISTS` / `IF EXISTS` verwenden:**
|
|
```sql
|
|
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:**
|
|
```sql
|
|
UPDATE profiles
|
|
SET email_verified = TRUE
|
|
WHERE email IS NOT NULL AND email_verified IS NULL;
|
|
```
|
|
|
|
- **Kommentare für Dokumentation:**
|
|
```sql
|
|
COMMENT ON COLUMN profiles.email_verified IS 'Whether email has been verified';
|
|
```
|
|
|
|
- **Indices für Performance:**
|
|
```sql
|
|
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:**
|
|
```sql
|
|
\echo "Starting migration" -- ❌ Funktioniert nicht
|
|
SELECT 'Starting migration'; -- ✅ Funktioniert
|
|
```
|
|
|
|
- **Keine Breaking Changes ohne Staging:**
|
|
```sql
|
|
ALTER TABLE profiles DROP COLUMN tier; -- ❌ App wird brechen
|
|
```
|
|
|
|
- **Keine Hardcoded Values für produktive Daten:**
|
|
```sql
|
|
INSERT INTO profiles (id, email, ...) VALUES (1, 'admin@example.com', ...); -- ❌
|
|
```
|
|
|
|
- **Keine Foreign Keys ohne Fallback:**
|
|
```sql
|
|
-- ❌ 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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
|