Přeskočit na obsah

Záloha, export a import

Všechno, co Control Center umí zkopírovat, předat nebo převzít, a přesný tvar každého artefaktu. Jak zálohu skutečně pořídit, je v Záloha a obnovení. Proč je ukládání rozdělené takhle, je v Pracovní prostory a izolace.

Existují tři artefakty ve formě kopie databáze, s různým rozsahem a různou politikou mazání.

Artefakt Zapisuje Tvar Pokrývá
Snímek instalace server.backupNow adresář s časovým razítkem všechny databáze na instalaci
Záloha pracovního prostoru pipeline Workspace backup adresář s časovým razítkem a jedním .db databáze jednoho pracovního prostoru
Export pracovního prostoru workspace.export jeden .db soubor databáze jednoho pracovního prostoru

Všechny se zapisují přes SQLite VACUUM INTO, což je bezpečné vůči živé databázi ve WAL: vezme čtecí transakci, vytvoří defragmentovanou a transakčně konzistentní kopii a server kvůli tomu není třeba zastavovat.

<dataDir>/backups/2026-07-28T09-12-33-000Z/
manifest.json
global.db
<workspaceId>/workspace.db one directory per workspace

Rozložení přesně zrcadlí živý datový adresář, a proto je obnova instalace zkopírování zpátky, ne převod. Jméno adresáře je časové razítko UTC, v němž jsou : a . nahrazené za -, takže je na Windows bezpečné pro souborový systém a jako obyčejný řetězec se řadí chronologicky.

Naplánované zálohy pracovního prostoru leží zvlášť v <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db. Nemají manifest ani global.db a nejsou to snímky instalace. Krok uchování v týdenní pipeline maže jen zálohy svého pracovního prostoru starší než nastavený věk (výchozí je 30 dní). Ten krok nikdy nerotuje ručně pořízené snímky instalace. server.listBackups vypisuje jen snímky instalace, včetně neúplných.

Pole Typ Význam
version celé číslo Verze formátu manifestu. Teď 1
created_at ISO-8601 UTC Kdy se snímek pořídil
global.file řetězec Vždy global.db
global.schema_version celé číslo Verze schématu GlobalDatabase v okamžiku zachycení
global.bytes celé číslo Velikost zapsaného global.db
workspace_schema_version celé číslo Verze schématu WorkspaceDatabase společná všem souborům pracovních prostorů
workspaces[] pole Jedna položka na zachycený pracovní prostor
workspaces[].workspace_id řetězec Pracovní prostor, který tenhle soubor drží
workspaces[].file řetězec Cesta relativní ke kořeni snímku, <workspaceId>/workspace.db
workspaces[].bytes celé číslo Velikost toho souboru
skipped_workspaces[] pole řetězců Pracovní prostory, které záloha nezachytila

Pracovní prostor se přeskočí, když je zaregistrovaný, ale ještě se do něj nezapsalo (soubor tedy zatím není), nebo když jeho VACUUM INTO selhalo. V obou případech se snímek stejně dokončí a manifest pojmenuje, co chybí.

server.listBackups hlásí u každého snímku příznak complete. Je nepravdivý, když manifest chybí nebo nejde rozebrat, když chybí global.db, nebo když manifest jmenuje soubor pracovního prostoru, který na disku není.

Neúplný snímek se pořád vypíše, protože snímek, který operátor nevidí, je snímek, o kterém věří, že ho má. Když manifest nejde přečíst, výpis se vrátí k samotnému rozložení a nahlásí ty soubory <workspaceId>/workspace.db, které najde. Ty se pořád dají převzít jednotlivě přes workspace.import, i když snímek jako celek instalaci neobnoví.

Oba artefakty jsou jen databáze. Adresář pracovního prostoru drží víc než svou databázi a nic z toho zbytku se nepřenáší:

Cesta Ve snímku? V exportu pracovního prostoru?
global.db Ano Ne
<workspaceId>/workspace.db Ano Ano (ten soubor to je)
<workspaceId>/blobs/ Ne Ne
<workspaceId>/skills/ Ne Ne
<workspaceId>/agents/ Ne Ne
<workspaceId>/chat_credentials/ Ne Ne
<workspaceId>/spaces/<spaceId>/ Ne Ne
<workspaceId>/pr_clones/ Ne Ne
secrets.json Ne Ne
models/ Ne Ne
meetings/<meetingId>/ Ne Ne
rigs/ Ne Ne

Část z toho se dá zahodit. spaces/ drží copy-on-write worktree a ty se znovu připraví z repozitářů, pr_clones/ je mezipaměť, models/ se stáhne znovu a rigs/ je stav stroje. Část ne: blobs/ drží vložené obrázky, na které ukazují řádky v databázi, skills/ a agents/ drží soubory, se kterými agent běží, a secrets.json drží každý klíč párování, přihlašovací údaje poskytovatele a nastavení SSO na instalaci. Zbytek pokrývá Záloha a obnovení.

RPC zálohy instalace a export a import pracovního prostoru jsou jen pro fullClient: spárovaný telefon je nespustí. Na serveru bez připojeného portu záloh, jako je demo server, chybí úplně. Neodmítají se, ve struktuře nejsou.

Operace Druh Rozsah Minimální role Argumenty Vrací
server.backupNow zápis Instalace vlastník instalace žádné {ok, path}
server.listBackups čtení Instalace vlastník instalace žádné {backups: [...]}
server.deleteBackup zápis Instalace vlastník instalace name {ok}
workspace.export čtení Pracovní prostor admin žádné {ok, path}
workspace.import zápis Pracovní prostor owner source_path {ok, workspace_id}
workspace.delete zápis Instalace* owner id řádek registru označený jako smazaný
  • workspace.delete je bez rozsahu, protože řádek, který označuje, žije v globálním registru. Jeho obsluha zkontroluje členství volajícího v pojmenovaném pracovním prostoru a vyžaduje owner.

path v každé odpovědi je cesta na hostiteli serveru.

Odpověď server.listBackups

Sekce “Odpověď server.listBackups”

Nejdřív nejnovější, seřazené podle jména adresáře. To je časové razítko, takže pořadí drží i u snímku, jehož manifest nešel přečíst.

{
"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 se vynechá, když manifest nešel přečíst. bytes na nejvyšší úrovni je skutečná velikost celého adresáře na disku, ne vlastní součet manifestu. Operátor, který snímky prořezává, se ptá, kolik adresář stojí, ne co záloha chtěla zapsat.

Každé workspaces[].path je přesně to, co workspace.import bere jako source_path. Je to schválně: „obnov tenhle pracovní prostor z tohohle snímku“ je operace importu, takže se obě nemůžou rozejít v tom, jak se stejným souborem naloží.

Ověření workspace.import

Sekce “Ověření workspace.import”

Než se cokoli nahradí, kandidátní soubor se otevře jen ke čtení krátkým syrovým spojením SQLite a přečte se jeho řádek workspace_meta.

Podmínka Výsledek
Není to čitelná databáze SQLite, nebo chybí workspace_meta Odmítnuto. Na nic se nesáhne
Zaznamenané id pracovního prostoru ≠ cíl Povoleno, zapsáno do logu. Takhle se pracovní prostor zduplikuje nebo obnoví pod novým id
Zaznamenané id instalace ≠ tahle instalace Povoleno, zapsáno do logu. Jeho spárovaná zařízení a id uživatelů patří té instalaci a tady se nevyřeší
Neplatné id pracovního prostoru, nebo soubor neexistuje Odmítnuto

Po přijetí se databáze cílového pracovního prostoru zavře a odpojí od správce databází, než se přes ni soubor zkopíruje (otevřené spojení Drift drží soubor i jeho -wal). Pak se znovu otevře, beforeOpen znovu nainstaluje spouštěče FTS a synchronizace a indexy FTS se přestaví. Tabulky obsahu v importovaném souboru jsou naplněné, ale jeho index může být zastaralý.

Každá operace výše mluví v cestách na straně serveru, a to je úplná odpověď jen tehdy, když je server tvůj vlastní stroj. Tyhle tři nesou bajty po stejné lince podepsané PSK, kterou používá proxy médií a úložiště blobů. Volající podepíše cílový řetězec předem sdíleným klíčem svého zařízení a podpis předá jako s.

Trasa Metoda Dotaz Podepsaný cíl Vyžaduje
/backup/workspace GET w, d, s backup-workspace:<workspaceId> admin pracovního prostoru
/backup/snapshot GET n, d, s backup-snapshot:<name> vlastník instalace
/backup/restore POST w, d, s backup-restore:<workspaceId> vlastník pracovního prostoru

w je id pracovního prostoru, n jméno adresáře snímku, d id volajícího zařízení a s podpis. n se vyřeší proti výpisu záloh, ne spojením cesty ke kořeni záloh, takže trasa nemůže mířit na adresář, který by výpis neukázal.

Stav Příčina
400 Chybí povinný parametr dotazu, nebo je tělo nahrání prázdné
403 Neznámé nebo odvolané zařízení, špatný podpis, nebo volající nemá roli
404 Na tomhle hostiteli není port záloh, nebo pojmenovaný snímek či soubor pracovního prostoru neexistuje
405 /backup/restore zavolané jinak než POST
413 Tělo nahrání přesahuje 8 GiB, podle deklarovaného content-length nebo podle bajtů, které se skutečně přečetly
500 Export nebo archiv selhal na straně serveru

Obě stažení odpovídají Cache-Control: no-store a Accept-Ranges: none. Každý požadavek vytvoří čerstvou kopii a po odstreamování ji smaže. Jinak se bajty ze dvou různých exportů slepí do jednoho souboru, ať už z mezipaměti, nebo z obnoveného rozsahu. Takový soubor vypadá platně a platný není.

/backup/snapshot vrací <name>.zip. Položky jsou relativní ke kořeni snímku, takže rozbalení zopakuje manifest.json + global.db + <workspaceId>/workspace.db. Položky se zapisují v seřazeném pořadí, takže dva archivy téhož snímku jsou tentýž archiv.

/backup/restore streamuje tělo rovnou do přípravného souboru a nebufferuje ho, omezí ho před čtením i během něj a přípravný soubor smaže na každé cestě ven, včetně odmítnutí.

Věc Hodnota
Snímky <dataDir>/backups/<timestamp>/
Naplánované zálohy pracovního prostoru <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db
Exporty pracovního prostoru <dataDir>/backups/exports/<workspaceId>-<timestamp>.db
Příprava přenosu <dataDir>/backups/transfer/ — mezisklad, který uklidí trasa, jež do něj zapisuje
Jméno archivu snímku <snapshot directory name>.zip
Strop nahrání 8 GiB na POST /backup/restore
Uchování Snímky instalace: ruční smazání. Zálohy pracovního prostoru: týdenní pipeline, výchozí 30 dní

Adresáře exports/, transfer/ a workspace-backups/ nejsou snímky instalace a server.listBackups je vynechává. Naplánované uchování má jen poslední z nich. Smazání snímku instalace vyžaduje výslovný zásah vlastníka instalace.