---
url: https://docs.nemo12.com/legacy/legacy-migration.md
description: >-
  Sổ rủi ro migrate chuyenchon và sutucon.com (RISK-xxx), mức nghiêm trọng, và
  đối sách Nemo12 cho từng rủi ro.
---

# Legacy Audit & Migration Risk Register

Kết quả rà soát 2026-08-13: `chuyenchon` (→ Turtle + Shark) và `sutucon.com` (→ Octopus). Mỗi rủi ro có mã `RISK-xxx` được trích dẫn trong PRD/SDD; cột **Đối sách** chỉ tới nơi Nemo12 xử lý.

**Severity:** 🔴 blocker · 🟠 major · 🟡 minor.

## 1. Identity & Data

| ID | Sev | Repo | Rủi ro | Đối sách |
| --- | --- | --- | --- | --- |
| RISK-001 | 🔴 | chuyenchon | **Không có canonical learner identity** — `owner_key` = email lowercase là PK của ~40 bảng (111 vị trí SQL); family↔learner join bằng so khớp chuỗi email | REQ-ACC-04, SDD-001 §7: `users.id`/`learners.id` UUID, email chỉ là thuộc tính login |
| RISK-002 | 🔴 | sutucon | **Schema thật không nằm trong repo** — ~70 bảng (users, courses, evidence registry, learner models…) có DDL ở repo ngoài `api.conan.school` | Nemo12 thiết kế schema mới từ SDD; nếu migrate data cần truy cập repo đó (Q-054) |
| RISK-003 | 🟠 | cả hai | Knowledge/skill định nghĩa trùng lặp ×3 (TS graphs 6.5k LOC → mori seed → learning_graph_nodes) | SDD-003 §3: một registry duy nhất, seed từ TS graphs |
| RISK-004 | 🔴 | chuyenchon | Một D1 dùng chung 4 workers với **3 chuỗi migration đánh số trùng nhau** từ 0001 | REQ-PLT-11, SDD-001 §7: một sequence duy nhất |
| RISK-005 | 🟠 | cả hai | 4+ hệ rubric song song (rubric\_*, quality_rubric\_*, le_rubric\_*, question_quality\_*) + 2 framework `.mjs` root | SDD-003 §7: một rubric registry, gốc CC-QAF-1.0 |
| RISK-006 | 🟠 | cả hai | 4 item banks không tương thích (assessment_item, math_diagnostic_item, diagnosis_question_registry, exam_problems) | SDD-004 §9: một Item Bank; exam_problems là registry Shark riêng có liên kết |
| RISK-007 | 🟠 | sutucon | 2 learner model cạnh tranh (`learner_*_models` course-scoped vs `member_*` 10-dimension) + model thứ 3 chỉ có trong docs kiara | SDD-002 §2 là canonical; member intelligence → REQ-PAR-08 ⏳ |
| RISK-008 | 🔴 | sutucon | **DB production dùng chung** `conan-platform-production` với sản phẩm khác; tenancy = UUID literal hardcode 5+ files | Nemo12 dùng D1 mới `nemo12-platform`, không đụng DB cũ; school_id là cột có ràng buộc |
| RISK-017 | 🟡 | cả hai | Schema nặng JSON blob (~113 cột `*_json`), enum tiếng Việt literal (`chac/lung_lay/hong`), timestamps TEXT không kỷ luật | SDD-001 §7 chuẩn hóa; enum tiếng Việt chỉ ở presentation layer |

## 2. Architecture

| ID | Sev | Repo | Rủi ro | Đối sách |
| --- | --- | --- | --- | --- |
| RISK-009 | 🔴 | chuyenchon | **Onboarding ép mọi learner khai mục tiêu thi chuyên** (exam_year, target_school NOT NULL; app gate toàn bộ sau onboarding) — learner Turtle không thể tồn tại | REQ-LRN-08: onboarding không ép goal thi chuyên |
| RISK-010 | 🟠 | cả hai | Không Hono: router tay ~6.7k LOC (chuyenchon); 35 Pages Functions copy-paste HMAC làm BFF (sutucon) — port = rewrite | SDD-001 §5: Hono + zod-openapi từ đầu |
| RISK-011 | 🟠 | chuyenchon | 4 paradigm frontend trộn lẫn: Astro SSR, Vite MPA 19 entries + 310 islands, vanilla TS, custom Node builder | SDD-001 §4: một chuẩn Vite+React SPA per app |
| RISK-012 | 🟠 | cả hai | Frontend nguyên khối: `App.tsx` 5.1k/8.3k LOC; `admin` là fork byte-level của `www` (~25k LOC nhân ba) | Design System package + cấu trúc route chuẩn; cấm fork app |
| RISK-018 | 🟠 | chuyenchon | Không Queues — cron poll bảng D1 + hand-rolled lease/lock (12+ crons, có cron `* * * * *`) | SDD-003 §10, SDD-006 §5: Cloudflare Queues + DLQ |
| RISK-019 | 🟠 | cả hai | Cross-school skill state fragmentation (`turtle.algebra` vs `shark.algebra`) | SDD-007 §5: canonical skill + school context |
| RISK-020 | 🟠 | sutucon | Mentor domain là proxy rỗng 42 dòng → `api.conan.school` (router ~1200 dòng + workflows nằm ngoài repo) nhưng rafiki 8.3k LOC phụ thuộc nó | App mentors Nemo12 xây mới theo REQ-MEN; không port proxy |
| RISK-026 | 🟠 | sutucon | Bug tiềm ẩn: `MEMBER_INTELLIGENCE_WORKFLOW` gọi nhưng **không bind** (TypeError mỗi final submission); 1 workflow bind sang worker ngoài (`script_name=api-conan-school`) | Không mang sang; CI check binding tồn tại (QG-009) |
| RISK-030 | 🟡 | cả hai | Phụ thuộc ngoài không kiểm soát: CAPOS (`capos.internal`), upstream conan.school; docs legacy mâu thuẫn (2 cặp system-design khác nhau, ADR đánh số trùng) | Intake + ADR registry mới; CAPOS → Q-043 |

## 3. Security & Config

| ID | Sev | Repo | Rủi ro | Đối sách |
| --- | --- | --- | --- | --- |
| RISK-013 | 🔴 | chuyenchon | Owner email `dac2205@gmail.com` hardcode 5 files; 2 Access audience hex hardcode; **không có RBAC** — "admin" = so sánh email | REQ-ACC-05 RBAC + REQ-SEC-06 cấm hardcode |
| RISK-021 | 🟠 | cả hai | 2 bản Google OAuth khác nhau (app vs family, cookie host-only không SSO); sutucon thì ổn hơn (GSI id_token) | SDD-001 §6: một auth module, GSI id_token (không cần client secret), cookie `.nemo12.com` + rotation |
| RISK-022 | 🟠 | chuyenchon | AI Gateway "probe-then-fallback": ping lỗi 1 lần → cả isolate **bypass gateway âm thầm**; exam-planning gọi AI không qua gateway | REQ-PLT-09: gateway bắt buộc, fail = fail rõ ràng |
| RISK-023 | 🟠 | cả hai | Domain hardcode ở 45 files (chuyenchon) / ~30 files (sutucon); cookie domain, CORS regex, school_id literal | REQ-SEC-06 + config package |
| RISK-024 | 🟡 | sutucon | `openapi.json` sinh từ **danh sách route viết tay**, không từ router; route không có zod validation | REQ-PLT-04: OpenAPI sinh từ code |
| RISK-025 | 🟡 | sutucon | Observability không bật cho api worker production | SDD-006 §10: bật cho mọi worker |
| RISK-027 | 🟠 | sutucon | HMAC service auth **không ký body, không chống replay** (60s window); Access JWT forward mà không verify; session không rotation | SDD-001 §6 thiết kế lại; không mang HMAC scheme sang |
| RISK-028 | 🟠 | sutucon | Media = base64 lưu trong D1 (≤200KB), `IMAGES`/R2 khai báo nhưng không dùng | SDD-009 Media Service (R2 + Cloudflare Images) |

## 4. Process & Hygiene

| ID | Sev | Repo | Rủi ro | Đối sách |
| --- | --- | --- | --- | --- |
| RISK-014 | 🟠 | chuyenchon | Content ship dưới dạng migration SQL (15.9k LOC trộn DDL + data + repair scripts) | SDD-004 §3: content là data qua API/pipeline, không phải migration |
| RISK-015 | 🟠 | cả hai | **Test = regex trên source text** (29 files chuyenchon; 1 file sutucon) — vỡ khi refactor, không có safety net hành vi | QG-005/QG-009: behavior tests bắt buộc, cấm source-regex tests |
| RISK-016 | 🟠 | cả hai | Migration không idempotent (bare ALTER TABLE, DELETE destructive), áp tay ngoài CI; `www` `migrations_dir` trỏ thư mục không tồn tại | QG-004: migration idempotent, áp qua CI |
| RISK-029 | 🟡 | cả hai | Build junk + stale trees commit vào repo (dist-worker ×4, tmp 6.1M, backups gitignored, `node_modules 2`, 200 file evidence audit); repo đang mid-refactor chưa commit | .gitignore kỷ luật; không mang junk sang |

## 5. Tài sản đáng kế thừa (carry-overs)

| Tài sản | Nguồn | Dùng cho |
| --- | --- | --- |
| `ARCHITECTURE-SUBSYSTEMS.md` — mô hình 6 subsystem | chuyenchon docs | khớp module map SDD-001 §2 |
| `DATA-MODEL.md` (bản aspirational normalized) + `docs/requirements/` (actor catalog, use cases, user stories, traceability) | chuyenchon docs | PRD-001 §3–4 |
| 4 quality frameworks `.mjs`: CC-QAF-1.0, requirements-assessment, story-acceptance, learning-experience-quality | chuyenchon root | QG-002/QG-006 rubric gốc |
| TS knowledge graphs Toán/Văn/Anh (6.5k LOC) | chuyenchon app/lib | seed canonical graph (SDD-003) |
| Blueprint→experience→rubric content pipeline + 18 Workflows | mori | SDD-003/004 tham chiếu thiết kế |
| Evidence registry + idempotency key pattern; GSI id_token auth; onboarding data gates; 4F reflection engines; product submission rubric hóa; gateway hardening | sutucon | SDD-001/002/005; REQ-SCH-05 |
| Kiara docs set (PRD/SDD/ADR/DATA-MODEL/PRIVACY…) — cấu trúc tốt nhất trong legacy | sutucon kiara/docs | tham chiếu Marlins app |
| Octopus curriculum spec: 5 Academies × 16 courses, Future Lion Journey, ai-teen | sutucon docs | PRD Octopus (REQ-SCH-05) |
| Exam & school intelligence suite (kho đề, registry trường, workflows) | chuyenchon api+data | REQ-SCH-04 (Shark) — phần **kho đề** đã confirm: REQ-EXAM-05..10, [SDD-012](../architecture/sdd-012-real-exam-bank.md) (SRC-029); calendar/simulator vẫn ⏳ |
| Tailwind v4 CSS-first toàn bộ (không cần migrate v3→v4) | cả hai | DS-001 |

## 6. Chiến lược migration (tóm tắt)

1. **Không đụng production cũ** — hai hệ legacy tiếp tục chạy; Nemo12 xây trên tài nguyên mới hoàn toàn (D1/R2/Queues mới, zone nemo12.com).
2. **Docs-first**: mọi capability legacy đáng giữ đi qua [Feature Inventory](legacy-feature-inventory.md) → REQ → SDD → code mới. **Không port code trực tiếp** trừ tài sản thuần logic (graphs, frameworks, rubric content).
3. **Data migration** (khi được yêu cầu): export từ legacy → transform (email→learner_id mapping, dedupe skill states) → import qua pipeline có kiểm chứng; giữ evidence provenance.
4. Cutover từng school; redirect chuyenchon.com/sutucon.com sau khi Nemo12 ổn định (Q-055).
