백업, 내보내기, 가져오기
Control Center가 복사하고, 넘겨주고, 받아들일 수 있는 모든 것과 각 산출물의 정확한 형태입니다. 실제로 백업을 뜨려면 백업 및 복원을, 영속성이 이렇게 나뉜 이유는 워크스페이스와 격리를 참고하세요.
산출물
섹션 제목: “산출물”범위와 삭제 정책이 서로 다른 데이터베이스 사본 산출물이 세 가지 있습니다.
| 산출물 | 작성 주체 | 형태 | 포함 범위 |
|---|---|---|---|
| 설치 스냅샷 | server.backupNow |
타임스탬프가 붙은 디렉터리 | 설치의 모든 데이터베이스 |
| 워크스페이스 백업 | Workspace backup 파이프라인 |
.db 하나를 담은 타임스탬프 디렉터리 |
워크스페이스 하나의 데이터베이스 |
| 워크스페이스 내보내기 | workspace.export |
.db 파일 하나 |
워크스페이스 하나의 데이터베이스 |
모두 SQLite VACUUM INTO로 작성되며, 이는 실행 중인 WAL 데이터베이스에도
안전합니다. 읽기 트랜잭션을 열고, 조각 모음된 트랜잭션 일관성 사본을 만들며,
서버를 중단할 필요가 전혀 없습니다.
스냅샷 레이아웃
섹션 제목: “스냅샷 레이아웃”<dataDir>/backups/2026-07-28T09-12-33-000Z/ manifest.json global.db <workspaceId>/workspace.db one directory per workspace이 레이아웃은 실제 데이터 디렉터리를 그대로 비추므로, 설치 복원이 변환이 아니라
되복사하는 일이 됩니다. 디렉터리 이름은 :와 .를 -로 바꾼 UTC
타임스탬프이므로, Windows에서 파일 시스템에 안전하고 일반 문자열로도 시간순으로
정렬됩니다.
예약된 워크스페이스 백업은
<dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db에 따로
있습니다. 여기에는 매니페스트나 global.db가 없으며 설치 스냅샷도 아닙니다.
주간 파이프라인의 보존 단계는 구성된 기간(기본값 30일)보다 오래된 자기
워크스페이스의 백업만 제거합니다. 수동으로 만든 설치 스냅샷은 그 단계에서 순환
삭제되는 일이 없습니다. server.listBackups는 불완전한 것까지 포함해 설치
스냅샷만 나열합니다.
manifest.json
섹션 제목: “manifest.json”| 필드 | 유형 | 의미 |
|---|---|---|
version |
int | 매니페스트 형식 버전. 현재 1 |
created_at |
ISO-8601 UTC | 스냅샷을 생성한 시각 |
global.file |
string | 항상 global.db |
global.schema_version |
int | 캡처 시점의 GlobalDatabase 스키마 버전 |
global.bytes |
int | 작성된 global.db의 크기 |
workspace_schema_version |
int | 모든 워크스페이스 파일이 공유하는 WorkspaceDatabase 스키마 버전 |
workspaces[] |
array | 캡처한 워크스페이스마다 하나의 항목 |
workspaces[].workspace_id |
string | 이 파일이 담고 있는 워크스페이스 |
workspaces[].file |
string | 스냅샷 루트 기준 상대 경로, <workspaceId>/workspace.db |
workspaces[].bytes |
int | 그 파일의 크기 |
skipped_workspaces[] |
array of string | 백업이 캡처하지 못한 워크스페이스 |
워크스페이스는 등록되어 있지만 한 번도 기록된 적이 없거나(따라서 아직 파일이
없거나), VACUUM INTO가 실패했을 때 건너뜁니다. 어느 쪽이든 스냅샷은 그대로
완료되며, 매니페스트에 무엇이 빠졌는지 적힙니다.
완전성
섹션 제목: “완전성”server.listBackups는 스냅샷마다 complete 플래그를 보고합니다. 매니페스트가
없거나 파싱할 수 없을 때, global.db가 없을 때, 또는 매니페스트가 디스크에 없는
워크스페이스 파일을 가리킬 때 false입니다.
불완전한 스냅샷도 계속 나열됩니다. 운영자가 볼 수 없는 스냅샷은 가지고 있다고
믿는 스냅샷이기 때문입니다. 매니페스트를 읽을 수 없으면 목록은 레이아웃 자체로
폴백하여 찾아낸 <workspaceId>/workspace.db 파일을 보고합니다. 이런 파일들은
스냅샷 전체로는 설치를 복원할 수 없더라도 workspace.import로 개별적으로
받아들일 수 있습니다.
백업에 포함되지 않는 것
섹션 제목: “백업에 포함되지 않는 것”두 산출물 모두 데이터베이스만 담습니다. 워크스페이스 디렉터리는 데이터베이스보다 많은 것을 담고 있으며, 나머지는 어느 것도 함께 가지 않습니다.
| 경로 | 스냅샷에 포함? | 워크스페이스 내보내기에 포함? |
|---|---|---|
global.db |
예 | 아니요 |
<workspaceId>/workspace.db |
예 | 예(파일 자체입니다) |
<workspaceId>/blobs/ |
아니요 | 아니요 |
<workspaceId>/skills/ |
아니요 | 아니요 |
<workspaceId>/agents/ |
아니요 | 아니요 |
<workspaceId>/chat_credentials/ |
아니요 | 아니요 |
<workspaceId>/spaces/<spaceId>/ |
아니요 | 아니요 |
<workspaceId>/pr_clones/ |
아니요 | 아니요 |
secrets.json |
아니요 | 아니요 |
models/ |
아니요 | 아니요 |
meetings/<meetingId>/ |
아니요 | 아니요 |
rigs/ |
아니요 | 아니요 |
그중 일부는 버려도 됩니다. spaces/는 저장소에서 다시 프로비저닝되는
copy-on-write 워크트리를 담고, pr_clones/는 캐시이며, models/는 다시
내려받고, rigs/는 머신 상태입니다. 그렇지 않은 것도 있습니다. blobs/는
데이터베이스의 행이 가리키는 붙여넣은 이미지를 담고, skills/와 agents/는
에이전트가 실행에 쓰는 파일을 담고, secrets.json은 설치의 모든 페어링 키와
공급자 자격 증명, SSO 설정을 담습니다. 나머지를 챙기는 방법은
백업 및 복원을
참고하세요.
설치 백업 RPC와 워크스페이스 내보내기/가져오기는 fullClient 전용이므로, 페어링된
휴대폰에서는 트리거할 수 없습니다. 백업 포트가 연결되지 않은 서버(예: 데모
서버)에서는 이들 모두가 아예 없습니다. 거부되는 것이 아니라 구조적으로
존재하지 않습니다.
| 연산 | 종류 | 범위 | 최소 역할 | 인수 | 반환 |
|---|---|---|---|---|---|
server.backupNow |
변경 | 설치 | 설치 소유자 | 없음 | {ok, path} |
server.listBackups |
읽기 | 설치 | 설치 소유자 | 없음 | {backups: [...]} |
server.deleteBackup |
변경 | 설치 | 설치 소유자 | name |
{ok} |
workspace.export |
읽기 | 워크스페이스 | admin |
없음 | {ok, path} |
workspace.import |
변경 | 워크스페이스 | owner |
source_path |
{ok, workspace_id} |
workspace.delete |
변경 | 설치* | owner |
id |
레지스트리 행이 삭제됨으로 표시됨 |
workspace.delete는 표시하는 행이 전역 레지스트리에 있으므로 범위가 없습니다. 이 연산의 핸들러는 호출자가 해당 워크스페이스의 멤버인지 확인하고owner를 요구합니다.
모든 응답의 path는 서버 호스트의 경로입니다.
server.listBackups 응답
섹션 제목: “server.listBackups 응답”최신순이며 디렉터리 이름으로 정렬합니다(이름이 곧 타임스탬프이므로, 매니페스트를 읽을 수 없는 스냅샷에서도 순서가 유지됩니다).
{ "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은 생략됩니다. 최상위 bytes는
매니페스트가 스스로 합한 값이 아니라 디렉터리 전체의 실제 디스크 크기입니다.
스냅샷을 정리하는 운영자가 묻는 것은 그 디렉터리가 차지하는 비용이지, 백업이
기록하려던 양이 아니기 때문입니다.
각 workspaces[].path는 workspace.import가 source_path로 받는 값과 정확히
같습니다. 이는 의도된 것으로, “이 스냅샷에서 이 워크스페이스를 복원한다”는 것이
곧 가져오기 연산이므로, 둘이 같은 파일을 다르게 취급하는 쪽으로 어긋날 수
없습니다.
workspace.import 검증
섹션 제목: “workspace.import 검증”무엇이든 대체되기 전에, 후보 파일을 수명이 짧은 원시 SQLite 연결로 읽기 전용으로
열고 workspace_meta 행을 읽습니다.
| 조건 | 결과 |
|---|---|
읽을 수 있는 SQLite 데이터베이스가 아니거나 workspace_meta가 없음 |
거부됩니다. 아무것도 건드리지 않습니다 |
| 기록된 워크스페이스 id ≠ 대상 | 허용되고 기록됩니다. 이렇게 해서 워크스페이스를 복제하거나 새 id로 복원합니다 |
| 기록된 설치 id ≠ 이 설치 | 허용되고 기록됩니다. 그 워크스페이스의 페어링된 기기와 사용자 id는 그 설치에 속하며 여기서는 해석되지 않습니다 |
| 유효하지 않은 워크스페이스 id이거나 파일이 없음 | 거부됩니다 |
받아들이면 대상 워크스페이스의 데이터베이스가 매니저에서 닫히고 제거된 뒤에 그
위로 파일이 복사되며(열려 있는 drift 연결이 파일과 그 -wal을 붙잡고 있습니다),
그다음 다시 열려 beforeOpen이 FTS와 동기화 트리거를 다시 설치하고 FTS 인덱스가
다시 작성됩니다. 가져온 파일의 콘텐츠 테이블은 채워져 있지만 인덱스는 오래되었을
수 있습니다.
전송 라우트
섹션 제목: “전송 라우트”위의 모든 연산은 서버 측 경로로 말하며, 이는 서버가 곧 자신의 머신일 때만 완전한
답입니다. 다음 세 가지가 바이트를 실어 나르며, 미디어 프록시와 블롭 저장소가
사용하는 것과 같은 PSK로 서명된 레인을 씁니다. 호출자는 기기의 사전 공유 키로
대상 문자열에 서명하고 그 서명을 s로 전달합니다.
| 라우트 | 메서드 | 쿼리 | 서명 대상 | 필요 권한 |
|---|---|---|---|---|
/backup/workspace |
GET | w, d, s |
backup-workspace:<workspaceId> |
워크스페이스 관리자 |
/backup/snapshot |
GET | n, d, s |
backup-snapshot:<name> |
설치 소유자 |
/backup/restore |
POST | w, d, s |
backup-restore:<workspaceId> |
워크스페이스 소유자 |
w는 워크스페이스 id, n은 스냅샷 디렉터리 이름, d는 호출 기기 id, s는
서명입니다. n은 백업 루트에 이어 붙이는 것이 아니라 백업 목록을 기준으로
해석되므로, 이 라우트를 목록에 없던 디렉터리로 겨냥할 수 없습니다.
| 상태 | 원인 |
|---|---|
400 |
필수 쿼리 매개변수가 없거나 업로드 본문이 비어 있음 |
403 |
알 수 없거나 해지된 기기, 잘못된 서명, 또는 호출자에게 역할이 없음 |
404 |
이 호스트에 백업 포트가 없거나, 지정한 스냅샷/워크스페이스 파일이 없음 |
405 |
/backup/restore가 POST가 아닌 다른 메서드로 호출됨 |
413 |
선언된 content-length 기준이든 실제로 읽은 바이트 기준이든 업로드 본문이 8 GiB를 초과함 |
500 |
서버 측에서 내보내기나 아카이브가 실패함 |
두 다운로드 모두 Cache-Control: no-store와 Accept-Ranges: none으로
응답합니다. 요청마다 새 사본을 만들어 내고 스트리밍이 끝나면 삭제하므로,
캐시되거나 재개된 응답은 서로 다른 두 내보내기의 바이트를 이어 붙여, 멀쩡해
보이지만 그렇지 않은 파일 하나를 만들게 됩니다.
/backup/snapshot은 <name>.zip을 반환하며, 항목들은 스냅샷 루트 기준 상대
경로이므로 압축을 풀면 manifest.json + global.db + <workspaceId>/workspace.db가
그대로 재현됩니다. 항목은 정렬된 순서로 기록되므로, 같은 스냅샷의 두 아카이브는
같은 아카이브입니다.
/backup/restore는 본문을 버퍼링하지 않고 곧바로 스테이징 파일로 스트리밍하며,
읽기 전과 읽는 동안 크기를 제한하고, 거부된 경우까지 포함해 나가는 모든
경로에서 스테이징된 파일을 삭제합니다.
경로와 한계
섹션 제목: “경로와 한계”| 항목 | 값 |
|---|---|
| 스냅샷 | <dataDir>/backups/<timestamp>/ |
| 예약된 워크스페이스 백업 | <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db |
| 워크스페이스 내보내기 | <dataDir>/backups/exports/<workspaceId>-<timestamp>.db |
| 전송 스테이징 | <dataDir>/backups/transfer/ — 작업 공간이며, 여기에 쓰는 라우트가 스윕합니다 |
| 스냅샷 아카이브 이름 | <snapshot directory name>.zip |
| 업로드 상한 | POST /backup/restore당 8 GiB |
| 보존 | 설치 스냅샷: 수동 삭제. 워크스페이스 백업: 주간 파이프라인, 기본 30일 |
exports/, transfer/, workspace-backups/ 디렉터리는 설치 스냅샷이 아니며
server.listBackups에서 제외됩니다. 마지막 디렉터리만 예약된 보존 정책을
가지며, 설치 스냅샷을 삭제하려면 설치 소유자의 명시적인 조치가 필요합니다.
함께 보기
섹션 제목: “함께 보기”- 백업 및 복원 — 이 연산들이 속한 레시피
- 워크스페이스와 격리 — 워크스페이스 하나가 파일 하나인 이유
cc_serverCLI — 이 경로들이 자리한 데이터 디렉터리- 라우트 맵 — UI가 있는 곳
- 아키텍처 — 경로들이 따르는 클라이언트/서버 분할