TeamVis Self-Host-Bundle v0.56.2

This commit is contained in:
TeamVis Release committed 2026-10-10 23:39:23 +02:00
1 parent f53579d3a4
commit 6da3cc2283
11 files changed
+432 -30

No files matched your search

+64 -18
View File
@@ -5,13 +5,21 @@
# Aktualisiert eine bestehende Instanz in einem Rutsch:
# 1. Pre-Update-Backup der Datenbank (Modus 2)
# 2. `git pull` im Bundle → neue Migrationen + Skripte
# 3. NUR die NEU hinzugekommenen Migrationen einspielen (git als Ledger:
# welche Dateien seit dem letzten Stand dazukamen)
# 3. Fehlende Migrationen einspielen — jede in EINER Transaktion zusammen
# mit ihrem Eintrag in public.teamvis_schema_migrations (Modus 2)
# 4. neues App-Image ziehen + Container neu starten
#
# Warum git als Ledger? Die Migrationen sind append-only. `git diff` zwischen
# altem und neuem Stand liefert exakt die neuen Migrationsdateien — kein
# separater DB-Tracker nötig, kein erneutes Ausführen alter Migrationen.
# Warum ein Ledger in der DB? Früher diente `git diff OLD NEW` als Ledger.
# Schlug dabei eine Migration fehl, war HEAD trotzdem schon vorgerückt — der
# nächste Lauf meldete „keine neuen Migrationen", die restlichen fehlten
# dauerhaft, und eine halb angewendete Migration blieb unbemerkt (Review
# 04.10.2026). Jetzt gilt: eingespielt ist, was in der Tabelle steht; eine
# fehlgeschlagene Migration rollt komplett zurück und wird beim nächsten
# Lauf erneut versucht.
#
# Bestandsinstanzen ohne Tabelle: Beim ersten Lauf wird sie angelegt und mit
# allen Migrationen des Stands VOR dem Pull befüllt — genau die galten nach
# der alten Logik als eingespielt.
#
# Aufruf: bash deploy/selfhost/update.sh [instanz-verzeichnis]
# (ohne Argument: das Instanz-Verzeichnis wird automatisch erkannt, wenn
@@ -64,6 +72,9 @@ if [ "$MODE2" = "1" ]; then
head "1) Datenbank-Backup"
ts="$(date +%Y%m%d-%H%M%S)"
dump="$INSTANCE/backup-db-$ts.sql"
# Der Dump enthält alle Personendaten — nur für den Eigentümer lesbar
# anlegen (vorher landete er mit 644 im Instanz-Verzeichnis).
install -m 600 /dev/null "$dump"
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
@@ -84,21 +95,56 @@ 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"
# ── 3. Fehlende Migrationen einspielen ────────────────────────────────
head "3) Migrationen"
if [ "$MODE2" = "1" ]; then
LEDGER="public.teamvis_schema_migrations"
if [ "$(dbsql -tAc "select to_regclass('$LEDGER') is not null")" != "t" ]; then
say "Migrations-Ledger fehlt — wird angelegt und mit dem bisherigen Stand (${OLD:0:8}) befüllt."
{
echo "begin;"
echo "create table $LEDGER (filename text primary key, applied_at timestamptz not null default now());"
echo "revoke all on $LEDGER from anon, authenticated;"
git ls-tree --name-only "$OLD" -- supabase/migrations/ | grep -E '\.sql$' | sort \
| sed -E "s#^supabase/migrations/(.*)\$#insert into $LEDGER (filename) values ('\\1');#"
echo "commit;"
} | dbsql >/dev/null
ok "Ledger angelegt ($(dbsql -tAc "select count(*) from $LEDGER") Einträge)."
fi
mapfile -t APPLIED < <(dbsql -tAc "select filename from $LEDGER")
declare -A DONE=()
for f in "${APPLIED[@]}"; do [ -n "$f" ] && DONE["$f"]=1; done
PENDING=()
for m in $(ls supabase/migrations/*.sql | sort); do
[ -z "${DONE[$(basename "$m")]:-}" ] && PENDING+=("$m")
done
ok "${#NEWMIG[@]} Migration(en) eingespielt."
if [ "${#PENDING[@]}" -eq 0 ]; then
ok "Keine offenen Migrationen."
else
for m in "${PENDING[@]}"; do
name="$(basename "$m")"
say "→ $name"
# Migration + Ledger-Eintrag atomar: scheitert die Migration, bleibt
# weder ein halber Schema-Stand noch ein Eintrag zurück.
{ cat "$BUNDLE/$m"; printf "\ninsert into %s (filename) values ('%s');\n" "$LEDGER" "$name"; } \
| dbsql --single-transaction >/dev/null \
|| die "Migration $name fehlgeschlagen und vollständig zurückgerollt. Fehler beheben und update.sh erneut starten — bereits eingespielte Migrationen bleiben erhalten, die App wurde NICHT aktualisiert."
done
ok "${#PENDING[@]} Migration(en) eingespielt."
fi
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
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 in diesem Update."
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
warn "Schlägt eine fehl: nicht weitermachen, sondern Fehler beheben — update.sh zeigt sie beim nächsten Lauf NICHT erneut an."
read -r -p " Enter drücken, sobald sie eingespielt sind … " _ || true
fi
fi
# ── 4. Neues Image ziehen + Container neu starten ─────────────────────