docs/web-ui.md beschreibt jetzt das Preset samt der drei begruendeten Abweichungen, die Sitzung mit ihren zwei Uhren und die Fehlergrenze. Dazu zwei neue Grenzen: Geist Mono wird nicht mitgeliefert, und die Suche im Ereignisprotokoll filtert weiterhin im Browser. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
11 KiB
Weboberfläche
Die Konsole, über die man die Anlage bedient — und der Ort, an dem sich am leichtesten etwas vortäuschen ließe.
Sie erreicht 89 von 95 fachlichen Endpunkten. Die sechs offenen sind
Detail-Abrufe (GET /alerts/{id}, GET /agents/{id}, GET /proxmox/vms/{id},
GET /security/findings, GET /verification/{id} und dessen Ergebnisse), deren
Daten die jeweiligen Listen bereits enthalten.
Die eine Entscheidung, die alles trägt
Semantische Farben ausschließlich für Zustände (PROMPT §106). Die Konsole ist neutral gehalten; wo Farbe erscheint, bedeutet sie etwas. Eine bunte Oberfläche verschleiert, welche Information wirklich dringend ist — und in einer Backup-Konsole ist genau das die einzige Frage, die zählt.
Daraus folgt der Zuschnitt: kein Markenblau als Fläche, der Akzent nur für Bedienelemente. Der Schweregrad einer Kennzahl färbt die Randlinie, nicht die Kachel; zehn farbige Flächen nebeneinander ergeben ein Mosaik, in dem die eine kritische Zahl untergeht.
Die Statuszuordnung steht an genau einer Stelle
components/ui/StatusBadge.tsx bildet jeden Fachbegriff der API auf einen der
fünf Töne ab. Wäre diese Abbildung über die Seiten verteilt, erschiene früher
oder später irgendwo partial_failure grün — und ein Betreiber hält einen
Teilfehler dann für einen Erfolg.
Vier Zuordnungen sind keine Geschmacksfrage:
| Wert | Ton | Warum |
|---|---|---|
partial_failure |
Warnung | Entwicklungsregel 1: nie SUCCESS |
successful (Einstufung) |
neutral | Heißt „der Lauf ist durchgelaufen", nicht „wiederherstellbar" |
corrupted |
kritisch | Nicht zu 70 % wiederherstellbar, sondern gar nicht |
advisory (Löschschutz) |
Warnung | Der Schutz ist eine Software-Regel, kein Schutz des Dateisystems |
Ein unbekannter Wert wird neutral dargestellt, niemals grün. Ein neuer
Serverzustand, den die Tabelle nicht kennt, darf nicht als „in Ordnung"
durchgehen. StatusBadge.test.tsx hält alle fünf Punkte fest; jeder wurde durch
Mutation als fangend bestätigt.
Was nicht da ist, wird benannt
Der Grundsatz aus PROMPT §139 gilt unverändert: Ein Menü, das nur die fertigen Bereiche zeigt, verschweigt den Ausbaustand; eines mit leeren Masken täuscht ihn vor. Jeder Eintrag erscheint, und ein noch nicht verfügbarer nennt, was fehlt.
Konkret sichtbar an vier Stellen:
- Kennzahlen ohne Datengrundlage erscheinen mit Begründung statt mit einer Null. „0 kritische Meldungen" hieße „keine Probleme" und bedeutete „es wird nicht geprüft".
- Ungemessene Eingangsgrößen der Bewertung stehen als „ungemessen" da, nicht als null Punkte. Als 0 zu zeigen bestrafte das Unbekannte.
- Nicht ausgewertete Meldungsregeln werden als solche gekennzeichnet. Eine Regel, die dauerhaft schweigt, ist gefährlicher als keine.
- Ungeprüfte Bereiche im Security Center gehen weder positiv noch negativ in die Rechnung ein; ab drei sagt die Seite, dass die Zahl eine Vermutung ist.
Die achtzehn Seiten
| Bereich | Seiten |
|---|---|
| Betrieb | Übersicht · Sicherungsaufträge · Wiederherstellung · Meldungen |
| Daten | Wiederherstellungspunkte · Prüfung · Repositories · Aufbewahrung |
| Infrastruktur | Agenten · Proxmox · Geschützte Systeme |
| Analyse | Kennzahlen · Berichte · Security Center |
| Verwaltung | Benutzer · Rollen · Ereignisprotokoll · Einstellungen |
Die Gliederung folgt dem Weg durch die Anlage: Was täglich beobachtet wird, steht oben; was einmal eingerichtet und dann selten angefasst wird, unten.
Handlungen, die etwas verändern
Die drei Hürden vor dem Überschreiben
Der Wiederherstellungs-Assistent setzt sie sichtbar um:
- Das Kennzeichen
overwrite_existingmuss gesetzt werden. - Die Berechtigung
restores.overwriteprüft der Server — sie steckt bewusst nicht inrestores.execute. confirm_overwriteverlangt den wörtlich wiederholten Zielpfad.
Läuft die dritte ins Leere, weil das Ziel leer ist, entfällt sie. Ein Ritual ohne Anlass gewöhnt das Wegklicken an — und dann wirkt es dort nicht mehr, wo es zählt. Dieselbe Überlegung trägt die wörtliche Bestätigung beim Löschen eines Wiederherstellungspunkts, eines Auftrags und beim Anwenden einer Aufbewahrungsregel.
Die Vorabprüfung ist ein eigener Schritt
Sie schreibt nichts und stellt fest, ob jeder benötigte Block noch da ist. Ein Manifest allein belegt nur, dass jemand einmal etwas gesichert hat. Fehlende Blöcke stehen ganz oben und in Rot; sie sind der einzige Befund, bei dem feststeht, dass die Wiederherstellung nicht vollständig gelingen kann.
Ein 409 ist eine Auskunft, kein Fehler
Ein zweiter Anstoß bei laufendem Auftrag erscheint als Hinweis, nicht als Fehlschlag. Der Auftrag läuft ja — und genau das wollte der Betreiber wissen.
Was Löschen wirklich bewirkt, steht dabei
- Ein gelöschter Auftrag nimmt seine Wiederherstellungspunkte nicht mit. Sie gehören zum Repository. Ohne diesen Hinweis löscht jemand einen Auftrag in der Annahme, Platz zu schaffen.
- Wird beim Löschen kein Speicher frei, ist das kein Fehler, sondern Deduplizierung: Die Blöcke werden von einem anderen Backup gebraucht.
Geheimnisse gehen nur hinein
Das Aufnahme-Token eines Agenten erscheint genau einmal, mit ausdrücklichem Hinweis und ohne Weg, den Dialog versehentlich zu schließen. Das API-Token eines Proxmox-Verbunds wird nach dem Anlegen nie wieder ausgeliefert — das ist kein Mangel, sondern der Grund, warum ein Lesezugriff auf die Konfiguration ungefährlich ist.
Aussehen
Farben, Radien, Schatten und Schrift stammen aus dem Preset b5vnF8SMi
(tweakcn): violett als Handlungsfarbe, Radius 0, schattenlos, durchgehend
Geist Mono. Kantig und ruhig.
Drei Abweichungen, begründet in styles/theme.css:
- Die Statusfarben bleiben. Das Preset kennt nur
destructiveund fünf Diagrammfarben; §106 verlangt fünf Bedeutungen. Ohne sie ließe sich ein Teilfehler nicht von einem Erfolg unterscheiden. - Das dunkle Thema hängt an
[data-theme='dark'], nicht an.dark— der Umschalter setzt dieses Attribut..darkfunktioniert zusätzlich. - Geist Mono lädt nicht nach. Sie steht zuerst im Stapel; liegt sie nicht auf dem Gerät, greift die System-Monospace. Eine Schrift von einem fremden Host zu holen verbietet die CSP — und ein Backup-Server, der für seine Oberfläche ins Internet greift, wäre auch ohne CSP falsch.
Eine Zuordnung ist die Stolperstelle: In shadcn ist accent die dezente
Hover-Fläche und primary die Farbe der Handlung. Sie zu verwechseln macht jede
Schaltfläche grau.
Die Benennung bleibt semantisch (--surface-card, --text-primary) statt
shadcn-typisch: Die Zuordnung steht an genau einer Stelle, und ein Wechsel des
Presets fasst keine einzige Komponente an.
Technik
- Tailwind v4 und Radix-Primitive nach shadcn-Muster. Alles gebündelt; die CSP der Auslieferung lässt externe Ressourcen ohnehin nicht zu.
- Farben als CSS-Variablen, damit dieselbe Komponente in beiden Themen
funktioniert, ohne dass jede Klasse eine
dark:-Variante braucht. - Fehlergrenze um den Seiteninhalt. Ohne sie reißt ein Fehler in einer Komponente den gesamten Baum ab; übrig bleibt eine leere Seite — im dunklen Thema ein schwarzer Bildschirm ohne Hinweis. Menü und Kopfzeile bleiben stehen, der Fehlertext ist lesbar.
- Dark Mode über ein Attribut am Wurzelelement, nicht allein über die Medienabfrage: Eine Konsole, die nachts während einer Störung von selbst umschaltet, ist lästig. Das Attribut sitzt am Wurzelelement, weil ein Dialog im Portal sonst im falschen Thema erschiene.
- Navigation über die History-API, keine Router-Bibliothek. Zwei Ebenen — Seite und optional ein Objekt darauf — reichen für diese Konsole.
useMutationfür schreibende Aufrufe: Doppelklickschutz, Vorgangsnummer bis in die Meldung, keinsetStatenach dem Aushängen.Idempotency-Keyan allen anlegenden und zerstörenden Aufrufen. Ohne ihn erzeugt ein Doppelklick zwei Aufträge — und bei einer Wiederherstellung zwei gleichzeitige Läufe in dasselbe Ziel.- Die Servermeldung hat Vorrang vor der allgemeinen Erklärung zum Fehlercode. Sie kennt den Einzelfall, und diese Genauigkeit ist mehr wert.
- Berechtigungen im Menü sind Anzeige, keine Sicherung. Sie verhindern Sackgassen; geprüft wird auf dem Server.
Sitzung
Sie überlebt ein Neuladen. Die Tokens liegen im sessionStorage des Tabs —
nicht im localStorage, der ein Schließen des Browsers überstünde. Begrenzt
wird sie durch zwei Uhren:
| Harte Obergrenze | 30 Minuten ab Anmeldung, durch keine Interaktion verschiebbar |
| Untätigkeitsgrenze | 30 Minuten ohne Eingabe |
Maßgeblich ist die frühere der beiden. Die verbleibende Zeit steht neben „Abmelden" und wird unter fünf Minuten auffällig.
Dass die Tokens überhaupt abgelegt werden, kehrt eine frühere Entscheidung um: Vorher lagen sie nur im Arbeitsspeicher, und jedes Neuladen warf den Betreiber auf die Anmeldemaske. Mitten in einer Störung ist das kein Sicherheitsgewinn, sondern ein Hindernis. Was den Rest trägt, ist nicht der Speicherort, sondern der sofortige serverseitige Widerruf: Die Tokens sind opak, kein JWT, und genau dafür wurden sie gewählt.
- Jede Fehleranzeige nennt
request_id, kopierbar. Ohne sie bleibt „es hat nicht funktioniert".
Betriebsfolge
Das Bundle braucht einen SPA-Fallback (try_files $uri /index.html), sonst
ergibt ein Neuladen auf /recovery-points einen 404. setup.sh richtet das mit
ein.
Nachgewiesen
Gegen Debian 12 mit echtem PostgreSQL und nginx, über genau die Aufrufe, die die Konsole macht:
- Repository übernommen, Durchsetzungsstufe gemessen (
advisory— auf overlayfs richtig) - Auftrag angelegt, Lauf
202, zweiter Anstoß409 - Sicherung erfolgreich: 2 Objekte, 3.000.006 Byte, 0 übergangen
- Blockprüfung
clean, 5 Blöcke - Vorabprüfung: „wiederherstellbar, 2 Dateien, 2,9 MiB"
- Wiederherstellung nach
/etcabgewiesen - Alle 18 Seiten liefern über HTTPS
200; das Design-System steckt samt Dark-Mode-Regeln im ausgelieferten CSS
76 Tests, tsc sauber, eslint ohne Warnung. Bundle 466 KB (136 KB gzip), CSS
30 KB (6 KB gzip).
Bekannte Grenzen
- Sechs Detail-Endpunkte haben keine eigene Ansicht; ihre Daten stehen in den Listen.
- Die Suche im Ereignisprotokoll filtert im Browser über die letzten 100 Einträge. Bei größeren Beständen gehört sie auf den Server.
- Geist Mono wird nicht mitgeliefert. Ohne die Schrift auf dem Gerät sieht die Oberfläche in der System-Monospace anders aus als im Preset.
- Kein Live-Fortschritt.
/api/v1/events/streamsteht inSYNCOVA_API.md, ist aber auch serverseitig nicht umgesetzt — es fehlt nicht nur die Anbindung. Laufende Sicherungen und Wiederherstellungen aktualisieren sich beim Neuladen, nicht von selbst. - Kein Simple Mode. Der Plan trennt Simple und Advanced Mode; umgesetzt ist eine Ansicht.
- Proxmox ist nicht auf echter Hardware freigegeben. Die Seite sagt das ausdrücklich.