# CheckPoint Ehrenamt — Updates & Datensicherung

> Vier Stufen von Änderungen · Backup-Strategie · Stand: Juni 2026

---

## Grundregel (immer)

**Vor jedem Update: Backup ziehen.** Kein Update ohne Backup — egal wie klein die
Änderung scheint.

---

## Backup manuell auslösen

```bash
docker exec checkpoint python3 -c "
import sqlite3
src = sqlite3.connect('/app/instance/checkpoint.sqlite')
dst = sqlite3.connect('/app/instance/latest-backup.sqlite')
src.backup(dst)
dst.close()
src.close()
"
```

Warum nicht einfach `cp`? SQLite schreibt in mehreren Schritten (WAL-Modus). Ein
roher Datei-Copy kann die Datenbank mitten in einem Schreibvorgang erwischen und
ein korruptes Backup erzeugen. `connection.backup()` macht einen konsistenten
Online-Snapshot — auch bei laufendem Betrieb sicher.

Backup prüfen:
```bash
docker exec checkpoint ls -lh /app/instance/
```

---

## Automatisches tägliches Backup (Cronjob)

Läuft täglich um 03:30 UTC auf dem VPS:

```
30 03 * * * docker exec checkpoint python3 -c "import sqlite3; src=sqlite3.connect('/app/instance/checkpoint.sqlite'); dst=sqlite3.connect('/app/instance/latest-backup.sqlite'); src.backup(dst); dst.close(); src.close()"
```

Cronjob anzeigen: `crontab -l`
Cronjob bearbeiten: `crontab -e`

**Wichtig:** Das Backup liegt im Docker-Volume auf dem VPS. Wenn der VPS ausfällt,
ist auch das Backup weg. Deshalb zusätzlich Ebene 3 (siehe unten).

---

## Backup vom VPS runterkopieren (Ebene 3)

Auf dem lokalen Rechner:

```bash
scp patsy@<vps-ip>:/var/lib/docker/volumes/checkpoint_checkpoint_data/_data/latest-backup.sqlite ./checkpoint-backup-$(date +%Y%m%d).sqlite
```

Mindestens einmal pro Woche, immer vor größeren Updates (Stufe 3 + 4).

---

## Die vier Update-Stufen

---

### Stufe 1 — Statische Dateien (CSS, JS, Bilder)

**Beispiele:** Farbe ändern, Button-Stil anpassen, Token-Werte in `tokens.css`.

**Risiko:** keines für die Daten.

**Vorgehen:**

```bash
# 1. Backup (Pflicht, auch hier)
docker exec checkpoint python3 -c "import sqlite3; src=sqlite3.connect('/app/instance/checkpoint.sqlite'); dst=sqlite3.connect('/app/instance/latest-backup.sqlite'); src.backup(dst); dst.close(); src.close()"

# 2. Code holen
cd ~/apps/checkpoint
git pull

# 3. Image neu bauen und Container ersetzen
cd ~/stacks/checkpoint
docker compose build
docker compose up -d

# 4. Logs prüfen
docker logs checkpoint --tail 50

# 5. App im Browser aufrufen und prüfen
```

---

### Stufe 2 — Python-Code, Routen, Templates (keine DB-Änderung)

**Beispiele:** Bugfix in einer Route, neues Template, geänderte Business-Logik,
neue Blueprint-Route.

**Risiko:** keines für die Daten. Aber: fehlerhafter Code kann die App down bringen.
Lokal testen bevor pushen.

**Vorgehen:** identisch mit Stufe 1.

`db.create_all()` läuft beim Container-Start automatisch — bei unverändertem
Datenmodell macht es nichts.

---

### Stufe 3 — Neue Tabelle oder neue Spalte (additiv)

**Beispiele:** Neues Modell hinzufügen, optionale Spalte ergänzen.

**Risiko:** mittel. `db.create_all()` legt neue Tabellen automatisch an, ändert
aber **bestehende Tabellen nicht**. Neue Spalte vergessen → App crasht beim ersten
Zugriff auf das Feld.

**Vorgehen:**

```bash
# 1. Backup ziehen (und lokal runterkopieren)
docker exec checkpoint python3 -c "import sqlite3; src=sqlite3.connect('/app/instance/checkpoint.sqlite'); dst=sqlite3.connect('/app/instance/latest-backup.sqlite'); src.backup(dst); dst.close(); src.close()"

# 2. Code holen, bauen, starten
cd ~/apps/checkpoint && git pull
cd ~/stacks/checkpoint && docker compose build && docker compose up -d

# 3. Neue Spalte manuell ergänzen (Beispiel)
docker exec -it checkpoint python3 -c "
import sqlite3
con = sqlite3.connect('/app/instance/checkpoint.sqlite')
con.execute('ALTER TABLE user ADD COLUMN telefon TEXT')
con.commit()
con.close()
"

# 4. Logs prüfen
docker logs checkpoint --tail 50

# 5. App testen — besonders die betroffenen Bereiche
```

Neue Tabellen (komplett neue Modelle) werden von `db.create_all()` automatisch
angelegt — kein manueller Schritt nötig.

---

### Stufe 4 — Schema-Änderung an bestehenden Tabellen

**Beispiele:** Spalte umbenennen, Datentyp ändern, Tabelle umstrukturieren,
Spalte löschen.

**Risiko:** hoch. SQLite unterstützt viele `ALTER TABLE`-Operationen nicht nativ.
Niemals ohne Backup und ohne vorherige Absprache durchführen.

**Vorgehen:**

```bash
# 1. Backup ziehen UND lokal runterkopieren (Pflicht)
docker exec checkpoint python3 -c "import sqlite3; src=sqlite3.connect('/app/instance/checkpoint.sqlite'); dst=sqlite3.connect('/app/instance/latest-backup.sqlite'); src.backup(dst); dst.close(); src.close()"

scp patsy@<vps-ip>:/var/lib/docker/volumes/checkpoint_checkpoint_data/_data/latest-backup.sqlite ./checkpoint-backup-$(date +%Y%m%d).sqlite

# 2. Migrationsstrategie mit Claude besprechen bevor Code angefasst wird

# 3. Lokal testen mit einer Kopie der echten DB

# 4. Erst dann: Code holen, bauen, starten
cd ~/apps/checkpoint && git pull
cd ~/stacks/checkpoint && docker compose build && docker compose up -d

# 5. Migration manuell ausführen (Strategie je nach Änderung)

# 6. Intensiv testen
```

**SQLite-Einschränkung:** Spalten umbenennen geht ab SQLite 3.25+, Spalten löschen
ab 3.35+. Datentyp ändern oder komplexe Umstrukturierungen erfordern die
„Tabelle neu bauen"-Strategie:
1. Neue Tabelle mit korrekter Struktur anlegen
2. Daten rüber kopieren
3. Alte Tabelle löschen
4. Neue Tabelle umbenennen

Bei Stufe 4 immer erst besprechen, nie blind durchführen.

---

## Update-Checkliste (für jedes Update)

```
Vor dem Update
  □ Backup manuell ausgelöst
  □ Backup-Datei im Volume vorhanden (ls -lh prüfen)
  □ Bei Stufe 3/4: Backup lokal runtergeladen

Update
  □ git pull
  □ docker compose build
  □ docker compose up -d

Nach dem Update
  □ docker logs checkpoint --tail 50  — keine Fehler?
  □ App im Browser aufgerufen — lädt sie?
  □ Login funktioniert?
  □ Bei Stufe 3: ALTER TABLE ausgeführt?
  □ Betroffene Funktion manuell getestet?
```

---

## Rollback (wenn etwas schiefgeht)

```bash
# 1. Letzten funktionierenden Commit finden
cd ~/apps/checkpoint
git log --oneline -10

# 2. Auf diesen Commit zurückgehen
git checkout <commit-hash>

# 3. Image neu bauen und starten
cd ~/stacks/checkpoint
docker compose build
docker compose up -d

# 4. Bei DB-Schaden: Backup wiederherstellen
docker exec checkpoint python3 -c "
import sqlite3
src = sqlite3.connect('/app/instance/latest-backup.sqlite')
dst = sqlite3.connect('/app/instance/checkpoint.sqlite')
src.backup(dst)
dst.close()
src.close()
"
```

---

## Drei Backup-Ebenen im Überblick

| Ebene | Was | Wie oft | Wo |
|---|---|---|---|
| 1 | Manuell vor jedem Update | Bei jedem Update | Docker Volume (VPS) |
| 2 | Automatischer Cronjob | Täglich 03:30 UTC | Docker Volume (VPS) |
| 3 | Lokale Kopie | Mindestens wöchentlich | Eigener Rechner |

Ebene 3 ist die wichtigste — nur ein Backup außerhalb des VPS ist ein echtes Backup.
