Backup & Wiederherstellung + Einstellungen in Kategorien mit Untermenü #17

Closed
opened 2026-09-26 05:03:49 +00:00 by AxonByteDev · 0 comments
Owner

Problem

  1. Kein Backup/Restore: Die gesamte Konfiguration von PatchPilot steckt in data/orchestrator.db und teilweise in Dateien auf dem Server. Zieht man auf einen neuen Server um oder fällt der alte aus, muss man alles von Hand neu einrichten: Server, Proxmox-Zugänge, Scripts, Zeitpläne, Matrix, Dokumentation usw. Eine Sicherungs- oder Wiederherstellungsfunktion in der Oberfläche gibt es nicht.
  2. Unübersichtliche Einstellungen: frontend/src/pages/Settings.tsx ist eine einzige lange Seite (rund 930 Zeilen) mit allen Bereichen untereinander. Mit den geplanten Erweiterungen (#13, #14, #16 und dem Backup aus diesem Issue) wird das noch länger.

Ziel

Teil A: Backup & Wiederherstellung

  • Unter Einstellungen → Backup & Wiederherstellung erstellt „Backup erstellen“ eine Datei, die direkt heruntergeladen wird.
  • Das Backup enthält alles, was nötig ist, damit eine frisch installierte, leere PatchPilot-Instanz danach genau so aussieht und funktioniert wie vorher.
  • Auf der neuen Instanz lädt man die Datei unter „Backup wiederherstellen“ hoch. Danach sind alle Server, Einstellungen, Scripts, Zeitpläne usw. wieder da, und Scans, Updates, Snapshots und Benachrichtigungen funktionieren sofort.

Teil B: Einstellungen mit Kategorien und Untermenü

Die Einstellungen werden in Kategorien aufgeteilt und bekommen ein Untermenü, sodass immer nur eine Kategorie zu sehen ist.

Teil A im Detail

Was ins Backup gehört (Stand im Code)

Inhalt Wo es heute liegt Hinweis
Server (inkl. SSH-Passwörter) Tabelle server Passwörter stehen im Klartext in der DB
Proxmox-Zugänge (inkl. Passwörter) Tabelle proxmoxserver
Scripts + Zeitpläne script, scriptschedule Die Zeitpläne müssen nach dem Restore neu im Scheduler landen
Server-Dokumentation serverdoc
Alle Einstellungen appsetting Scan-Zeitplan, Matrix (inkl. Passwort), Benachrichtigungs-Schalter, Update-Kanal, Login (auth_username, auth_password_hash), _secret_key
Verlauf updatescan, updaterun, scriptrun Kann groß werden (log_output, raw_output), deshalb optional
SSH-Schlüsseldateien nicht in der DB! server.ssh_key_path zeigt auf eine Datei, Default ~/.ssh/id_rsa (servers.py, scripts.py) ⚠️ Ohne die Schlüssel funktioniert auf dem neuen Server keine SSH-Verbindung, siehe unten

Nicht hinein gehören: update_cache (wird neu geprüft), laufende Update-Anforderungen bzw. Logs (#16) und die .env / SECRET_KEY aus der Umgebung (gehört zur Installation, nicht zu den Daten).

Format

  • Eine ZIP-Datei patchpilot-backup-<version>-<zeitstempel>.zip mit:
    • manifest.json: PatchPilot-Version, Erstellungszeitpunkt, Liste der Tabellen mit Zeilenanzahl, ob der Verlauf enthalten ist, Format-Version des Backups
    • database.db: konsistente Kopie über sqlite3.backup() (keine reine Dateikopie, wegen WAL). Alternativ JSON pro Tabelle, was robuster gegen Schemaänderungen ist. Beides abwägen, siehe offene Punkte.
    • ssh-keys/…: alle Dateien, auf die ein ssh_key_path zeigt (inkl. Default-Key, falls ein Server ihn nutzt), mit einer Zuordnung Server → Datei im Manifest
  • Verschlüsselung mit Passwort (dringend empfohlen): Das Backup enthält SSH-Passwörter, private SSH-Schlüssel, Proxmox-, Matrix- und Login-Daten. Beim Erstellen gibt man ein Backup-Passwort ein, und die Datei wird damit verschlüsselt (z. B. AES-GCM mit einem per scrypt/PBKDF2 abgeleiteten Schlüssel; cryptography ist schon in requirements.txt). Ohne Passwort wäre eine heruntergeladene Datei ein Generalschlüssel für das gesamte Homelab.

Wiederherstellung

  • Upload + Backup-Passwort → PatchPilot prüft zuerst das Manifest und zeigt eine Vorschau: „Backup von vX.Y.Z vom …, enthält N Server, M Scripts, …, Verlauf ja/nein“. Danach kommt ein deutlicher Bestätigungsdialog: „Alle aktuellen Daten werden ersetzt.“
  • Versionsprüfung:
    • Backup von einer älteren oder gleichen Version: erlaubt. Danach läuft die bestehende Migration in init_db() (ALTER TABLE … ADD COLUMN) und ergänzt neue Spalten.
    • Backup von einer neueren Version als der installierten: ablehnen, mit dem Hinweis „Bitte PatchPilot erst auf vX.Y.Z aktualisieren“.
  • Vor dem Überschreiben wird automatisch eine Sicherung des aktuellen Stands nach data/backups/ gelegt, damit ein Fehlgriff nicht alles zerstört.
  • SSH-Schlüssel werden in ein festes Verzeichnis innerhalb von data/ geschrieben (z. B. data/ssh-keys/, Rechte 600). ssh_key_path der Server wird beim Restore auf den neuen Ort umgeschrieben, weil der alte Pfad auf dem neuen Server oft nicht existiert, besonders bei Docker.
  • Danach Neustart des Prozesses (wie beim Selbst-Update os._exit(0): systemd bzw. Docker mit restart: unless-stopped startet neu). So werden Scheduler-Jobs (Scan, Update-Prüfung, Script-Zeitpläne), Matrix-Verbindung und JWT-Schlüssel sauber neu geladen. Die Oberfläche wartet auf die Rückkehr und leitet dann zum Login weiter.
  • Login nach dem Restore: Es gelten Benutzername und Passwort aus dem Backup, nicht mehr admin/PatchPilot. Das muss in der Oberfläche vor dem Bestätigen deutlich dastehen. Weil _secret_key mit übernommen wird, werden bestehende Tokens ungültig und man muss sich neu anmelden.

Backend

  • Neuer Router backend/routers/backup.py:
    • POST /api/backup/export (Body: password, include_history) → ZIP als Download (Content-Disposition: attachment)
    • POST /api/backup/inspect (Upload + Passwort) → Manifest/Vorschau, ohne etwas zu ändern
    • POST /api/backup/restore (Upload + Passwort) → Restore wie oben beschrieben, danach Neustart
  • Die Endpunkte brauchen einen gültigen Login (wie alle anderen). Größenlimit für den Upload, und die ZIP-Einträge werden gegen Path Traversal geprüft (keine ../ in den Pfaden).

SSH-Schlüssel (Grundsatzentscheidung)

Im Moment liegen die Schlüssel irgendwo auf dem Host bzw. im Container, und PatchPilot kennt nur den Pfad. Für ein vollständiges Backup muss PatchPilot die Schlüssel lesen können, und beim Restore müssen sie an einem Ort landen, den der Container dauerhaft sieht. Deshalb ist es sinnvoll, dass Schlüssel künftig grundsätzlich unter data/ssh-keys/ liegen. Optional kann man in der Server-Maske einen Schlüssel hochladen. Das kann auch ein eigenes Folge-Issue werden. Für dieses Issue reicht: Beim Backup werden die referenzierten Dateien eingesammelt, und fehlt eine oder ist sie nicht lesbar, warnt das Backup deutlich, statt stillschweigend ein unvollständiges Backup zu erzeugen.

Teil B im Detail: Einstellungen neu gliedern

Heutiger Aufbau (Settings.tsx, alles untereinander)

Allgemein (automatischer Scan + Zeitplan, Verlauf-Limit) → Proxmox-Server → Zugangsdaten → Matrix-Benachrichtigungen (Verbindung + Ereignis-Schalter) → Updates (Selbst-Update: Kanal, Prüfung, Auto-Apply, Versionsauswahl)

Vorgeschlagene Kategorien

Kategorie Inhalt
Allgemein Automatischer Scan (an/aus, Zeitplan, Zeitzone), Verlauf-Limit
Proxmox Proxmox-Server verwalten (hinzufügen, testen, Nodes); später Proxmox-Hosts scannen (#13)
Benachrichtigungen Matrix-Verbindung (Homeserver, Benutzer, Raum), Ereignis-Schalter
Sicherheit Zugangsdaten (Benutzername/Passwort)
PatchPilot-Update Kanal, automatische Prüfung, Auto-Apply, Versionswahl/Downgrade, Update anstoßen (#16)
Backup & Wiederherstellung Neu, aus Teil A

Später können weitere Punkte ohne Umbau dazukommen, z. B. ein GitHub-Token für Versions-Checks (#14) unter „Integrationen“.

Umsetzung

  • Untermenü: Auf dem Desktop eine Navigation links innerhalb der Einstellungsseite, rechts der Inhalt der gewählten Kategorie. Auf dem Handy ein Auswahlmenü bzw. horizontal scrollbare Tabs oben.
  • Eigene URL pro Kategorie: /settings/general, /settings/proxmox, /settings/notifications, /settings/security, /settings/update, /settings/backup. So funktionieren Direktlinks (z. B. aus der Matrix-Meldung „siehe Einstellungen → Updates“) und der Zurück-Button. /settings leitet auf /settings/general weiter.
  • Settings.tsx wird in einzelne Komponenten pro Kategorie aufgeteilt, z. B. pages/settings/GeneralSettings.tsx, ProxmoxSettings.tsx usw. (CredentialsSection und UpdateSection sind schon eigene Komponenten).
  • Warnt die Seite vor ungespeicherten Änderungen? Sie sollte es tun, wenn man mit ungespeicherten Änderungen die Kategorie wechselt.
  • Nur eine Umstrukturierung: Funktion, Endpunkte und gespeicherte Werte bleiben unverändert.

Offene Punkte

  • DB-Kopie oder JSON-Export? Eine DB-Kopie ist einfach und vollständig, ein JSON-Export pro Tabelle ist lesbarer und robuster gegen Schemaänderungen. Vorschlag: DB-Kopie, weil die bestehende Migration in init_db() ältere Stände schon hochzieht.
  • Verschlüsselung Pflicht oder optional? Vorschlag: Pflicht, weil zu viele Geheimnisse drinstecken.
  • Automatische Backups nach Zeitplan (z. B. täglich nach data/backups/ mit Rotation) wären ein sinnvoller nächster Schritt, gehören aber nicht in dieses Issue.

Akzeptanzkriterien

Backup & Wiederherstellung

  • Unter Einstellungen → Backup & Wiederherstellung lässt sich ein Backup erstellen und direkt herunterladen
  • Das Backup enthält alle Tabellen, Einstellungen und die referenzierten SSH-Schlüssel; der Verlauf ist optional
  • Fehlende oder unlesbare SSH-Schlüssel führen zu einer deutlichen Warnung
  • Das Backup ist mit einem Passwort verschlüsselt
  • Beim Restore gibt es erst eine Vorschau und eine Bestätigung, dann wird der aktuelle Stand automatisch gesichert
  • Ein Backup einer neueren Version wird abgelehnt, ein älteres wird eingespielt und migriert
  • Nach dem Restore auf einer frisch installierten Instanz funktionieren Login, Scans, Updates, Snapshots, Scripts, Zeitpläne und Matrix ohne Nacharbeit
  • Tests: Export → Restore im Rundlauf, falsches Passwort, neuere Version, manipulierte ZIP (Path Traversal)

Einstellungen

  • Die Einstellungen sind in Kategorien mit Untermenü aufgeteilt, auf Desktop und Handy nutzbar
  • Jede Kategorie hat eine eigene URL, Direktlinks und der Zurück-Button funktionieren
  • Alle bestehenden Einstellungen funktionieren unverändert
## Problem 1. **Kein Backup/Restore:** Die gesamte Konfiguration von PatchPilot steckt in `data/orchestrator.db` und teilweise in Dateien auf dem Server. Zieht man auf einen neuen Server um oder fällt der alte aus, muss man alles von Hand neu einrichten: Server, Proxmox-Zugänge, Scripts, Zeitpläne, Matrix, Dokumentation usw. Eine Sicherungs- oder Wiederherstellungsfunktion in der Oberfläche gibt es nicht. 2. **Unübersichtliche Einstellungen:** `frontend/src/pages/Settings.tsx` ist eine einzige lange Seite (rund 930 Zeilen) mit allen Bereichen untereinander. Mit den geplanten Erweiterungen (#13, #14, #16 und dem Backup aus diesem Issue) wird das noch länger. ## Ziel ### Teil A: Backup & Wiederherstellung - Unter **Einstellungen → Backup & Wiederherstellung** erstellt „Backup erstellen“ eine Datei, die **direkt heruntergeladen** wird. - Das Backup enthält **alles**, was nötig ist, damit eine **frisch installierte, leere PatchPilot-Instanz** danach **genau so** aussieht und funktioniert wie vorher. - Auf der neuen Instanz lädt man die Datei unter „Backup wiederherstellen“ hoch. Danach sind alle Server, Einstellungen, Scripts, Zeitpläne usw. wieder da, und Scans, Updates, Snapshots und Benachrichtigungen funktionieren sofort. ### Teil B: Einstellungen mit Kategorien und Untermenü Die Einstellungen werden in Kategorien aufgeteilt und bekommen ein **Untermenü**, sodass immer nur eine Kategorie zu sehen ist. ## Teil A im Detail ### Was ins Backup gehört (Stand im Code) | Inhalt | Wo es heute liegt | Hinweis | |---|---|---| | Server (inkl. SSH-Passwörter) | Tabelle `server` | Passwörter stehen im Klartext in der DB | | Proxmox-Zugänge (inkl. Passwörter) | Tabelle `proxmoxserver` | | | Scripts + Zeitpläne | `script`, `scriptschedule` | Die Zeitpläne müssen nach dem Restore neu im Scheduler landen | | Server-Dokumentation | `serverdoc` | | | Alle Einstellungen | `appsetting` | Scan-Zeitplan, Matrix (inkl. Passwort), Benachrichtigungs-Schalter, Update-Kanal, Login (`auth_username`, `auth_password_hash`), `_secret_key` | | Verlauf | `updatescan`, `updaterun`, `scriptrun` | Kann groß werden (`log_output`, `raw_output`), deshalb **optional** | | **SSH-Schlüsseldateien** | **nicht in der DB!** `server.ssh_key_path` zeigt auf eine Datei, Default `~/.ssh/id_rsa` (`servers.py`, `scripts.py`) | ⚠️ Ohne die Schlüssel funktioniert auf dem neuen Server keine SSH-Verbindung, siehe unten | **Nicht** hinein gehören: `update_cache` (wird neu geprüft), laufende Update-Anforderungen bzw. Logs (#16) und die `.env` / `SECRET_KEY` aus der Umgebung (gehört zur Installation, nicht zu den Daten). ### Format - Eine **ZIP-Datei** `patchpilot-backup-<version>-<zeitstempel>.zip` mit: - `manifest.json`: PatchPilot-Version, Erstellungszeitpunkt, Liste der Tabellen mit Zeilenanzahl, ob der Verlauf enthalten ist, Format-Version des Backups - `database.db`: konsistente Kopie über `sqlite3.backup()` (keine reine Dateikopie, wegen WAL). Alternativ JSON pro Tabelle, was robuster gegen Schemaänderungen ist. Beides abwägen, siehe offene Punkte. - `ssh-keys/…`: alle Dateien, auf die ein `ssh_key_path` zeigt (inkl. Default-Key, falls ein Server ihn nutzt), mit einer Zuordnung Server → Datei im Manifest - **Verschlüsselung mit Passwort (dringend empfohlen):** Das Backup enthält SSH-Passwörter, private SSH-Schlüssel, Proxmox-, Matrix- und Login-Daten. Beim Erstellen gibt man ein Backup-Passwort ein, und die Datei wird damit verschlüsselt (z. B. AES-GCM mit einem per scrypt/PBKDF2 abgeleiteten Schlüssel; `cryptography` ist schon in `requirements.txt`). Ohne Passwort wäre eine heruntergeladene Datei ein Generalschlüssel für das gesamte Homelab. ### Wiederherstellung - Upload + Backup-Passwort → PatchPilot prüft zuerst das Manifest und zeigt eine **Vorschau**: „Backup von vX.Y.Z vom …, enthält N Server, M Scripts, …, Verlauf ja/nein“. Danach kommt ein deutlicher Bestätigungsdialog: **„Alle aktuellen Daten werden ersetzt.“** - **Versionsprüfung:** - Backup von einer **älteren oder gleichen** Version: erlaubt. Danach läuft die bestehende Migration in `init_db()` (`ALTER TABLE … ADD COLUMN`) und ergänzt neue Spalten. - Backup von einer **neueren** Version als der installierten: ablehnen, mit dem Hinweis „Bitte PatchPilot erst auf vX.Y.Z aktualisieren“. - Vor dem Überschreiben wird automatisch eine **Sicherung des aktuellen Stands** nach `data/backups/` gelegt, damit ein Fehlgriff nicht alles zerstört. - SSH-Schlüssel werden in ein festes Verzeichnis **innerhalb von `data/`** geschrieben (z. B. `data/ssh-keys/`, Rechte `600`). `ssh_key_path` der Server wird beim Restore auf den neuen Ort umgeschrieben, weil der alte Pfad auf dem neuen Server oft nicht existiert, besonders bei Docker. - Danach **Neustart des Prozesses** (wie beim Selbst-Update `os._exit(0)`: systemd bzw. Docker mit `restart: unless-stopped` startet neu). So werden Scheduler-Jobs (Scan, Update-Prüfung, Script-Zeitpläne), Matrix-Verbindung und JWT-Schlüssel sauber neu geladen. Die Oberfläche wartet auf die Rückkehr und leitet dann zum Login weiter. - **Login nach dem Restore:** Es gelten Benutzername und Passwort **aus dem Backup**, nicht mehr `admin`/`PatchPilot`. Das muss in der Oberfläche vor dem Bestätigen deutlich dastehen. Weil `_secret_key` mit übernommen wird, werden bestehende Tokens ungültig und man muss sich neu anmelden. ### Backend - Neuer Router `backend/routers/backup.py`: - `POST /api/backup/export` (Body: `password`, `include_history`) → ZIP als Download (`Content-Disposition: attachment`) - `POST /api/backup/inspect` (Upload + Passwort) → Manifest/Vorschau, ohne etwas zu ändern - `POST /api/backup/restore` (Upload + Passwort) → Restore wie oben beschrieben, danach Neustart - Die Endpunkte brauchen einen gültigen Login (wie alle anderen). Größenlimit für den Upload, und die ZIP-Einträge werden gegen Path Traversal geprüft (keine `../` in den Pfaden). ### SSH-Schlüssel (Grundsatzentscheidung) Im Moment liegen die Schlüssel irgendwo auf dem Host bzw. im Container, und PatchPilot kennt nur den Pfad. Für ein vollständiges Backup muss PatchPilot die Schlüssel lesen können, und beim Restore müssen sie an einem Ort landen, den der Container dauerhaft sieht. Deshalb ist es sinnvoll, dass Schlüssel künftig grundsätzlich unter `data/ssh-keys/` liegen. Optional kann man in der Server-Maske einen Schlüssel hochladen. Das kann auch ein eigenes Folge-Issue werden. Für dieses Issue reicht: Beim Backup werden die referenzierten Dateien eingesammelt, und fehlt eine oder ist sie nicht lesbar, **warnt** das Backup deutlich, statt stillschweigend ein unvollständiges Backup zu erzeugen. ## Teil B im Detail: Einstellungen neu gliedern ### Heutiger Aufbau (`Settings.tsx`, alles untereinander) Allgemein (automatischer Scan + Zeitplan, Verlauf-Limit) → Proxmox-Server → Zugangsdaten → Matrix-Benachrichtigungen (Verbindung + Ereignis-Schalter) → Updates (Selbst-Update: Kanal, Prüfung, Auto-Apply, Versionsauswahl) ### Vorgeschlagene Kategorien | Kategorie | Inhalt | |---|---| | **Allgemein** | Automatischer Scan (an/aus, Zeitplan, Zeitzone), Verlauf-Limit | | **Proxmox** | Proxmox-Server verwalten (hinzufügen, testen, Nodes); später Proxmox-Hosts scannen (#13) | | **Benachrichtigungen** | Matrix-Verbindung (Homeserver, Benutzer, Raum), Ereignis-Schalter | | **Sicherheit** | Zugangsdaten (Benutzername/Passwort) | | **PatchPilot-Update** | Kanal, automatische Prüfung, Auto-Apply, Versionswahl/Downgrade, Update anstoßen (#16) | | **Backup & Wiederherstellung** | Neu, aus Teil A | Später können weitere Punkte ohne Umbau dazukommen, z. B. ein GitHub-Token für Versions-Checks (#14) unter „Integrationen“. ### Umsetzung - **Untermenü:** Auf dem Desktop eine Navigation links innerhalb der Einstellungsseite, rechts der Inhalt der gewählten Kategorie. Auf dem Handy ein Auswahlmenü bzw. horizontal scrollbare Tabs oben. - **Eigene URL pro Kategorie:** `/settings/general`, `/settings/proxmox`, `/settings/notifications`, `/settings/security`, `/settings/update`, `/settings/backup`. So funktionieren Direktlinks (z. B. aus der Matrix-Meldung „siehe Einstellungen → Updates“) und der Zurück-Button. `/settings` leitet auf `/settings/general` weiter. - `Settings.tsx` wird in einzelne Komponenten pro Kategorie aufgeteilt, z. B. `pages/settings/GeneralSettings.tsx`, `ProxmoxSettings.tsx` usw. (`CredentialsSection` und `UpdateSection` sind schon eigene Komponenten). - Warnt die Seite vor ungespeicherten Änderungen? Sie sollte es tun, wenn man mit ungespeicherten Änderungen die Kategorie wechselt. - Nur eine Umstrukturierung: Funktion, Endpunkte und gespeicherte Werte bleiben unverändert. ## Offene Punkte - **DB-Kopie oder JSON-Export?** Eine DB-Kopie ist einfach und vollständig, ein JSON-Export pro Tabelle ist lesbarer und robuster gegen Schemaänderungen. Vorschlag: DB-Kopie, weil die bestehende Migration in `init_db()` ältere Stände schon hochzieht. - **Verschlüsselung Pflicht oder optional?** Vorschlag: Pflicht, weil zu viele Geheimnisse drinstecken. - **Automatische Backups nach Zeitplan** (z. B. täglich nach `data/backups/` mit Rotation) wären ein sinnvoller nächster Schritt, gehören aber nicht in dieses Issue. ## Akzeptanzkriterien **Backup & Wiederherstellung** - [x] Unter Einstellungen → Backup & Wiederherstellung lässt sich ein Backup erstellen und direkt herunterladen - [x] Das Backup enthält alle Tabellen, Einstellungen und die referenzierten SSH-Schlüssel; der Verlauf ist optional - [x] Fehlende oder unlesbare SSH-Schlüssel führen zu einer deutlichen Warnung - [x] Das Backup ist mit einem Passwort verschlüsselt - [x] Beim Restore gibt es erst eine Vorschau und eine Bestätigung, dann wird der aktuelle Stand automatisch gesichert - [x] Ein Backup einer neueren Version wird abgelehnt, ein älteres wird eingespielt und migriert - [x] Nach dem Restore auf einer **frisch installierten** Instanz funktionieren Login, Scans, Updates, Snapshots, Scripts, Zeitpläne und Matrix ohne Nacharbeit - [x] Tests: Export → Restore im Rundlauf, falsches Passwort, neuere Version, manipulierte ZIP (Path Traversal) **Einstellungen** - [x] Die Einstellungen sind in Kategorien mit Untermenü aufgeteilt, auf Desktop und Handy nutzbar - [x] Jede Kategorie hat eine eigene URL, Direktlinks und der Zurück-Button funktionieren - [x] Alle bestehenden Einstellungen funktionieren unverändert
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
AxonByteDev/PatchPilot#17
No description provided.