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>
7.1 KiB
API
/api/v1 — eingefroren. Die vollständige Liste aller 102 Endpunkte samt
geforderter Berechtigung steht maschinenlesbar in
apps/api/internal/httpapi/contract_routes.txt; eine Prüfung schlägt an, sobald
sich etwas daran ändert. Der verbindliche Vertrag ist SYNCOVA_API.md.
Dieses Dokument erklärt, wie die API sich verhält — die Dinge, die man aus einer Endpunktliste nicht abliest.
Die Antworthülle ist maßgeblich, nicht der HTTP-Status
{ "data": { "…": "…" }, "meta": { "request_id": "…" } }
{ "error": { "code": "BACKUP_REPOSITORY_UNAVAILABLE",
"message": "…", "details": {}, "request_id": "…" } }
Werten Sie error gegen data aus, nicht response.ok. GET /health
liefert bei kritischem Zustand 503 mit vollständigem data-Bericht:
Monitoring schlägt an, und die Oberfläche kann trotzdem anzeigen, was kaputt
ist. Ein Client, der bei 503 nur „Fehler" meldet, verschenkt genau die
Auskunft, die er braucht.
Fehlercodes sind sprechende Konstanten in SCREAMING_SNAKE_CASE. Sie sind Teil
des Vertrags; werten Sie sie aus, nicht den Meldungstext — der ist für
Menschen und darf sich ändern.
request_id steht in jeder Antwort, auch der erfolgreichen. Bei einer
Rückfrage ist sie das Einzige, womit sich eine Anfrage in den Protokollen
wiederfinden lässt.
Anmeldung
curl -X POST https://<server>/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"…"}'
{ "data": { "mfa_required": false,
"tokens": { "access_token": "…", "refresh_token": "…",
"access_expires_at": "…", "refresh_expires_at": "…" },
"user": { "…": "…" } } }
Bei "mfa_required": true folgt POST /auth/mfa/verify mit dem Code.
Opake Tokens, keine JWT. Der Grund ist die sofortige Widerrufbarkeit: Ein JWT bliebe nach Sperre oder Passwortänderung bis zum Ablauf gültig. Gespeichert wird serverseitig nur der SHA-256-Hash.
Danach Authorization: Bearer <access_token>.
Zwei Pflichtfelder im Kopf
| Kopfzeile | Wann | Wozu |
|---|---|---|
X-Correlation-ID |
jede Anfrage | verbindet Anfrage und Logzeilen. Nur eine gültige UUID wird übernommen, sonst verworfen — damit keine fremden Zeichenketten in die Protokolle geraten |
Idempotency-Key |
siehe unten | verhindert Doppelausführung |
Idempotenz ist erforderlich bei: Auftrag anlegen, Backup starten, Wiederherstellung anlegen, Repository eintragen und destruktiven Konfigurationsänderungen. Ein wiederholter Aufruf mit demselben Schlüssel liefert das erste Ergebnis, statt ein zweites Mal zu handeln.
Berechtigungen
Jeder Endpunkt verlangt genau eine. Sie steht in der eingefrorenen Liste, weil eine stillschweigend gelockerte Prüfung die gefährlichste Änderung überhaupt wäre: Der Endpunkt funktioniert weiter, nur dürfen ihn plötzlich mehr Leute aufrufen.
Vier Sonderfälle:
-— ohne Anmeldung erreichbar:/health*,/auth/login,/auth/refresh,/auth/mfa/verifyund/agents/register(ein sich aufnehmender Agent besitzt noch kein Betriebstoken).sitzung— angemeldet, ohne besondere Berechtigung:/me,/auth/logout, MFA-Einrichtung für sich selbst.agent-token— Betriebstoken eines Agenten statt Benutzersitzung.restores.overwritesteckt nicht inrestores.execute.
Berechtigungen im Frontend sind Anzeige, keine Sicherung. Sie verhindern Sackgassen; geprüft wird auf dem Server.
Seitenweise Ergebnisse
GET /api/v1/backups?page=2&page_size=50
{ "data": [ … ], "meta": { "page": 2, "page_size": 50, "total": 312,
"request_id": "…" } }
Dateien
Berichte kommen als CSV, JSON oder PDF — ohne Antworthülle. Der Fehlerfall dagegen trägt sie.
Prüfen Sie den Inhaltstyp, bevor Sie speichern. Sonst landet eine
Fehlermeldung als bericht.pdf im Download-Ordner.
Die Endpunkte im Überblick
| Bereich | Endpunkte | Wofür |
|---|---|---|
/auth, /me |
7 | Anmeldung, Sitzung, eigener zweiter Faktor |
/users, /roles, /permissions |
12 | Konten und Rollen |
/repositories |
11 | Eintragen, Zustand, Prüfung, Integritätslauf, Katalogaufbau, Aufbewahrung |
/jobs |
8 | Aufträge und deren Läufe |
/backups |
8 | Wiederherstellungspunkte, Schutz, Legal Hold, Bewertung |
/restores |
6 | Vorabprüfung, Ausführung, Fortsetzung |
/verification |
5 | Prüfläufe bis zum Wiederherstellungstest |
/agents |
11 | Aufnahme, Verwaltung, Auftragsabholung |
/proxmox, /virtual-machines |
10 | Verbünde, Bestandsaufnahme, Gäste |
/alerts, /notification-channels |
8 | Meldungen und Zustellung |
/metrics, /reports, /security, /audit-events |
7 | Kennzahlen, Berichte, Sicherheitslage, Protokoll |
/health |
3 | Betriebszustand |
Vier Verhaltensweisen, die überraschen
POST /jobs/{id}/run antwortet 202, nicht 201. Der Lauf ist eingereiht;
die Sicherung hat nicht begonnen. Ein zweiter Anstoß bei laufendem Auftrag
ergibt 409, nicht 500.
POST /repositories legt nichts an, sondern übernimmt. Ein Repository
entsteht auf einem Datenträger (syncova-repo create). Der Endpunkt öffnet das
vorhandene, liest dessen Kennung aus dem Descriptor und trägt es ein. Liegt
dort keines, wird abgelehnt — ein Eintrag ohne Ablage dahinter wäre ein Ziel,
das erst um zwei Uhr nachts als nicht vorhanden auffällt.
Der Integritätslauf meldet einen Befund nicht als Fehler. POST /repositories/{id}/integrity-scan antwortet 200 mit "healthy": false.
„Die Prüfung schlug fehl" und „das Repository ist beschädigt" sind zwei völlig
verschiedene Lagen; sie zu verwechseln macht aus einem Befund einen
Werkzeugfehler.
Kennzahlen unterscheiden „null" und „unbekannt". Jeder Punkt einer Zeitreihe
trägt has_value. Ein Zeitfenster ohne Sicherungslauf hat keinen Durchsatz —
nicht null Byte je Sekunde. Zeichnen Sie die Linie unterbrochen, nicht durch
den Nullpunkt.
Was es nicht gibt
- Kein WebSocket/SSE-Stream.
/api/v1/events/streamist im Vertrag vorgesehen und nicht umgesetzt. Live-Anzeigen laufen über Abfragen. - Keine Massenoperationen. Kein
DELETE /backups?filter=…— destruktive Handlungen gehen einzeln und werden einzeln auditiert. - Kein
PUT. Änderungen laufen überPATCHmit den Feldern, die sich tatsächlich ändern.
Fehlercodes, die man kennen sollte
| Code | Status | Bedeutung |
|---|---|---|
VALIDATION_FAILED |
422 | fachlich ungültig — die Meldung sagt, was fehlt |
PERMISSION_DENIED |
403 | angemeldet, aber nicht berechtigt |
CONFLICT |
409 | Zustand passt nicht: Auftrag läuft bereits, Name vergeben, Verbund in Benutzung |
RATE_LIMITED |
429 | zu viele Anfragen (Vorgabe 600/min) |
SERVICE_UNAVAILABLE |
503 | Abhängigkeit weg. Bei Datenbankausfall ausdrücklich nicht „Sitzung abgelaufen" — die Meldung sagt: „Das ist kein Problem Ihrer Sitzung." |
NOT_IMPLEMENTED |
501 | geplant, aber nicht gebaut. Wird angezeigt statt vorgetäuscht |