ข้ามไปยังเนื้อหา

สำรอง นำออก และนำเข้า

ทุกสิ่งที่ Control Center คัดลอก ส่งต่อ หรือนำมาใช้ได้ พร้อมรูปร่างที่แน่นอนของอาร์ติแฟกต์ แต่ละชิ้น หากต้องการสำรองข้อมูลจริง ๆ ดู สำรองและกู้คืน ส่วนเหตุใดการเก็บข้อมูลถาวรจึง แยกแบบนี้ ดูเวิร์กสเปซและการแยกโดเมน

มีอาร์ติแฟกต์สำเนาฐานข้อมูลสามแบบ ซึ่งมีขอบเขตและนโยบายการลบต่างกัน

อาร์ติแฟกต์ เขียนโดย รูปร่าง ครอบคลุม
สแนปช็อตการติดตั้ง server.backupNow ไดเรกทอรีที่ประทับเวลา ทุกฐานข้อมูลบนการติดตั้ง
ข้อมูลสำรองของเวิร์กสเปซ ไปป์ไลน์ Workspace backup ไดเรกทอรีที่ประทับเวลาซึ่งมี .db หนึ่งไฟล์ ฐานข้อมูลของเวิร์กสเปซหนึ่งตัว
การส่งออกเวิร์กสเปซ workspace.export ไฟล์ .db ไฟล์เดียว ฐานข้อมูลของเวิร์กสเปซหนึ่งตัว

ทั้งหมดเขียนด้วย VACUUM INTO ของ SQLite ซึ่งปลอดภัยกับฐานข้อมูล 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 แสดงเฉพาะสแนปช็อตการติดตั้ง รวมถึงสแนปช็อตที่ไม่ครบด้วย

ฟิลด์ ชนิด ความหมาย
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 ต่อสแนปช็อตหนึ่งตัว โดยเป็น false เมื่อ แมนิเฟสต์หายไปหรืออ่านไม่รู้เรื่อง เมื่อ global.db หายไป หรือเมื่อแมนิเฟสต์ ระบุชื่อไฟล์เวิร์กสเปซที่ไม่มีอยู่บนดิสก์

สแนปช็อตที่ไม่ครบยังคงถูกแสดง เพราะสแนปช็อตที่ผู้ดำเนินการมองไม่เห็นคือ สแนปช็อตที่พวกเขาเชื่อว่ามีอยู่ เมื่ออ่านแมนิเฟสต์ไม่ได้ การแสดงรายการจะถอยไปใช้ โครงร่างเองและรายงานไฟล์ <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 ในทุกคำตอบเป็นพาธบนโฮสต์เซิร์ฟเวอร์

ใหม่สุดก่อน เรียงตามชื่อไดเรกทอรี (ซึ่งก็คือเวลาประทับ ลำดับจึงยังถูกต้องแม้ กับสแนปช็อตที่อ่านแมนิเฟสต์ไม่ได้)

{
"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 พอดี เป็นเจตนา: “กู้คืนเวิร์กสเปซนี้จากสแนปช็อตนี้” ก็คือ ปฏิบัติการนำเข้า ทั้งสองจึงแยกไปปฏิบัติต่อไฟล์เดียวกันต่างกันไม่ได้

ก่อนที่จะแทนที่สิ่งใด ไฟล์ตัวเลือกจะถูกเปิดแบบอ่านเท่านั้นด้วยการเชื่อมต่อ SQLite ดิบอายุสั้น และอ่านแถว workspace_meta ของมัน

เงื่อนไข ผลลัพธ์
ไม่ใช่ฐานข้อมูล SQLite ที่อ่านได้ หรือไม่มี workspace_meta ปฏิเสธ ไม่มีอะไรถูกแตะต้อง
ไอดีเวิร์กสเปซที่บันทึกไว้ ≠ เป้าหมาย อนุญาต พร้อมบันทึกล็อก นี่คือวิธีทำสำเนาเวิร์กสเปซหรือกู้คืนภายใต้ไอดีใหม่
ไอดีการติดตั้งที่บันทึกไว้ ≠ การติดตั้งนี้ อนุญาต พร้อมบันทึกล็อก อุปกรณ์ที่จับคู่และไอดีผู้ใช้ของมันเป็นของการติดตั้งนั้นและจะรีโซลฟ์ที่นี่ไม่ได้
ไอดีเวิร์กสเปซไม่ถูกต้อง หรือไฟล์ไม่มีอยู่ ปฏิเสธ

เมื่อรับ ฐานข้อมูลของเวิร์กสเปซเป้าหมายจะถูกปิดและถอดออกจากตัวจัดการ ก่อนคัดลอกไฟล์ทับ (การเชื่อมต่อ 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 คือไอดีเวิร์กสเปซ n คือชื่อไดเรกทอรีสแนปช็อต d คือไอดีอุปกรณ์ที่เรียก s คือลายเซ็น n ถูกตรีสินกับรายการข้อมูลสำรอง ไม่ใช่ต่อเข้ากับรากของ backups เส้นทางจึงไม่อาจเล็งไปที่ไดเรกทอรีที่รายการไม่เคยแสดง

สถานะ สาเหตุ
400 พารามิเตอร์คำค้นที่จำเป็นหายไป หรือบอดี้อัปโหลดว่างเปล่า
403 อุปกรณ์ไม่รู้จักหรือถูกเพิกถอน ลายเซ็นไม่ถูกต้อง หรือผู้เรียกไม่มีบทบาทนั้น
404 ไม่มีพอร์ตสำรองบนโฮสต์นี้ หรือสแนปช็อต/ไฟล์เวิร์กสเปซที่ระบุชื่อไม่มีอยู่
405 เรียก /backup/restore ด้วยเมธอดอื่นที่ไม่ใช่ POST
413 บอดี้อัปโหลดเกิน 8 GiB ไม่ว่าจะตาม content-length ที่ประกาศไว้หรือตามไบต์ที่อ่านจริง
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
เพดานการอัปโหลด 8 GiB ต่อ POST /backup/restore
การเก็บรักษา สแนปช็อตการติดตั้ง: ลบด้วยมือ ข้อมูลสำรองของเวิร์กสเปซ: ไปป์ไลน์รายสัปดาห์ ค่าเริ่มต้น 30 วัน

ไดเรกทอรี exports/, transfer/ และ workspace-backups/ ไม่ใช่ สแนปช็อตการติดตั้งและถูกตัดออกจาก server.listBackups มีเพียงไดเรกทอรี สุดท้ายเท่านั้นที่มีการเก็บรักษาตามกำหนด การลบสแนปช็อตการติดตั้งต้องมี การดำเนินการอย่างชัดแจ้งของเจ้าของการติดตั้ง