253 lines
6.9 KiB
Markdown
253 lines
6.9 KiB
Markdown
# 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.
|