Guard against missing Mail-Graveyard DB

This commit is contained in:
DonVoo 2026-07-14 19:24:50 +02:00
parent d4d43fe672
commit 29208b7a41
4 changed files with 127 additions and 3 deletions

94
db-rename-brief.md Normal file
View file

@ -0,0 +1,94 @@
# Codex-Brief — DB-Namen-Altlast beseitigen (stiller Daten-GAU)
**Priorität: vor der ersten echten `@dr-gold.de`-Migration.** Das ist kein
Kosmetikproblem.
## Der Befund
| Stelle | `db_path` |
|---|---|
| `config.json.example` | `mail-graveyard.db` |
| `INSTALL.md` (`cp config.json.example config.json`) | → `mail-graveyard.db` |
| Code-Default in `ConnectDB` (02-database.go) | `mail-graveyard.db` |
| **LIVE auf GoldPi** | **`/app/data/emailforwarder.db`** ← hier liegen die echten Daten |
Im `data/`-Verzeichnis liegen aktuell:
```
emailforwarder.db 380.928 <- die ECHTEN Daten
emailforwarder.db-wal 4.124.152 <- ACHTUNG: groesser als die DB selbst!
emailforwarder.db-shm 32.768
mail-graveyard.db 0 <- Leiche
email-forwarder.db 0 <- Leiche
```
**Der Schaden, wenn der Default je greift** (jemand folgt der eigenen
INSTALL.md, oder `db_path` fehlt in einer Config): SQLite legt klaglos eine
**frische, leere DB** an. Konten weg, `copied`-Historie weg. Der Watcher sieht
eine leere `copied`-Tabelle und **kopiert jede Mail erneut in die
Ziel-Postfaecher** → **Dubletten quer ueber alle ~20 echten dr-gold-Postfaecher**,
lautlos, ohne einen einzigen Fehler im Log.
## Teil A — Die Daten umziehen (einmalige Ops-Aktion)
**Ist-Zustand als Baseline (muss danach identisch sein; Stand vor Codex-Umzug):**
`accounts=19`, `copied=215`, `app_users=3`, `jobs=294`
Reihenfolge ist wichtig — **das WAL ist der gefaehrliche Teil**:
```sh
APP=/mnt/DATA/Containers/Test-Container/Mail-Graveyard-Pod
D=$APP/data
# 1. BEIDE Container stoppen -> kein Schreiber mehr auf der DB
podman stop mail-graveyard mail-graveyard-watch
# 2. Backup, bevor irgendwas angefasst wird (inkl. WAL/SHM!)
cp -a $D/emailforwarder.db $D/BACKUP-emailforwarder.db
cp -a $D/emailforwarder.db-wal $D/BACKUP-emailforwarder.db-wal
# 3. WAL in die Haupt-DB falten. OHNE DAS gehen 4 MB Daten verloren.
sqlite3 $D/emailforwarder.db "PRAGMA wal_checkpoint(TRUNCATE);"
# 4. Gegenpruefen, dass alles noch da ist
sqlite3 $D/emailforwarder.db "SELECT
(SELECT COUNT(*) FROM accounts), (SELECT COUNT(*) FROM copied),
(SELECT COUNT(*) FROM app_users), (SELECT COUNT(*) FROM jobs);"
# -> MUSS 19|215|3|294 liefern. Wenn nicht: STOPP, nichts weiter tun.
# 5. Erst jetzt umbenennen (ueberschreibt die 0-Byte-Leiche)
mv -f $D/emailforwarder.db $D/mail-graveyard.db
rm -f $D/emailforwarder.db-wal $D/emailforwarder.db-shm $D/email-forwarder.db
# 6. Config umstellen
# $APP/config.json: "db_path": "/app/data/mail-graveyard.db"
```
## Teil B — Die Ursache beseitigen (Code + Repo)
1. `deploy/goldpi-test-container/mail-graveyard-pod/config.json` **und**
`config.json.example`: `db_path` auf `mail-graveyard.db` — damit Doku, Deploy
und Live endlich dasselbe sagen.
2. **Kein stilles Anlegen mehr.** Das ist die eigentliche Wurzel: `ConnectDB`
erzeugt heute klaglos eine leere DB, wenn die Datei fehlt. Bau eine
Sicherung ein:
- Wenn die DB-Datei **nicht existiert**, nur dann anlegen, wenn explizit
`--init-db` uebergeben wurde. Sonst: **laut scheitern** mit
`DB %q existiert nicht — mit --init-db neu anlegen oder db_path pruefen`
und Exit ≠ 0.
- Damit wird aus einem stillen Daten-GAU ein sofort sichtbarer Startfehler.
Dasselbe Prinzip wie beim Watch-Fail-Fast: **permanenter Konfigfehler muss
schreien, nicht schweigen.**
## Abnahme
1. Container wieder hoch, dann in der DB pruefen:
`accounts=19`, `copied=215`, `app_users=3`, `jobs=289`**identisch**.
2. **Der entscheidende Test:** Der erste Watcher-Lauf nach dem Umzug muss
`copied=0` melden (`total=215 copied=0 errors=0`).
→ Meldet er stattdessen `copied=215`, ist die Dedup-Historie verloren
gegangen und er schreibt gerade Dubletten ins Ziel. **Sofort stoppen** und
das Backup aus Schritt 2 zurueckspielen.
3. Login in der Web-UI funktioniert weiter (die 3 Benutzer sind mitgezogen).
4. `go test ./...` gruen.
Ich (Claude) verifiziere danach Punkt 13 unabhaengig auf GoldPi.