Backup, Export und Import
Alles, was Control Center kopieren, übergeben oder übernehmen kann, und die genaue Form jedes Artefakts. Wie du tatsächlich eine Sicherung anlegst, steht unter Sichern und wiederherstellen. Warum die Persistenz so aufgeteilt ist, steht unter Arbeitsbereiche und Isolation.
Artefakte
Abschnitt betitelt „Artefakte“Es gibt drei Artefakte, die eine Datenbank kopieren, mit unterschiedlichem Geltungsbereich und unterschiedlicher Löschregel.
| Artefakt | Geschrieben von | Form | Umfang |
|---|---|---|---|
| Momentaufnahme der Installation | server.backupNow |
Ein Verzeichnis mit Zeitstempel | Jede Datenbank der Installation |
| Arbeitsbereichssicherung | Pipeline Workspace backup |
Verzeichnis mit Zeitstempel und einer .db |
Die Datenbank eines Arbeitsbereichs |
| Arbeitsbereichs-Export | workspace.export |
Eine einzelne .db-Datei |
Die Datenbank eines Arbeitsbereichs |
Alle werden mit SQLite VACUUM INTO geschrieben. Das ist gegen eine laufende WAL-Datenbank sicher:
es nimmt eine Lesetransaktion, erzeugt eine defragmentierte und transaktional konsistente
Kopie und verlangt nie, den Server anzuhalten.
Layout der Momentaufnahme
Abschnitt betitelt „Layout der Momentaufnahme“<dataDir>/backups/2026-07-28T09-12-33-000Z/ manifest.json global.db <workspaceId>/workspace.db one directory per workspaceDas Layout spiegelt das laufende Datenverzeichnis genau. Deshalb ist das Wiederherstellen einer
Installation ein Zurückkopieren und keine Umwandlung. Der Verzeichnisname ist der UTC-Zeitstempel,
in dem : und . durch - ersetzt sind. So ist er auf Windows dateisystemsicher und sortiert
als bloße Zeichenkette chronologisch.
Geplante Arbeitsbereichssicherungen liegen getrennt unter
<dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db.
Sie enthalten kein Manifest und kein global.db und sind keine Momentaufnahmen der Installation.
Der Aufbewahrungsschritt der wöchentlichen Pipeline entfernt nur Sicherungen des eigenen Arbeitsbereichs,
die älter sind als das konfigurierte Alter (standardmäßig 30 Tage). Manuell erstellte Momentaufnahmen
der Installation fasst dieser Schritt nie an. server.listBackups listet nur Momentaufnahmen der
Installation, auch unvollständige.
manifest.json
Abschnitt betitelt „manifest.json“| Feld | Typ | Bedeutung |
|---|---|---|
version |
Ganzzahl | Version des Manifest-Formats. Derzeit 1 |
created_at |
ISO-8601 UTC | Wann die Momentaufnahme erstellt wurde |
global.file |
Zeichenkette | Immer global.db |
global.schema_version |
Ganzzahl | Schemaversion von GlobalDatabase zum Zeitpunkt der Erfassung |
global.bytes |
Ganzzahl | Größe der geschriebenen global.db |
workspace_schema_version |
Ganzzahl | Schemaversion von WorkspaceDatabase, die jede Arbeitsbereichsdatei teilt |
workspaces[] |
Array | Ein Eintrag je erfasstem Arbeitsbereich |
workspaces[].workspace_id |
Zeichenkette | Der Arbeitsbereich, den diese Datei enthält |
workspaces[].file |
Zeichenkette | Pfad relativ zur Wurzel der Momentaufnahme, <workspaceId>/workspace.db |
workspaces[].bytes |
Ganzzahl | Größe dieser Datei |
skipped_workspaces[] |
Array aus Zeichenketten | Arbeitsbereiche, die die Sicherung nicht erfassen konnte |
Ein Arbeitsbereich wird übersprungen, wenn er registriert, aber noch nie beschrieben wurde (es gibt
also noch keine Datei), oder wenn sein VACUUM INTO fehlgeschlagen ist. In beiden Fällen wird die
Momentaufnahme trotzdem fertig, und das Manifest nennt, was fehlt.
Vollständigkeit
Abschnitt betitelt „Vollständigkeit“server.listBackups meldet je Momentaufnahme ein Flag complete. Es ist falsch, wenn das
Manifest fehlt oder sich nicht parsen lässt, wenn global.db fehlt, oder wenn das Manifest
eine Arbeitsbereichsdatei nennt, die nicht auf der Platte liegt.
Eine unvollständige Momentaufnahme steht trotzdem in der Liste. Eine Momentaufnahme, die du nicht
siehst, ist eine, von der du glaubst, sie zu haben. Lässt sich das Manifest nicht lesen, fällt die
Auflistung auf das Layout selbst zurück und meldet die <workspaceId>/workspace.db-Dateien, die sie
findet. Die lassen sich weiterhin einzeln über workspace.import übernehmen, auch wenn die
Momentaufnahme als Ganzes eine Installation nicht wiederherstellen kann.
Was eine Sicherung nicht enthält
Abschnitt betitelt „Was eine Sicherung nicht enthält“Beide Artefakte sind nur Datenbanken. Ein Arbeitsbereichsverzeichnis hält mehr als seine Datenbank, und nichts vom Rest geht mit:
| Pfad | In einer Momentaufnahme? | In einem Arbeitsbereichs-Export? |
|---|---|---|
global.db |
Ja | Nein |
<workspaceId>/workspace.db |
Ja | Ja (sie ist die Datei) |
<workspaceId>/blobs/ |
Nein | Nein |
<workspaceId>/skills/ |
Nein | Nein |
<workspaceId>/agents/ |
Nein | Nein |
<workspaceId>/chat_credentials/ |
Nein | Nein |
<workspaceId>/spaces/<spaceId>/ |
Nein | Nein |
<workspaceId>/pr_clones/ |
Nein | Nein |
secrets.json |
Nein | Nein |
models/ |
Nein | Nein |
meetings/<meetingId>/ |
Nein | Nein |
rigs/ |
Nein | Nein |
Einiges davon ist entbehrlich. spaces/ hält Copy-on-Write-Worktrees, die aus den Repos neu
bereitgestellt werden, pr_clones/ ist ein Cache, models/ wird neu heruntergeladen, rigs/
ist Maschinenzustand. Anderes nicht: blobs/ hält eingefügte Bilder, auf die Zeilen in der
Datenbank zeigen, skills/ und agents/ halten die Dateien, mit denen ein Agent läuft, und
secrets.json hält jeden Kopplungsschlüssel, alle Anbieter-Zugangsdaten und alle SSO-Einstellungen der
Installation. Den Rest deckt Sichern und wiederherstellen ab.
Operationen
Abschnitt betitelt „Operationen“Die RPCs für die Sicherung der Installation sowie Export und Import eines Arbeitsbereichs gibt es nur für fullClient: ein gekoppeltes
Telefon kann sie nicht auslösen. Auf einem Server ohne verdrahteten Backup-Port, etwa dem Demo-Server,
fehlen sie ganz. Sie werden nicht abgelehnt, sie sind strukturell nicht da.
| Operation | Art | Geltungsbereich | Mindestrolle | Argumente | Rückgabe |
|---|---|---|---|---|---|
server.backupNow |
Schreiben | Installation | Eigentümer der Installation | keine | {ok, path} |
server.listBackups |
Lesen | Installation | Eigentümer der Installation | keine | {backups: [...]} |
server.deleteBackup |
Schreiben | Installation | Eigentümer der Installation | name |
{ok} |
workspace.export |
Lesen | Arbeitsbereich | admin |
keine | {ok, path} |
workspace.import |
Schreiben | Arbeitsbereich | owner |
source_path |
{ok, workspace_id} |
workspace.delete |
Schreiben | Installation* | owner |
id |
Registry-Zeile als gelöscht markiert |
workspace.deletehat keinen Geltungsbereich, weil die Zeile, die es markiert, in der globalen Registry lebt. Der Handler prüft die Mitgliedschaft des Aufrufers im genannten Arbeitsbereich und verlangtowner.
path in jeder Antwort ist ein Pfad auf dem Server-Host.
Antwort von server.listBackups
Abschnitt betitelt „Antwort von server.listBackups“Neueste zuerst, sortiert nach Verzeichnisnamen. Der Name ist der Zeitstempel, die Reihenfolge hält also auch bei einer Momentaufnahme, deren Manifest sich nicht lesen ließ.
{ "backups": [ { "path": "/…/backups/2026-07-28T09-12-33-000Z", "name": "2026-07-28T09-12-33-000Z", "created_at": "2026-07-28T09:12:33.000Z", "bytes": 481203712, "complete": true, "workspaces": [ { "workspace_id": "w_9f2c…", "path": "/…/backups/2026-07-28T09-12-33-000Z/w_9f2c…/workspace.db", "bytes": 190840832 } ], "skipped_workspace_ids": [] } ]}created_at fehlt, wenn sich das Manifest nicht lesen ließ. bytes auf der obersten Ebene ist
die echte Größe des ganzen Verzeichnisses auf der Platte, nicht die eigene Summe des Manifests. Wer
Momentaufnahmen ausdünnt, fragt, was das Verzeichnis kostet, nicht was die Sicherung schreiben wollte.
Jedes workspaces[].path ist genau das, was workspace.import als source_path nimmt. Das
ist Absicht: „diesen Arbeitsbereich aus dieser Momentaufnahme wiederherstellen“ ist die Import-Operation, die beiden
können also nicht auseinanderlaufen in der Behandlung derselben Datei.
Prüfung von workspace.import
Abschnitt betitelt „Prüfung von workspace.import“Bevor irgendetwas ersetzt wird, wird die Kandidatendatei schreibgeschützt mit einer kurzlebigen
rohen SQLite-Verbindung geöffnet und ihre Zeile workspace_meta gelesen.
| Bedingung | Ergebnis |
|---|---|
Keine lesbare SQLite-Datenbank, oder kein workspace_meta |
Abgelehnt. Nichts wird angefasst |
| Aufgezeichnete Arbeitsbereichs-ID ≠ das Ziel | Erlaubt, protokolliert. So wird ein Arbeitsbereich dupliziert oder unter einer neuen ID wiederhergestellt |
| Aufgezeichnete Installations-ID ≠ diese Installation | Erlaubt, protokolliert. Die gekoppelten Geräte und Benutzer-IDs gehören zu jener Installation und lösen sich hier nicht auf |
| Ungültige Arbeitsbereichs-ID, oder die Datei existiert nicht | Abgelehnt |
Nach der Annahme wird die Datenbank des Ziel-Arbeitsbereichs geschlossen und aus dem Manager genommen,
bevor die Datei darüber kopiert wird (eine offene Drift-Verbindung hält die Datei und ihre
-wal). Danach wird sie neu geöffnet, damit beforeOpen die FTS- und Sync-Trigger neu anlegt, und die FTS-
Indizes werden neu aufgebaut. Die Inhaltstabellen einer importierten Datei sind gefüllt, ihr Index kann
aber veraltet sein.
Transfer-Routen
Abschnitt betitelt „Transfer-Routen“Jede Operation oben spricht in serverseitigen Pfaden, und das ist nur dann eine vollständige Antwort, wenn der
Server dein eigener Rechner ist. Diese drei tragen die Bytes, auf derselben mit PSK signierten Bahn, die der
Medien-Proxy und der Blob-Speicher nutzen. Der Aufrufer signiert eine Zielzeichenkette mit dem vorab geteilten Schlüssel seines Geräts
und übergibt die Signatur als s.
| Route | Methode | Query | Signiertes Ziel | Erfordert |
|---|---|---|---|---|
/backup/workspace |
GET | w, d, s |
backup-workspace:<workspaceId> |
Admin des Arbeitsbereichs |
/backup/snapshot |
GET | n, d, s |
backup-snapshot:<name> |
Eigentümer der Installation |
/backup/restore |
POST | w, d, s |
backup-restore:<workspaceId> |
Eigentümer des Arbeitsbereichs |
w ist eine Arbeitsbereichs-ID, n der Verzeichnisname einer Momentaufnahme, d die Geräte-ID des Aufrufers, s die
Signatur. n wird gegen die Sicherungsliste aufgelöst und nicht an die Wurzel der Sicherungen
gehängt, die Route lässt sich also nicht auf ein Verzeichnis richten, das die Liste nicht gezeigt hätte.
| Status | Ursache |
|---|---|
400 |
Ein erforderlicher Query-Parameter fehlt, oder der Upload-Body ist leer |
403 |
Unbekanntes oder widerrufenes Gerät, ungültige Signatur, oder dem Aufrufer fehlt die Rolle |
404 |
Kein Backup-Port auf diesem Host, oder die genannte Momentaufnahme bzw. Arbeitsbereichsdatei existiert nicht |
405 |
/backup/restore mit etwas anderem als POST aufgerufen |
413 |
Der Upload-Body überschreitet 8 GiB, nach deklariertem content-length oder nach den Bytes, die tatsächlich gelesen wurden |
500 |
Export oder Archiv ist serverseitig fehlgeschlagen |
Beide Downloads antworten mit Cache-Control: no-store und Accept-Ranges: none. Jede Anfrage
erzeugt eine frische Kopie und löscht sie, sobald sie gestreamt ist. Eine gecachte oder fortgesetzte Antwort
würde Bytes aus zwei verschiedenen Exporten zu einer Datei zusammenfügen, die gültig aussieht und es nicht ist.
/backup/snapshot liefert <name>.zip. Die Einträge liegen relativ zur Wurzel der Momentaufnahme, das
Entpacken stellt also manifest.json + global.db + <workspaceId>/workspace.db wieder her.
Die Einträge werden in sortierter Reihenfolge geschrieben, zwei Archive derselben Momentaufnahme sind also dasselbe
Archiv.
/backup/restore streamt den Body direkt in eine Staging-Datei, statt ihn zu puffern,
begrenzt ihn vor dem Lesen und währenddessen und löscht die bereitgestellte Datei auf jedem Weg nach draußen,
auch bei einer Ablehnung.
Pfade und Grenzen
Abschnitt betitelt „Pfade und Grenzen“| Eintrag | Wert |
|---|---|
| Momentaufnahmen | <dataDir>/backups/<timestamp>/ |
| Geplante Arbeitsbereichssicherungen | <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db |
| Arbeitsbereichs-Exporte | <dataDir>/backups/exports/<workspaceId>-<timestamp>.db |
| Transfer-Bereitstellung | <dataDir>/backups/transfer/ — eine Werkbank, die die Route wegräumt, die hineinschreibt |
| Archivname der Momentaufnahme | <snapshot directory name>.zip |
| Upload-Obergrenze | 8 GiB je POST /backup/restore |
| Aufbewahrung | Momentaufnahmen der Installation: manuelles Löschen. Arbeitsbereichssicherungen: wöchentliche Pipeline, Standard 30 Tage |
Die Verzeichnisse exports/, transfer/ und workspace-backups/ sind keine
Momentaufnahmen der Installation und fehlen in server.listBackups. Nur das letzte
Verzeichnis hat eine geplante Aufbewahrung. Eine Momentaufnahme der Installation zu löschen braucht die
ausdrückliche Handlung des Eigentümers der Installation.
Siehe auch
Abschnitt betitelt „Siehe auch“- Sichern und wiederherstellen: die Abläufe, zu denen diese Operationen gehören
- Arbeitsbereiche und Isolation: warum ein Arbeitsbereich eine Datei ist
cc_serverCLI: das Datenverzeichnis, in dem diese Pfade liegen- Routenkarte: wo die Oberfläche liegt
- Architektur: die Aufteilung von Client und Server, der diese Pfade folgen