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>
169 lines
7.1 KiB
Markdown
169 lines
7.1 KiB
Markdown
# 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
|
|
|
|
```json
|
|
{ "data": { "…": "…" }, "meta": { "request_id": "…" } }
|
|
```
|
|
|
|
```json
|
|
{ "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
|
|
|
|
```bash
|
|
curl -X POST https://<server>/api/v1/auth/login \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"username":"admin","password":"…"}'
|
|
```
|
|
|
|
```json
|
|
{ "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/verify` und `/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.overwrite` steckt **nicht** in `restores.execute`.
|
|
|
|
**Berechtigungen im Frontend sind Anzeige, keine Sicherung.** Sie verhindern
|
|
Sackgassen; geprüft wird auf dem Server.
|
|
|
|
## Seitenweise Ergebnisse
|
|
|
|
```text
|
|
GET /api/v1/backups?page=2&page_size=50
|
|
```
|
|
|
|
```json
|
|
{ "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/stream` ist 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 über `PATCH` mit 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 |
|