Files
kaffeekasse-saas/docs/betrieb-backup-monitoring.md
T
clemensandClaude Sonnet 5 3fc65812ef M8: Backup/Restore-Prozess und Monitoring dokumentiert
docs/betrieb-backup-monitoring.md: taeglicher mysqldump-Cron-Job mit
Aufbewahrung, Restore-Befehl inklusive Hinweis auf scripts/migrate.php,
vierteljaehrlicher Restore-Test. Produktive PHP-Fehlerkonfiguration
(display_errors aus, log_errors an) und die aktiv zu beobachtenden
Signale ohne dediziertes APM-Tool: audit_log fuer ungewoehnliche
Admin-Aktionen, rate_limit_attempts fuer Brute-Force-Versuche,
outbound_emails.status=failed fuer Mailversand-Probleme.

Damit ist M8 fuer den geplanten Scope abgeschlossen, mit einer bewusst
offenen Ausnahme (Content-Security-Policy, braucht Template-Bereinigung
der bestehenden Inline-Styles).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 20:19:20 +02:00

107 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Backup, Restore und Monitoring im Produktivbetrieb
Stand: 2026-07-15
Dieses Dokument beschreibt die für den Produktivbetrieb auf dem Webspace
empfohlenen Backup-, Restore- und Monitoring-Maßnahmen. Es ergänzt
`docs/betrieb-mail.md` und `docs/m8-haertung.md`.
## Backups
Die App hat kein eigenes Backup-Tooling; das ist bei einer MySQL-Datenbank
auf Webspace-Hosting bewusst nicht nötig `mysqldump` reicht.
Empfohlener täglicher Cron-Job (Zeitpunkt außerhalb der Hauptnutzungszeit):
```bash
#!/usr/bin/env bash
set -euo pipefail
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
BACKUP_DIR="/pfad/ausserhalb/des/webroots/backups"
mkdir -p "$BACKUP_DIR"
mysqldump \
--single-transaction \
--routines \
--triggers \
-h "$DB_HOST" -P "${DB_PORT:-3306}" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" \
| gzip > "$BACKUP_DIR/kaffeeliste_${TIMESTAMP}.sql.gz"
# Aufbewahrung: 14 Tage taegliche Backups behalten, aeltere loeschen
find "$BACKUP_DIR" -name 'kaffeeliste_*.sql.gz' -mtime +14 -delete
```
Wichtige Punkte:
- `--single-transaction` sorgt für einen konsistenten Snapshot ohne
Tabellen zu sperren (InnoDB, wie hier durchgängig verwendet).
- Der Backup-Ordner muss **außerhalb** des über HTTP erreichbaren Webroots
liegen, sonst wären Dumps öffentlich abrufbar.
- Zusätzlich zu lokalen Backups auf dem Webspace mindestens eine Kopie an
einen anderen Ort übertragen (z. B. verschlüsselt in Cloud-Speicher),
damit ein Ausfall des Webspace-Anbieters nicht auch die Backups
vernichtet.
- `var/uploads`, `var/mail` und `var/sessions` enthalten keine dauerhaft
relevanten Daten (Uploads werden nach Verarbeitung gelöscht,
`var/mail` ist nur der Dev-Log-Transport) und müssen nicht gesichert
werden.
## Restore
```bash
gunzip -c kaffeeliste_20260715_030000.sql.gz | mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME"
```
Danach `php scripts/migrate.php` laufen lassen, falls das Backup älter als
die zuletzt eingespielten Migrationen ist (das Skript ist idempotent und
wendet nur fehlende Migrationen an).
**Restore-Test:** Mindestens einmal pro Quartal einen echten Restore gegen
eine separate Test-Datenbank durchführen und die App dagegen starten
(`scripts/run-dev-server.sh` mit den Test-DB-Zugangsdaten). Ein Backup, das
nie zurückgespielt wurde, ist kein verlässliches Backup.
## Monitoring und Fehlerlogging
### PHP-Fehlerausgabe
Im Dev-Modus zeigt `display_errors=1` Fehler direkt im Browser (siehe
`.local/php-dev.ini`) das ist für lokale Entwicklung richtig, aber
produktiv ein Sicherheitsrisiko (Stacktraces, Dateipfade). Produktiv muss
gelten:
```ini
display_errors = Off
log_errors = On
error_log = /pfad/ausserhalb/des/webroots/logs/php-error.log
```
Die meisten Webspace-Anbieter setzen das bereits serverseitig; im Zweifel
per `.htaccess` oder `ini_set()` am Anfang von `config.php` erzwingen.
### Was aktiv beobachtet werden sollte
- **`php-error.log`**: Fatal Errors und Warnings. Ein plötzlicher Anstieg
deutet meist auf eine kaputte Migration oder einen fehlerhaften Deploy
hin.
- **`audit_log`**: Ungewöhnliche Häufung sicherheitsrelevanter Aktionen
(`participant.access_granted`, `tenant_settings.updated`,
`year_end_bonus.distributed`, `tenant_data.exported`) außerhalb der
üblichen Nutzungszeiten eines Mandanten.
- **`rate_limit_attempts`**: Viele Treffer in kurzer Zeit für einen
`login_ip:*`- oder `login_email:*`-Bucket zeigen einen laufenden
Brute-Force-Versuch, auch wenn er durch das Rate-Limit bereits
abgewehrt wird.
- **`outbound_emails` mit `status = 'failed'`**: Deutet meist auf ein
Problem mit dem lokalen Mailversand hin (siehe
`docs/betrieb-mail.md`), zum Beispiel einen falsch konfigurierten
`APP_MAIL_FROM` oder ein Zustellproblem beim Webspace-Anbieter.
### Bewusst nicht umgesetzt
Ein dediziertes APM-/Monitoring-Tool (z. B. Uptime-Checks, strukturiertes
Log-Shipping, Alerting) ist für den aktuellen Umfang nicht eingerichtet.
Das lohnt sich erst mit echtem Produktivbetrieb und mehreren zahlenden
Mandanten; bis dahin reichen die oben genannten manuellen Prüfpunkte.