From cc37e7ac6b7d8e34defbc4b74fc0e09e37d19d12 Mon Sep 17 00:00:00 2001 From: TeamVis Release Date: Fri, 26 Jun 2026 11:15:12 +0200 Subject: [PATCH] TeamVis Self-Host-Bundle v0.32.0 --- README.md | 11 ++++ deploy/selfhost/update.sh | 112 ++++++++++++++++++++++++++++++++++++++ docs/NEUKUNDE.md | 15 ++++- 3 files changed, 135 insertions(+), 3 deletions(-) create mode 100755 deploy/selfhost/update.sh diff --git a/README.md b/README.md index c41feaf..a72361e 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,17 @@ docker login git.zfx.services # Benutzer: teamvis-pull · Passwort: &2; exit 1; } + +BUNDLE="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$BUNDLE" +[ -d .git ] || die "Kein git-Repo in $BUNDLE — Updates laufen über 'git pull'. Bitte das Bundle per 'git clone' beziehen." +command -v docker >/dev/null || die "docker fehlt." + +# ── Instanz-Verzeichnis bestimmen (enthält docker-compose.yml + .env) ── +INSTANCE="${1:-}" +if [ -z "$INSTANCE" ]; then + mapfile -t cands < <( + for d in "$BUNDLE"/*/; do + [ -f "${d}docker-compose.yml" ] && [ -f "${d}.env" ] && printf '%s\n' "${d%/}" + done + ) + if [ "${#cands[@]}" -eq 1 ]; then + INSTANCE="${cands[0]}" + elif [ "${#cands[@]}" -eq 0 ]; then + die "Kein Instanz-Verzeichnis gefunden. Bitte als Argument angeben: bash deploy/selfhost/update.sh " + else + say "Mehrere Instanzen gefunden:"; printf ' %s\n' "${cands[@]}" + die "Bitte das gewünschte Verzeichnis als Argument angeben." + fi +fi +[ -f "$INSTANCE/docker-compose.yml" ] || die "In $INSTANCE liegt keine docker-compose.yml." +ok "Instanz: $INSTANCE" + +# Modus erkennen: eigener db-Service (Modus 2) oder externe Supabase (Modus 1). +MODE2=0 +grep -qE '^[[:space:]]+db:' "$INSTANCE/docker-compose.yml" && MODE2=1 + +POSTGRES_DB="$(grep -E '^POSTGRES_DB=' "$INSTANCE/.env" 2>/dev/null | cut -d= -f2- || true)" +POSTGRES_DB="${POSTGRES_DB:-postgres}" +PGPW="$(grep -E '^POSTGRES_PASSWORD=' "$INSTANCE/.env" 2>/dev/null | cut -d= -f2- || true)" +dbsql() { ( cd "$INSTANCE" && docker compose exec -T -e PGPASSWORD="$PGPW" db psql -v ON_ERROR_STOP=1 -U supabase_admin -d "$POSTGRES_DB" "$@" ); } + +# ── 1. Pre-Update-Backup (nur Modus 2 — lokale DB) ──────────────────── +if [ "$MODE2" = "1" ]; then + head "1) Datenbank-Backup" + ts="$(date +%Y%m%d-%H%M%S)" + dump="$INSTANCE/backup-db-$ts.sql" + if ( cd "$INSTANCE" && docker compose exec -T -e PGPASSWORD="$PGPW" db pg_dump -U supabase_admin "$POSTGRES_DB" ) > "$dump" 2>/dev/null; then + ok "Backup: $dump ($(wc -l < "$dump") Zeilen)" + else + warn "Backup fehlgeschlagen — trotzdem fortfahren? (Strg-C zum Abbrechen)"; read -r _ || true + fi +else + warn "Externe Supabase (Modus 1): Backup macht dein Supabase-Anbieter. Kein lokaler Dump." +fi + +# ── 2. git pull → neue Migrationen/Skripte ──────────────────────────── +head "2) Bundle aktualisieren (git pull)" +OLD="$(git rev-parse HEAD)" +git pull --ff-only origin main || die "git pull fehlgeschlagen (abweichende Branches?). Notfalls: git fetch && git reset --hard origin/main" +NEW="$(git rev-parse HEAD)" +if [ "$OLD" = "$NEW" ]; then + ok "Schon aktuell (keine neuen Commits)." +else + ok "Aktualisiert: ${OLD:0:8} → ${NEW:0:8}" +fi + +# ── 3. NUR neue Migrationen einspielen ──────────────────────────────── +head "3) Neue Migrationen" +mapfile -t NEWMIG < <(git diff --diff-filter=A --name-only "$OLD" "$NEW" -- 'supabase/migrations/*.sql' 2>/dev/null | sort) +if [ "${#NEWMIG[@]}" -eq 0 ]; then + ok "Keine neuen Migrationen." +elif [ "$MODE2" = "1" ]; then + for m in "${NEWMIG[@]}"; do + say "→ $m" + dbsql < "$BUNDLE/$m" + done + ok "${#NEWMIG[@]} Migration(en) eingespielt." +else + warn "Externe Supabase: bitte diese neuen Migrationen EINMAL in Supabase Studio (SQL-Editor) ausführen:" + for m in "${NEWMIG[@]}"; do say " $BUNDLE/$m"; done + read -r -p " Enter drücken, sobald sie eingespielt sind … " _ || true +fi + +# ── 4. Neues Image ziehen + Container neu starten ───────────────────── +head "4) App aktualisieren" +( cd "$INSTANCE" && docker compose pull && docker compose up -d ) +ok "Container neu gestartet." + +head "Fertig 🎉" +SITE_URL="$(grep -E '^SITE_URL=|^NEXT_PUBLIC_SITE_URL=' "$INSTANCE/.env" 2>/dev/null | head -1 | cut -d= -f2-)" +[ -n "$SITE_URL" ] && say " $SITE_URL" +say " Bei Problemen Logs prüfen: ( cd $INSTANCE && docker compose logs -f app )" diff --git a/docs/NEUKUNDE.md b/docs/NEUKUNDE.md index 8b42e50..e8d5040 100644 --- a/docs/NEUKUNDE.md +++ b/docs/NEUKUNDE.md @@ -216,12 +216,21 @@ Patch + Minor sind DB-rückwärtskompatibel (altes Image läuft mit neuer DB). Image-Tag in Production **immer pinnen** (`teamvis:0.11.6`), nicht `:latest` — sonst zieht ein `compose pull` ungewollt einen Major-Sprung. -**Standard-Update:** +**Standard-Update (Self-Host-Bundle, empfohlen):** +```bash +# Im Bundle-Verzeichnis (teamvis-selfhost) — erledigt Backup, neue Migrationen +# (nur die NEUEN, git als Ledger) und Image-Update in einem Schritt: +bash deploy/selfhost/update.sh +``` +> Wichtig: Updates **immer** über `update.sh` — nicht selbst `git pull`, sonst +> können Migrationen übersprungen werden. + +**Manuell (externe Supabase ohne psql-Zugang / Sonderfall):** ```bash # 1. Backup (siehe Abschnitt 8) # 2. Release-Notes / CHANGELOG.md prüfen -# 3. fehlende Migration(en) aus supabase/migrations/ einspielen (nur die neuen!) -# 4. Tag im docker-compose.yml bumpen +# 3. NEUE Migration(en) aus supabase/migrations/ in Supabase Studio einspielen +# 4. Image-Tag aktualisieren docker compose pull && docker compose up -d --force-recreate ```