Enterprise-Backup-, Recovery-, Verification-, Security- und Monitoring-Plattform fuer Proxmox VE, Windows, Linux und Dateisysteme. Der Leitsatz, der fast jede Entscheidung erklaert: Ein Backup gilt erst als vertrauenswuerdig, wenn Integritaet geprueft und Wiederherstellbarkeit nachgewiesen wurde. Deshalb steigt ein Wiederherstellungspunkt erst nach einem tatsaechlich durchgefuehrten Restore-Test auf "recoverable", und Unbekanntes geht in keine Bewertung als "gut" ein. Umfang (Phasen 0-23): - Repository Engine: inhaltsadressierte Bloecke, atomares Commit-Protokoll, Katalogaufbau allein aus den Manifesten — ohne Datenbank - Backup Engine: inhaltsabhaengiges Chunking, Deduplizierung trotz Verschluesselung, zstd, AES-256-GCM, Streaming mit Gegendruck - Agenten fuer Windows und Linux mit Auftragsabholung (Pull-Modell) - Proxmox-Provider mit beiden Zugriffswegen auf die Sicherungsarchive - Scheduler, Recovery Engine mit Pruefpunkt, Verification, Unveraenderlichkeit - Weboberflaeche, Kennzahlen, Meldungen, Berichte, Security Center, Ransomware-Heuristik (meldet, handelt nie) - Disaster Recovery, Haertung, Leistungsmessung, Chaos Testing - Eingefrorene Vertraege fuer API, Migrationen, Backup-Format und Repository - Auslieferungspaket fuer linux/amd64, linux/arm64 und windows/amd64 Nicht enthalten und als solches gekennzeichnet: Kapazitaetsprognose, Backup Copy, Changed Block Tracking bei Proxmox, erweiterte Attribute und ACLs. Gebaut, aber nie auf echter Hardware gefahren: der Windows-Dienst, die systemd-Einheit und der verpflichtende Proxmox-Meilenstein — ob eine wiederhergestellte VM startet, ist ungeprueft. Einzelheiten in CHANGELOG.md und docs/release-candidate.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.8 KiB
Aufbau des Codes
Dieses Dokument beschreibt den aktuell implementierten Stand. Die angestrebte Gesamtarchitektur steht in SYNCOVA_ARCHITECTURE.md.
Schichtung
apps/web Weboberfläche (React + TypeScript)
| HTTP (gleicher Ursprung, im Entwicklungsbetrieb über Proxy)
v
apps/api Control-Plane-API (Go)
|
v
packages/platform Querschnittsdienste: config, logging, database, health
|
v
PostgreSQL ausschließlich Control Plane, niemals Backup-Nutzdaten
Die Abhängigkeitsrichtung ist strikt: packages/ kennt apps/ nicht. Damit können Agent und Worker später dieselben Querschnittsdienste nutzen, ohne die API einzubinden.
packages/platform
| Paket | Verantwortung |
|---|---|
config |
Konfiguration aus Umgebungsvariablen, vollständige Validierung |
logging |
strukturiertes Logging, Correlation IDs, Secret-Redaction |
database |
PostgreSQL-Pool, Health-Check, Migrationsverwaltung |
health |
Health Engine über alle Komponenten |
config
Alle Werte stammen aus SYNCOVA_*-Umgebungsvariablen. Zwei Entscheidungen prägen das Paket:
- Secrets besitzen keinen Standardwert. Das Datenbankpasswort ist als nicht exportiertes Feld abgelegt, damit es nicht versehentlich serialisiert wird. Zugriff besteht nur über
ConnectionString()(mit Passwort) undRedactedConnectionString()(ohne). - Validierungsfehler werden gesammelt.
Load()meldet alle Probleme gemeinsam, statt beim ersten abzubrechen.
Sicherheitsrelevante Voreinstellungen: Listener nur auf 127.0.0.1, CORS leer, Body-Limit 1 MiB, Wildcard-Herkunft grundsätzlich unzulässig, unverschlüsselte Herkunft in der Produktion abgelehnt.
logging
slog mit JSON-Ausgabe. Die Redaction hängt an ReplaceAttr und greift damit für jedes Attribut — der einzige Ort, an dem sie nicht vergessen werden kann. Erkannt werden Feldnamen, die auf ein Geheimnis hindeuten (password, token, secret, connection_string und weitere), unabhängig von Schreibweise und Präfix.
health
Jede Komponente meldet einen expliziten Zustand; der Gesamtzustand ist der schlechteste Einzelzustand. Drei Eigenschaften sind bewusst so gebaut:
- Eine Prüfung ohne gemeldeten Zustand gilt als kritisch, nicht als gesund.
- Eine Zeitüberschreitung gilt als kritisch, statt den Endpunkt zu blockieren.
- Ein Panic in einer Prüfung wird abgefangen und als kritisch gemeldet.
Nur als kritisch registrierte Komponenten beeinflussen die Readiness. Eine ausgefallene Nebenkomponente nimmt den Dienst also nicht aus dem Verkehr, erscheint aber weiterhin ehrlich im Bericht.
apps/api
Middleware-Reihenfolge
Recovery → Correlation → SecurityHeaders → CORS → BodyLimit → AccessLog → Router
Recovery liegt außen, damit auch Fehler innerer Schichten erfasst werden. Correlation folgt unmittelbar, damit jede weitere Schicht bereits eine ID zum Loggen hat.
Request-ID und Correlation ID
Die Request-ID wird immer serverseitig als UUID vergeben. Die Correlation ID darf der Aufrufer über X-Correlation-ID vorgeben, um eine Operation über Systemgrenzen zu verfolgen — aber nur, wenn der Wert eine gültige UUID ist. Andernfalls wird er verworfen, damit keine fremden Zeichenketten in die Logs gelangen.
Antworthülle
{ "data": {}, "meta": { "request_id": "uuid" } }
{ "error": { "code": "...", "message": "...", "request_id": "uuid" } }
APIError trennt die ausgelieferte Darstellung von der internen Ursache: Letztere wird über WithCause mitgeführt, erscheint im Log und nie in der Antwort.
Maßgeblich für den Client ist die Hülle, nicht der HTTP-Status. Beide tragen unterschiedliche Aussagen: der Status beschreibt den Betriebszustand, die Hülle den Inhalt. GET /api/v1/health nutzt genau das und meldet einen kritischen Systemzustand mit 503, liefert dabei aber den vollständigen Bericht als Nutzlast — das externe Monitoring schlägt an, und die Oberfläche kann trotzdem anzeigen, was kaputt ist.
Health-Endpunkte
| Endpunkt | Prüft | Zweck |
|---|---|---|
GET /health/live |
nur den Prozess | Neustartentscheidung |
GET /health/ready |
alle kritischen Komponenten | Verkehrszuteilung |
GET /api/v1/health |
alle Komponenten einzeln | Diagnose |
Liveness prüft bewusst keine Abhängigkeiten: sonst würde eine kurzzeitig nicht erreichbare Datenbank einen Neustart des Dienstes auslösen und das Problem verschlimmern.
Datenbank
PostgreSQL ist die Control-Plane-Datenbank und enthält niemals Backup-Nutzdaten. Beide Zugriffswege — Verbindungspool und Migrationsläufe — nutzen denselben pgx-Treiber. Das ist eine bewusste Festlegung: golang-migrate würde sonst seinen eingebauten lib/pq-Treiber verwenden, der andere SSL-Modi kennt, womit dieselbe Konfiguration je nach Kommando funktionieren oder scheitern würde.
Migrationen sind über embed ins Binary eingebettet und laufen ausschließlich über syncova-migrate. Der API-Dienst prüft beim Start nur, ob der Schemastand zur Programmversion passt.
apps/web
Aufbau nach PROMPT.md §104:
src/
api/ HTTP-Client mit Fehlerbehandlung
components/ wiederverwendbare Bausteine des Designsystems
features/ fachliche Bereiche (aktuell: health)
styles/ Design-Token
types/ Typen des API-Vertrags
Der Client requestApi kapselt die Antworthülle und liefert Fehler stets als ApiError. Eine Antwort außerhalb des Vertrags führt zu einem klaren Fehler statt zu einem stillschweigend leeren Ergebnis.
Die Statusfarben (grün/gelb/orange/rot/blau) sind ausschließlich Zuständen vorbehalten. Ein Zustand wird nie allein über Farbe vermittelt, sondern immer zusätzlich als Text — Farbe allein wäre für farbfehlsichtige Anwender unzugänglich.