#!/bin/bash # Deploy DB zum VServer # Usage: ./scripts/deploy-db.sh [--dry-run] [--migrate-only] [--skip-migrate] # # Modes: # (default) Upload DB + run migrations + restart container # --dry-run Nur anzeigen, nichts ändern # --migrate-only Nur Migrationen auf Remote-DB ausführen (kein Upload) # --skip-migrate DB hochladen, aber keine Migrationen # # Migrationen: FTS5, Strang, Fristen set -euo pipefail LOCAL_DB="data/tracker.db" REMOTE_DB="/opt/antragstracker/data/tracker.db" REMOTE_HOST="vserver" CONTAINER="antragstracker-hagen" DRY_RUN=false MIGRATE_ONLY=false SKIP_MIGRATE=false for arg in "$@"; do case $arg in --dry-run) DRY_RUN=true ;; --migrate-only) MIGRATE_ONLY=true ;; --skip-migrate) SKIP_MIGRATE=true ;; -h|--help) echo "Usage: $0 [--dry-run] [--migrate-only] [--skip-migrate]" exit 0 ;; *) echo "Unknown arg: $arg"; exit 1 ;; esac done cd "$(dirname "$0")/.." echo "=== DB Deploy ===" # --- Schema-Validierung (nur bei Upload) --- if [ "$MIGRATE_ONLY" = false ]; then # Fallback zu tracker_remote.db wenn tracker.db nicht existiert if [ ! -f "$LOCAL_DB" ]; then if [ -f "data/tracker_remote.db" ]; then LOCAL_DB="data/tracker_remote.db" echo " → Nutze data/tracker_remote.db" else echo "❌ Keine lokale DB gefunden (data/tracker.db oder data/tracker_remote.db)" exit 1 fi fi echo "Lokale DB: $(du -sh $LOCAL_DB | cut -f1)" echo "Schema prüfen..." EXPECTED_TABLES="vorlagen beratungen ketten ketten_glieder ki_bewertungen parteien antragsteller gremien orte referenzen" MISSING="" for tbl in $EXPECTED_TABLES; do EXISTS=$(sqlite3 "$LOCAL_DB" "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='$tbl'" 2>/dev/null) if [ "$EXISTS" != "1" ]; then MISSING="$MISSING $tbl" fi done if [ -n "$MISSING" ]; then echo "❌ Fehlende Tabellen:$MISSING" exit 1 fi echo " ✓ Alle Tabellen vorhanden" # Stats echo "" echo " Vorlagen: $(sqlite3 "$LOCAL_DB" 'SELECT COUNT(*) FROM vorlagen')" echo " Ketten: $(sqlite3 "$LOCAL_DB" 'SELECT COUNT(*) FROM ketten')" echo " KI-Bew.: $(sqlite3 "$LOCAL_DB" 'SELECT COUNT(*) FROM ki_bewertungen')" echo " Orte: $(sqlite3 "$LOCAL_DB" 'SELECT COUNT(*) FROM orte WHERE lat IS NOT NULL')" echo "" # Flush WAL journal echo " WAL flushen..." sqlite3 "$LOCAL_DB" "PRAGMA wal_checkpoint(TRUNCATE)" 2>/dev/null fi if [ "$DRY_RUN" = true ]; then echo "" echo "🔍 DRY RUN" if [ "$MIGRATE_ONLY" = false ]; then echo " Würde hochladen: $(du -sh $LOCAL_DB | cut -f1) nach $REMOTE_HOST:$REMOTE_DB" echo " Prod-DB: $(ssh $REMOTE_HOST "du -sh $REMOTE_DB 2>/dev/null | cut -f1" || echo "N/A")" fi if [ "$SKIP_MIGRATE" = false ]; then echo " Migrationen: FTS5, Strang, Fristen" fi echo "" echo "DRY RUN fertig." exit 0 fi # --- Upload --- if [ "$MIGRATE_ONLY" = false ]; then # Backup auf VServer BACKUP_NAME="${REMOTE_DB}.bak-$(date +%Y%m%d-%H%M)" echo "1. Backup Prod-DB..." ssh $REMOTE_HOST "cp $REMOTE_DB $BACKUP_NAME 2>/dev/null || echo ' (keine bestehende DB)'" echo " → $BACKUP_NAME" # Container stoppen für sicheren DB-Write echo "2. Container stoppen..." ssh $REMOTE_HOST "cd /opt/antragstracker && docker compose stop antragstracker" 2>&1 | grep -v "level=warning" || true echo "3. Upload..." scp "$LOCAL_DB" "$REMOTE_HOST:$REMOTE_DB" echo " ✓ Upload fertig" fi # --- Migrationen --- if [ "$SKIP_MIGRATE" = false ]; then echo "4. Migrationen ausführen..." # Migrationen im Docker-Container auf dem VServer ssh $REMOTE_HOST "cd /opt/antragstracker && docker compose run --rm --no-deps antragstracker python scripts/migrate_fts5.py /app/data/tracker.db" 2>&1 | grep -v "level=warning" || true echo " ✓ FTS5" ssh $REMOTE_HOST "cd /opt/antragstracker && docker compose run --rm --no-deps antragstracker python scripts/migrate_strang.py" 2>&1 | grep -v "level=warning" || true echo " ✓ Strang" ssh $REMOTE_HOST "cd /opt/antragstracker && docker compose run --rm --no-deps antragstracker python scripts/migrate_fristen.py" 2>&1 | grep -v "level=warning" || true echo " ✓ Fristen" fi # --- Container starten --- echo "5. Container starten..." ssh $REMOTE_HOST "cd /opt/antragstracker && docker compose up -d" 2>&1 | grep -v "level=warning" || true # --- Health-Check --- sleep 5 HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://antraege.toppyr.de/api/health" 2>/dev/null || echo "000") if [ "$HTTP_STATUS" = "200" ]; then echo " ✓ Health-Check OK" else echo " ⚠️ Health-Check: HTTP $HTTP_STATUS" fi echo "" echo "✅ DB-Deploy fertig" if [ "$MIGRATE_ONLY" = false ]; then echo "Backup: $BACKUP_NAME" echo "Rollback: ssh $REMOTE_HOST 'cp $BACKUP_NAME $REMOTE_DB && cd /opt/antragstracker && docker compose restart antragstracker'" fi