Cadangan, ekspor, dan impor
Semua yang bisa disalin, diserahkan, atau diadopsi Control Center, beserta bentuk persis setiap artefaknya. Untuk benar-benar membuat cadangan, lihat Cadangkan dan pulihkan; untuk alasan persistensi dipisah seperti ini, lihat Ruang kerja dan isolasi.
Artefak
Bagian berjudul “Artefak”Ada tiga artefak salinan basis data, dengan cakupan dan kebijakan penghapusan yang berbeda.
| Artefak | Ditulis oleh | Bentuk | Cakupan |
|---|---|---|---|
| Snapshot instalasi | server.backupNow |
Direktori bertanda waktu | Setiap basis data di instalasi |
| Cadangan ruang kerja | Pipeline Workspace backup |
Direktori bertanda waktu dengan satu .db |
Basis data satu ruang kerja |
| Ekspor ruang kerja | workspace.export |
Satu file .db |
Basis data satu ruang kerja |
Semuanya ditulis dengan VACUUM INTO SQLite, yang aman terhadap basis data WAL yang
aktif: perintah ini mengambil transaksi baca, menghasilkan salinan yang didefragmentasi
dan konsisten secara transaksional, serta tidak pernah memerlukan penghentian server.
Tata letak snapshot
Bagian berjudul “Tata letak snapshot”<dataDir>/backups/2026-07-28T09-12-33-000Z/ manifest.json global.db <workspaceId>/workspace.db one directory per workspaceTata letaknya mencerminkan direktori data aktif dengan persis, itulah yang membuat
pemulihan sebuah instalasi sekadar menyalin kembali, bukan menerjemahkan. Nama
direktorinya adalah stempel waktu UTC dengan : dan . diganti -, jadi aman untuk
sistem berkas di Windows dan terurut secara kronologis sebagai string biasa.
Cadangan ruang kerja terjadwal berada terpisah di
<dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db.
Cadangan itu tidak menyertakan manifest atau global.db dan bukan snapshot instalasi.
Langkah retensi pipeline mingguan hanya menghapus cadangan ruang kerjanya sendiri
yang lebih tua dari usia yang dikonfigurasi (bawaannya 30 hari); snapshot instalasi
yang dibuat secara manual tidak pernah dipangkas oleh langkah itu. server.listBackups
hanya mendaftarkan snapshot instalasi, termasuk yang tidak lengkap.
manifest.json
Bagian berjudul “manifest.json”| Kolom | Tipe | Arti |
|---|---|---|
version |
int | Versi format manifest. Saat ini 1 |
created_at |
ISO-8601 UTC | Kapan snapshot diambil |
global.file |
string | Selalu global.db |
global.schema_version |
int | Versi skema GlobalDatabase pada saat perekaman |
global.bytes |
int | Ukuran global.db yang ditulis |
workspace_schema_version |
int | Versi skema WorkspaceDatabase yang sama untuk setiap file ruang kerja |
workspaces[] |
array | Satu entri per ruang kerja yang terekam |
workspaces[].workspace_id |
string | Ruang kerja yang dimuat file ini |
workspaces[].file |
string | Path relatif terhadap akar snapshot, <workspaceId>/workspace.db |
workspaces[].bytes |
int | Ukuran file itu |
skipped_workspaces[] |
array of string | Ruang kerja yang tidak bisa direkam oleh cadangan |
Sebuah ruang kerja dilewati ketika ruang kerja itu terdaftar tetapi belum pernah
ditulisi (jadi filenya belum ada), atau ketika VACUUM INTO-nya gagal. Dengan cara apa
pun, snapshot tetap selesai dan manifest menyebutkan apa yang hilang.
Kelengkapan
Bagian berjudul “Kelengkapan”server.listBackups melaporkan flag complete per snapshot. Flag itu bernilai false
ketika manifest tidak ada atau tidak bisa diurai, ketika global.db hilang, atau ketika
manifest menyebut file ruang kerja yang tidak ada di disk.
Snapshot yang tidak lengkap tetap didaftarkan, karena snapshot yang tidak bisa dilihat
operator adalah snapshot yang mereka yakini mereka miliki. Ketika manifest tidak bisa
dibaca, daftar itu beralih ke tata letak itu sendiri dan melaporkan file
<workspaceId>/workspace.db apa pun yang ditemukannya — file-file itu tetap bisa
diadopsi satu per satu melalui workspace.import meskipun snapshot secara keseluruhan
tidak bisa memulihkan instalasi.
Apa yang tidak dimuat cadangan
Bagian berjudul “Apa yang tidak dimuat cadangan”Kedua artefak itu hanya basis data. Direktori ruang kerja memuat lebih dari sekadar basis datanya, dan tidak ada bagian lain yang ikut berpindah:
| Path | Ada di snapshot? | Ada di ekspor ruang kerja? |
|---|---|---|
global.db |
Ya | Tidak |
<workspaceId>/workspace.db |
Ya | Ya (itulah filenya) |
<workspaceId>/blobs/ |
Tidak | Tidak |
<workspaceId>/skills/ |
Tidak | Tidak |
<workspaceId>/agents/ |
Tidak | Tidak |
<workspaceId>/chat_credentials/ |
Tidak | Tidak |
<workspaceId>/spaces/<spaceId>/ |
Tidak | Tidak |
<workspaceId>/pr_clones/ |
Tidak | Tidak |
secrets.json |
Tidak | Tidak |
models/ |
Tidak | Tidak |
meetings/<meetingId>/ |
Tidak | Tidak |
rigs/ |
Tidak | Tidak |
Sebagian dari itu bisa dibuang — spaces/ menyimpan worktree copy-on-write yang
disediakan ulang dari repo, pr_clones/ adalah cache, models/ diunduh ulang, rigs/
adalah status mesin. Sebagiannya lagi tidak: blobs/ menyimpan gambar yang ditempelkan
dan dirujuk baris-baris di basis data, skills/ dan agents/ menyimpan file yang dipakai
agen untuk berjalan, dan secrets.json menyimpan setiap kunci pemasangan, kredensial
penyedia, dan pengaturan SSO di instalasi. Lihat
Cadangkan dan pulihkan
untuk menutupi sisanya.
Operasi
Bagian berjudul “Operasi”RPC cadangan instalasi dan ekspor/impor ruang kerja hanya untuk fullClient: ponsel yang
dipasangkan tidak bisa memicunya. Semuanya sama sekali tidak ada — bukan ditolak,
melainkan tidak ada secara struktural — pada server yang tidak memiliki port cadangan,
seperti server demo.
| Operasi | Jenis | Cakupan | Peran minimum | Argumen | Hasil |
|---|---|---|---|---|---|
server.backupNow |
mutasi | Instalasi | pemilik instalasi | tidak ada | {ok, path} |
server.listBackups |
baca | Instalasi | pemilik instalasi | tidak ada | {backups: [...]} |
server.deleteBackup |
mutasi | Instalasi | pemilik instalasi | name |
{ok} |
workspace.export |
baca | Ruang kerja | admin |
tidak ada | {ok, path} |
workspace.import |
mutasi | Ruang kerja | owner |
source_path |
{ok, workspace_id} |
workspace.delete |
mutasi | Instalasi* | owner |
id |
baris pendaftaran ditandai terhapus |
workspace.deletetidak bercakupan karena baris yang ditandainya berada di pendaftaran global; handler-nya memeriksa keanggotaan pemanggil pada ruang kerja yang disebut dan mewajibkanowner.
path di setiap respons adalah path di host server.
Respons server.listBackups
Bagian berjudul “Respons server.listBackups”Terbaru lebih dulu, diurutkan berdasarkan nama direktori (yang merupakan stempel waktu, jadi urutannya tetap berlaku bahkan untuk snapshot yang manifest-nya tidak bisa dibaca).
{ "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 dihilangkan ketika manifest tidak bisa dibaca. bytes di tingkat teratas
adalah ukuran nyata di disk dari seluruh direktori, bukan jumlah dari manifest itu
sendiri — pertanyaan yang diajukan operator yang memangkas snapshot adalah berapa biaya
direktori itu, bukan berapa yang dimaksudkan untuk ditulis oleh cadangan.
Setiap workspaces[].path persisnya adalah nilai yang diterima workspace.import
sebagai source_path. Itu memang sengaja: “memulihkan ruang kerja ini dari snapshot ini”
adalah operasi impor, jadi keduanya tidak bisa menyimpang menjadi perlakuan yang
berbeda terhadap file yang sama.
Validasi workspace.import
Bagian berjudul “Validasi workspace.import”Sebelum apa pun diganti, file kandidat dibuka dalam mode hanya baca dengan koneksi SQLite
mentah yang berumur pendek dan baris workspace_meta-nya dibaca.
| Kondisi | Hasil |
|---|---|
Bukan basis data SQLite yang bisa dibaca, atau tidak ada workspace_meta |
Ditolak. Tidak ada yang disentuh |
| Id ruang kerja yang tercatat ≠ target | Diizinkan, dicatat di log. Beginilah ruang kerja diduplikasi atau dipulihkan dengan id baru |
| Id instalasi yang tercatat ≠ instalasi ini | Diizinkan, dicatat di log. Perangkat yang dipasangkan dan id pengguna milik instalasi itu tidak akan dikenali di sini |
| Id ruang kerja tidak valid, atau file tidak ada | Ditolak |
Saat diterima, basis data ruang kerja tujuan ditutup dan dilepas dari pengelola sebelum
file disalin menimpanya (koneksi drift yang terbuka memegang file itu beserta -wal-nya),
lalu dibuka kembali sehingga beforeOpen memasang ulang pemicu FTS dan sinkronisasi, dan
indeks FTS dibangun ulang — tabel konten file yang diimpor terisi, tetapi indeksnya
mungkin sudah usang.
Rute transfer
Bagian berjudul “Rute transfer”Setiap operasi di atas berbicara dalam path sisi server, yang merupakan jawaban lengkap
hanya ketika server itu mesin Anda sendiri. Ketiga rute ini yang membawa byte-nya, di
jalur bertanda tangan PSK yang sama dengan yang dipakai proksi media dan penyimpanan blob.
Pemanggil menandatangani string target dengan kunci pra-bersama perangkatnya dan
meneruskan tanda tangannya sebagai s.
| Rute | Metode | Kueri | Target bertanda tangan | Memerlukan |
|---|---|---|---|---|
/backup/workspace |
GET | w, d, s |
backup-workspace:<workspaceId> |
admin ruang kerja |
/backup/snapshot |
GET | n, d, s |
backup-snapshot:<name> |
pemilik instalasi |
/backup/restore |
POST | w, d, s |
backup-restore:<workspaceId> |
pemilik ruang kerja |
w adalah id ruang kerja, n nama direktori snapshot, d id perangkat pemanggil, s
tanda tangannya. n diselesaikan terhadap daftar cadangan alih-alih digabungkan ke akar
cadangan, sehingga rute itu tidak bisa diarahkan ke direktori yang tidak akan ditampilkan
oleh daftar.
| Status | Penyebab |
|---|---|
400 |
Parameter kueri yang diwajibkan hilang, atau isi unggahan kosong |
403 |
Perangkat tidak dikenal atau dicabut, tanda tangan buruk, atau pemanggil tidak memiliki peran itu |
404 |
Tidak ada port cadangan di host ini, atau snapshot/file ruang kerja yang disebut tidak ada |
405 |
/backup/restore dipanggil dengan apa pun selain POST |
413 |
Isi unggahan melebihi 8 GiB, baik menurut content-length yang dideklarasikan maupun menurut byte yang benar-benar dibaca |
500 |
Ekspor atau arsip gagal di sisi server |
Kedua unduhan merespons Cache-Control: no-store dengan Accept-Ranges: none. Setiap
permintaan membuat salinan baru dan menghapusnya setelah dialirkan, jadi respons yang
di-cache atau dilanjutkan akan menyambung byte dari dua ekspor berbeda menjadi satu file
yang tampak valid padahal tidak.
/backup/snapshot mengembalikan <name>.zip, dengan entri relatif terhadap akar snapshot
sehingga penguraiannya mereproduksi manifest.json + global.db +
<workspaceId>/workspace.db. Entri ditulis dalam urutan terurut, jadi dua arsip dari
snapshot yang sama adalah arsip yang sama.
/backup/restore mengalirkan isinya langsung ke file staging alih-alih menampungnya di
buffer, membatasinya sebelum dan selama pembacaan, dan menghapus file yang di-staging pada
setiap jalur keluar termasuk saat penolakan.
Path dan batas
Bagian berjudul “Path dan batas”| Hal | Nilai |
|---|---|
| Snapshot | <dataDir>/backups/<timestamp>/ |
| Cadangan ruang kerja terjadwal | <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db |
| Ekspor ruang kerja | <dataDir>/backups/exports/<workspaceId>-<timestamp>.db |
| Staging transfer | <dataDir>/backups/transfer/ — sebuah meja kerja, dibersihkan oleh rute yang menulisinya |
| Nama arsip snapshot | <snapshot directory name>.zip |
| Batas unggahan | 8 GiB per POST /backup/restore |
| Retensi | Snapshot instalasi: penghapusan manual. Cadangan ruang kerja: pipeline mingguan, bawaan 30 hari |
Direktori exports/, transfer/, dan workspace-backups/ bukan snapshot instalasi dan
dikecualikan dari server.listBackups. Hanya direktori terakhir yang memiliki retensi
terjadwal; menghapus snapshot instalasi memerlukan tindakan eksplisit dari pemilik
instalasi.
Lihat juga
Bagian berjudul “Lihat juga”- Cadangkan dan pulihkan — resep tempat operasi-operasi ini berada
- Ruang kerja dan isolasi — mengapa satu ruang kerja adalah satu file
- CLI
cc_server— direktori data tempat path-path ini berada - Peta rute — tempat UI berada
- Arsitektur — pemisahan klien/server yang diikuti path-path ini