Backup/Restore Drill Log
Bằng chứng đã thử khôi phục D1 nemo12-platform ít nhất một lần — theo Audit Standard AS-04.5.5 (🔴🚸 Pilot Gate: dữ liệu trẻ em thật, chưa từng restore-thử là rủi ro không chấp nhận được cho một pilot chạm dữ liệu thật). "Có phương án backup" không đủ — phải có bằng chứng đã restore thật, đếm khớp.
Đợt diễn tập 2026-08-22 (mới nhất)
Chạy lại vì đúng điều kiện đã ghi ở §Lịch diễn tập: schema đổi đáng kể kể từ đợt trước. So với 2026-08-15, cơ sở dữ liệu đã khác hẳn — 79 → 96 bảng, 39 → 67 migration, 2.146 → 15.656 item, file data export 3,4 MB → 27 MB. Một quy trình khôi phục chưa thử lại trên khối dữ liệu gấp 8 lần thì chưa gọi là đã thử.
Đây cũng là đợt đầu tiên kiểm vân tay nội dung, không chỉ đếm dòng — xem Bước 4.
Bước 1 — Export production (chỉ đọc)
npx wrangler d1 export nemo12-platform --remote --no-data --output=prod-schema.sql -y # 1.271 dòng
npx wrangler d1 export nemo12-platform --remote --no-schema --output=prod-data.sql -y # 34.980 dòng, 27 MBQuy trình tách schema/data của đợt 2026-08-15 vẫn đúng ở quy mô 27 MB — không lỗi no such table nào. Export mất khoảng 7 giây.
Bước 2 — Restore vào D1 local cô lập
P=/tmp/restore-drill-persist && rm -rf "$P"
npx wrangler d1 execute nemo12-platform --local --persist-to "$P" --file=prod-schema.sql # 1,8 giây
npx wrangler d1 execute nemo12-platform --local --persist-to "$P" --file=prod-data.sql # 80 giâyRestore 27 MB mất 80 giây. Con số này là thứ cần biết trước khi có sự cố: nó nói rằng khôi phục toàn bộ là việc của vài phút, không phải vài giờ — nên phương án "chờ khôi phục" là phương án dùng được, không phải phương án trên giấy.
Bước 3 — Đếm dòng cả 96 bảng
| Kiểm | Production | Restored | Khớp? |
|---|---|---|---|
| Số bảng | 96 | 96 | ✅ |
| Tổng số dòng | 34.978 | 34.978 | ✅ |
| Số bảng lệch | — | — | ✅ 0/96 |
Đếm bằng một truy vấn sinh từ chính sqlite_master của bản restore (chia lô 32 bảng/câu vì D1 chặn compound SELECT dài), chạy y hệt hai phía.
Bước 4 — Vân tay nội dung (mới ở đợt 2026-08-22)
Đợt trước chỉ đếm dòng. Nhưng đếm dòng khớp vẫn có thể che nội dung hỏng: 15.656 dòng items với prompt bị cắt cụt hay mã hoá sai vẫn đếm ra đúng 15.656. Vì vậy đợt này so thêm ba đại lượng cho tám bảng nặng nhất: tổng số dòng, tổng độ dài một cột nội dung, và biên khoá (MIN/MAX).
| Bảng | Dòng | Tổng ký tự cột nội dung | Khớp? |
|---|---|---|---|
items | 15.656 | 890.141 (prompt) | ✅ |
exam_questions | 3.711 | 285.311 (prompt) | ✅ |
item_figures | 2.912 | 383.485 (figure_json) | ✅ |
skill_nodes | 1.799 | 37.771 (title_vi) | ✅ |
lab_content | 1.587 | 2.333.669 (content_json) | ✅ |
labs | 1.587 | 30.536 (title_vi) | ✅ |
learner_evidence | 702 | 9.102 (type) | ✅ |
learner_model_versions | 425 | 3.770 (state) | ✅ |
8/8 khớp cả ba đại lượng.
Kết luận đợt 2026-08-22: khôi phục thành công ở quy mô 27 MB / 96 bảng / 34.978 dòng. 0 bảng lệch, 0 lệch nội dung trên tám bảng nặng nhất. Quy trình hai bước tách schema/data giữ nguyên hiệu lực, không cần đổi.
Dọn sau diễn tập: file export chứa dữ liệu trẻ em thật. Xoá cả thư mục persist lẫn hai file .sql ngay sau khi đối chiếu xong — bản export nằm lại trên đĩa là một bản sao dữ liệu thật không ai canh.
Đợt diễn tập 2026-08-15
Mục tiêu: xác nhận export production → restore vào một bản D1 độc lập → dữ liệu khớp 100%, không cần tạo/đụng tài nguyên Cloudflare mới nào (dùng D1 local persist làm đích restore — cô lập tuyệt đối khỏi production, không tốn quota).
Bước 1 — Export production (chỉ đọc, không mutate)
cd workers/api
npx wrangler d1 export nemo12-platform --remote --no-data --output=prod-schema.sql -y
npx wrangler d1 export nemo12-platform --remote --no-schema --output=prod-data.sql -yTách schema/data riêng — export gộp một file (--output không kèm --no-data/--no-schema) từng thất bại khi restore (no such table: main.portrait_tracks), nghi do wrangler d1 execute --file chia batch trên file lớn (3.4M/5695 dòng) làm lệch thứ tự CREATE TABLE trước INSERT ở một số bảng giữa file. Export tách đôi (schema 1001 dòng, data 4695 dòng) tránh được vấn đề này hoàn toàn — restore cả hai file phụ không lỗi gì.
Bước 2 — Restore vào D1 local cô lập
PERSIST=/tmp/restore-drill-persist
npx wrangler d1 execute nemo12-platform --local --persist-to "$PERSIST" --file=prod-schema.sql
npx wrangler d1 execute nemo12-platform --local --persist-to "$PERSIST" --file=prod-data.sql--persist-to trỏ tới thư mục tạm riêng — không đụng .wrangler/state cục bộ đang dùng cho npm run dev, không đụng production.
Bước 3 — Đối chiếu
| Kiểm | Production | Restored | Khớp? |
|---|---|---|---|
| Số bảng | 79 | 79 | ✅ |
| Số dòng — tất cả 79 bảng | (xem bảng dưới) | (xem bảng dưới) | ✅ 0/79 lệch |
Chi tiết từng bảng (trích lệnh SELECT COUNT(*) FROM "<table>" chạy cả hai phía, script lặp qua toàn bộ sqlite_master):
items 2146/2146 · skill_nodes 274/274 · skill_edges 251/251 · labs 225/225 · lab_content 225/225 ·
item_figures 280/280 · content_blueprints 104/104 · exam_questions 110/110 · blueprint_weights 191/191 ·
whale_rankings 99/99 · whale_universities 92/92 · whale_scholarships 73/73 · success_stories 54/54 ·
strands 42/42 · milestones 63/63 · learner_skill_state 24/24 · d1_migrations 39/39 ·
+ 62 bảng khác (đa số 0-20 dòng — dữ liệu vận hành/pilot chưa phát sinh nhiều) — toàn bộ khớp tuyệt đốiKết luận: Restore thành công, 0 dữ liệu mất, 0 dữ liệu lệch. Quy trình 2 bước (export tách schema/data → restore theo đúng thứ tự) là quy trình khuyến nghị — không dùng export gộp một file cho restore diện rộng.
Thời gian thực hiện
Export (2 lệnh) + restore (2 lệnh) + đối chiếu 79 bảng: dưới 5 phút tổng cộng. Không cần tài khoản/quyền gì ngoài token hiện có (D1 Edit đã có sẵn — export/execute local không cần quyền tạo resource mới).
Quy trình khôi phục thật (nếu sự cố xảy ra)
Khác đợt diễn tập ở một điểm: khôi phục thật ghi vào chính nemo12-platform remote (không phải local persist), và bắt buộc làm khi ứng dụng đang dừng ghi (maintenance mode hoặc sau khi xác nhận sự cố):
npx wrangler d1 export nemo12-platform --remote --no-data --output=schema.sql -y # backup gần nhất, làm TRƯỚC khi restore đè
npx wrangler d1 export nemo12-platform --remote --no-schema --output=data.sql -y
# … xác định file backup cần khôi phục (từ đợt export trước sự cố) …
npx wrangler d1 execute nemo12-platform --remote --file=<backup-schema>.sql
npx wrangler d1 execute nemo12-platform --remote --file=<backup-data>.sqlĐây là ngoại lệ DUY NHẤT được phép chạy DDL/restore trực tiếp trên --remote ngoài CI (xem migration-reconciliation.md §Cấm chạy migration production ngoài CI) — chỉ khi đang xử lý sự cố mất dữ liệu thật, có xác nhận của chủ dự án, và ghi lại thành một đợt diễn tập mới ở file này ngay sau đó.
Lịch diễn tập
Chạy lại drill này mỗi khi schema đổi đáng kể (đợt migration lớn) và tối thiểu mỗi quý.
| Đợt | Bảng | Dòng | Cỡ export | Lệch | Vân tay nội dung |
|---|---|---|---|---|---|
| 2026-08-22 | 96 | 34.978 | 27 MB | 0/96 | 8/8 khớp |
| 2026-08-15 | 79 | — | 3,4 MB | 0/79 | chưa kiểm |