Salta ai contenuti

Backup, esportazione e importazione

Tutto ciò che Control Center può copiare, cedere o adottare, e la forma esatta di ogni artefatto. Per creare davvero un backup, vedi Backup e ripristino; per capire perché la persistenza è suddivisa in questo modo, vedi Spazi di lavoro e isolamento.

Esistono tre artefatti di copia del database, con ambiti e politiche di eliminazione diversi.

Artefatto Scritto da Forma Copre
Istantanea dell’installazione server.backupNow Una directory con data e ora Tutti i database dell’installazione
Backup dello spazio di lavoro pipeline Workspace backup Directory con data e ora con un solo .db Il database di uno spazio di lavoro
Esportazione dello spazio di lavoro workspace.export Un singolo file .db Il database di uno spazio di lavoro

Tutti vengono scritti con VACUUM INTO di SQLite, che è sicuro su un database WAL in uso: apre una transazione di lettura, produce una copia deframmentata e transazionalmente coerente e non richiede mai di fermare il server.

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

La struttura rispecchia esattamente la directory dei dati attiva, ed è ciò che rende il ripristino di un’installazione una copia di ritorno anziché una traduzione. Il nome della directory è la data e ora UTC con : e . sostituiti da -, quindi è sicuro per i filesystem di Windows e si ordina cronologicamente come semplice stringa.

I backup pianificati degli spazi di lavoro vivono separatamente in <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db. Non includono un manifest né global.db e non sono istantanee dell’installazione. Il passaggio di conservazione della pipeline settimanale elimina solo i backup del proprio spazio di lavoro più vecchi dell’età configurata (30 giorni per impostazione predefinita); le istantanee dell’installazione create manualmente non vengono mai ruotate da quel passaggio. server.listBackups elenca solo le istantanee dell’installazione, comprese quelle incomplete.

Campo Tipo Significato
version int Versione del formato del manifest. Attualmente 1
created_at ISO-8601 UTC Quando l’istantanea è stata scattata
global.file stringa Sempre global.db
global.schema_version int Versione dello schema di GlobalDatabase al momento dell’acquisizione
global.bytes int Dimensione del global.db scritto
workspace_schema_version int Versione dello schema di WorkspaceDatabase condivisa da ogni file di spazio di lavoro
workspaces[] array Una voce per ogni spazio di lavoro acquisito
workspaces[].workspace_id stringa Lo spazio di lavoro contenuto in questo file
workspaces[].file stringa Percorso relativo alla radice dell’istantanea, <workspaceId>/workspace.db
workspaces[].bytes int Dimensione di quel file
skipped_workspaces[] array di stringhe Spazi di lavoro che il backup non è riuscito ad acquisire

Uno spazio di lavoro viene saltato quando è registrato ma non vi è mai stato scritto nulla (quindi il file non esiste ancora), oppure quando il suo VACUUM INTO non è riuscito. In entrambi i casi l’istantanea viene comunque completata e il manifest indica ciò che manca.

server.listBackups riporta un flag complete per ogni istantanea. È false quando il manifest è assente o non analizzabile, quando global.db manca, o quando il manifest nomina un file di spazio di lavoro che non è su disco.

Un’istantanea incompleta viene comunque elencata, perché un’istantanea che un operatore non vede è un’istantanea che crede di avere. Quando il manifest non è leggibile, l’elenco ripiega sulla struttura stessa e riporta tutti i file <workspaceId>/workspace.db che trova: quelli restano adottabili singolarmente tramite workspace.import, anche se l’istantanea nel suo complesso non può ripristinare un’installazione.

Entrambi gli artefatti sono solo database. La directory di uno spazio di lavoro contiene più del suo database, e niente del resto viaggia:

Percorso In un’istantanea? In un’esportazione dello spazio di lavoro?
global.db Sì No
<workspaceId>/workspace.db Sì Sì (è proprio il file)
<workspaceId>/blobs/ No No
<workspaceId>/skills/ No No
<workspaceId>/agents/ No No
<workspaceId>/chat_credentials/ No No
<workspaceId>/spaces/<spaceId>/ No No
<workspaceId>/pr_clones/ No No
secrets.json No No
models/ No No
meetings/<meetingId>/ No No
rigs/ No No

Una parte è usa e getta: spaces/ contiene worktree copy-on-write che vengono riprovisionati dai repo, pr_clones/ è una cache, models/ viene riscaricato, rigs/ è stato della macchina. Una parte no: blobs/ contiene le immagini incollate a cui puntano le righe del database, skills/ e agents/ contengono i file con cui viene eseguito un agente, e secrets.json contiene ogni chiave di associazione, credenziale di fornitore e impostazione SSO dell’installazione. Vedi Backup e ripristino per coprire il resto.

Gli RPC di backup dell’installazione e l’esportazione/importazione degli spazi di lavoro sono riservati ai fullClient: un telefono associato non può attivarli. Su un server senza porta di backup cablata, come il server demo, sono del tutto assenti — non rifiutati, ma strutturalmente mancanti.

Operazione Tipo Ambito Ruolo minimo Argomenti Restituisce
server.backupNow mutazione Installazione proprietario dell’installazione nessuno {ok, path}
server.listBackups lettura Installazione proprietario dell’installazione nessuno {backups: [...]}
server.deleteBackup mutazione Installazione proprietario dell’installazione name {ok}
workspace.export lettura Spazio di lavoro admin nessuno {ok, path}
workspace.import mutazione Spazio di lavoro owner source_path {ok, workspace_id}
workspace.delete mutazione Installazione* owner id riga di registro contrassegnata come eliminata
  • workspace.delete non ha ambito perché la riga che contrassegna vive nel registro globale; il suo handler verifica l’appartenenza del chiamante allo spazio di lavoro indicato e richiede owner.

path in ogni risposta è un percorso sull’host del server.

Dalla più recente, ordinate per nome della directory (che è la data e ora, quindi l’ordine vale anche per un’istantanea il cui manifest non è stato leggibile).

{
"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 viene omesso quando il manifest non è stato leggibile. bytes al livello superiore è la dimensione reale su disco dell’intera directory, non la somma del manifest: la domanda che si pone un operatore che ripulisce le istantanee è quanto costa la directory, non quanto il backup intendeva scrivere.

Ogni workspaces[].path è esattamente ciò che workspace.import accetta come source_path. È deliberato: «ripristina questo spazio di lavoro da questa istantanea» è l’operazione di importazione, quindi le due non possono divergere in trattamenti diversi dello stesso file.

Prima che qualsiasi cosa venga sostituita, il file candidato viene aperto in sola lettura con una connessione SQLite grezza di breve durata e viene letta la sua riga workspace_meta.

Condizione Risultato
Non è un database SQLite leggibile, o manca workspace_meta Rifiutato. Non viene toccato nulla
Id di spazio di lavoro registrato ≠ quello di destinazione Consentito, registrato nei log. È così che uno spazio di lavoro viene duplicato o ripristinato sotto un nuovo id
Id dell’installazione registrato ≠ quello di questa installazione Consentito, registrato nei log. I suoi dispositivi associati e gli id utente appartengono a quell’installazione e non si risolveranno qui
Id di spazio di lavoro non valido, o file inesistente Rifiutato

In caso di accettazione, il database dello spazio di lavoro di destinazione viene chiuso e rimosso dal manager prima che il file vi venga copiato sopra (una connessione drift aperta tiene il file e il suo -wal), poi riaperto così che beforeOpen reinstalli i trigger FTS e di sincronizzazione, e gli indici FTS vengono ricostruiti: le tabelle dei contenuti di un file importato sono popolate, ma il suo indice può essere obsoleto.

Ogni operazione qui sopra parla in termini di percorsi lato server, il che è una risposta completa solo quando il server è la tua macchina. Queste tre trasportano i byte, sullo stesso canale firmato con PSK che usano il proxy dei media e il blob store. Il chiamante firma una stringa di destinazione con la chiave pre-condivisa del suo dispositivo e passa la firma come s.

Route Metodo Query Destinazione firmata Richiede
/backup/workspace GET w, d, s backup-workspace:<workspaceId> admin dello spazio di lavoro
/backup/snapshot GET n, d, s backup-snapshot:<name> proprietario dell’installazione
/backup/restore POST w, d, s backup-restore:<workspaceId> proprietario dello spazio di lavoro

w è un id di spazio di lavoro, n un nome di directory di istantanea, d l’id del dispositivo chiamante, s la firma. n viene risolto rispetto all’elenco dei backup anziché concatenato alla radice dei backup, quindi la route non può essere puntata su una directory che l’elenco non avrebbe mostrato.

Stato Causa
400 Manca un parametro di query obbligatorio, o il corpo di un caricamento è vuoto
403 Dispositivo sconosciuto o revocato, firma non valida, o il chiamante non ha il ruolo
404 Nessuna porta di backup su questo host, o il file di istantanea/spazio di lavoro indicato non esiste
405 /backup/restore chiamato con un metodo diverso da POST
413 Il corpo del caricamento supera gli 8 GiB, per content-length dichiarato o per byte effettivamente letti
500 L’esportazione o l’archiviazione non è riuscita lato server

Entrambi i download rispondono con Cache-Control: no-store e Accept-Ranges: none. Ogni richiesta genera una copia nuova e la elimina dopo averla trasmessa in streaming, quindi una risposta in cache o ripresa unirebbe i byte di due esportazioni diverse in un unico file che sembra valido e non lo è.

/backup/snapshot restituisce <name>.zip, con voci relative alla radice dell’istantanea, così l’estrazione riproduce manifest.json + global.db + <workspaceId>/workspace.db. Le voci vengono scritte in ordine, quindi due archivi della stessa istantanea sono lo stesso archivio.

/backup/restore trasmette il corpo direttamente in un file temporaneo anziché bufferizzarlo, lo limita prima e durante la lettura, ed elimina il file temporaneo su ogni percorso di uscita, compreso un rifiuto.

Elemento Valore
Istantanee <dataDir>/backups/<timestamp>/
Backup pianificati degli spazi di lavoro <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db
Esportazioni degli spazi di lavoro <dataDir>/backups/exports/<workspaceId>-<timestamp>.db
Staging dei trasferimenti <dataDir>/backups/transfer/ — un banco di lavoro, ripulito dalla route che lo scrive
Nome dell’archivio dell’istantanea <snapshot directory name>.zip
Limite di caricamento 8 GiB per POST /backup/restore
Conservazione Istantanee dell’installazione: eliminazione manuale. Backup degli spazi di lavoro: pipeline settimanale, 30 giorni per impostazione predefinita

Le directory exports/, transfer/ e workspace-backups/ non sono istantanee dell’installazione e sono escluse da server.listBackups. Solo l’ultima directory ha una conservazione pianificata; l’eliminazione di un’istantanea dell’installazione richiede l’azione esplicita del proprietario dell’installazione.