syncova-backup/docs/api.md
Jerrit Fritzsche 610719c316
Some checks failed
CI / Backend (Go) (push) Failing after 3m7s
CI / Frontend (React/TypeScript) (push) Successful in 37s
CI / Sicherheitsprüfungen (push) Successful in 44s
Syncova Backups V1
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>
2026-08-17 09:10:54 +02:00

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 |