Skip to content

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

IDSevRepoRủi roĐối sách
RISK-001🔴chuyenchonKhông có canonical learner identityowner_key = email lowercase là PK của ~40 bảng (111 vị trí SQL); family↔learner join bằng so khớp chuỗi emailREQ-ACC-04, SDD-001 §7: users.id/learners.id UUID, email chỉ là thuộc tính login
RISK-002🔴sutuconSchema thật không nằm trong repo — ~70 bảng (users, courses, evidence registry, learner models…) có DDL ở repo ngoài api.conan.schoolNemo12 thiết kế schema mới từ SDD; nếu migrate data cần truy cập repo đó (Q-054)
RISK-003🟠cả haiKnowledge/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🔴chuyenchonMột D1 dùng chung 4 workers với 3 chuỗi migration đánh số trùng nhau từ 0001REQ-PLT-11, SDD-001 §7: một sequence duy nhất
RISK-005🟠cả hai4+ hệ rubric song song (rubric_, quality_rubric_, le_rubric_, question_quality_) + 2 framework .mjs rootSDD-003 §7: một rubric registry, gốc CC-QAF-1.0
RISK-006🟠cả hai4 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🟠sutucon2 learner model cạnh tranh (learner_*_models course-scoped vs member_* 10-dimension) + model thứ 3 chỉ có trong docs kiaraSDD-002 §2 là canonical; member intelligence → REQ-PAR-08 ⏳
RISK-008🔴sutuconDB production dùng chung conan-platform-production với sản phẩm khác; tenancy = UUID literal hardcode 5+ filesNemo12 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ả haiSchema nặng JSON blob (~113 cột *_json), enum tiếng Việt literal (chac/lung_lay/hong), timestamps TEXT không kỷ luậtSDD-001 §7 chuẩn hóa; enum tiếng Việt chỉ ở presentation layer

2. Architecture

IDSevRepoRủi roĐối sách
RISK-009🔴chuyenchonOnboarding é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ạiREQ-LRN-08: onboarding không ép goal thi chuyên
RISK-010🟠cả haiKhông Hono: router tay ~6.7k LOC (chuyenchon); 35 Pages Functions copy-paste HMAC làm BFF (sutucon) — port = rewriteSDD-001 §5: Hono + zod-openapi từ đầu
RISK-011🟠chuyenchon4 paradigm frontend trộn lẫn: Astro SSR, Vite MPA 19 entries + 310 islands, vanilla TS, custom Node builderSDD-001 §4: một chuẩn Vite+React SPA per app
RISK-012🟠cả haiFrontend 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🟠chuyenchonKhô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ả haiCross-school skill state fragmentation (turtle.algebra vs shark.algebra)SDD-007 §5: canonical skill + school context
RISK-020🟠sutuconMentor 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🟠sutuconBug 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ả haiPhụ 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

IDSevRepoRủi roĐối sách
RISK-013🔴chuyenchonOwner email dac2205@gmail.com hardcode 5 files; 2 Access audience hex hardcode; không có RBAC — "admin" = so sánh emailREQ-ACC-05 RBAC + REQ-SEC-06 cấm hardcode
RISK-021🟠cả hai2 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🟠chuyenchonAI 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 gatewayREQ-PLT-09: gateway bắt buộc, fail = fail rõ ràng
RISK-023🟠cả haiDomain hardcode ở 45 files (chuyenchon) / ~30 files (sutucon); cookie domain, CORS regex, school_id literalREQ-SEC-06 + config package
RISK-024🟡sutuconopenapi.json sinh từ danh sách route viết tay, không từ router; route không có zod validationREQ-PLT-04: OpenAPI sinh từ code
RISK-025🟡sutuconObservability không bật cho api worker productionSDD-006 §10: bật cho mọi worker
RISK-027🟠sutuconHMAC service auth không ký body, không chống replay (60s window); Access JWT forward mà không verify; session không rotationSDD-001 §6 thiết kế lại; không mang HMAC scheme sang
RISK-028🟠sutuconMedia = base64 lưu trong D1 (≤200KB), IMAGES/R2 khai báo nhưng không dùngSDD-009 Media Service (R2 + Cloudflare Images)

4. Process & Hygiene

IDSevRepoRủi roĐối sách
RISK-014🟠chuyenchonContent 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ả haiTest = regex trên source text (29 files chuyenchon; 1 file sutucon) — vỡ khi refactor, không có safety net hành viQG-005/QG-009: behavior tests bắt buộc, cấm source-regex tests
RISK-016🟠cả haiMigration 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ạiQG-004: migration idempotent, áp qua CI
RISK-029🟡cả haiBuild 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ảnNguồnDùng cho
ARCHITECTURE-SUBSYSTEMS.md — mô hình 6 subsystemchuyenchon docskhớp module map SDD-001 §2
DATA-MODEL.md (bản aspirational normalized) + docs/requirements/ (actor catalog, use cases, user stories, traceability)chuyenchon docsPRD-001 §3–4
4 quality frameworks .mjs: CC-QAF-1.0, requirements-assessment, story-acceptance, learning-experience-qualitychuyenchon rootQG-002/QG-006 rubric gốc
TS knowledge graphs Toán/Văn/Anh (6.5k LOC)chuyenchon app/libseed canonical graph (SDD-003)
Blueprint→experience→rubric content pipeline + 18 WorkflowsmoriSDD-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 hardeningsutuconSDD-001/002/005; REQ-SCH-05
Kiara docs set (PRD/SDD/ADR/DATA-MODEL/PRIVACY…) — cấu trúc tốt nhất trong legacysutucon kiara/docstham chiếu Marlins app
Octopus curriculum spec: 5 Academies × 16 courses, Future Lion Journey, ai-teensutucon docsPRD Octopus (REQ-SCH-05)
Exam & school intelligence suite (kho đề, registry trường, workflows)chuyenchon api+dataREQ-SCH-04 (Shark)
Tailwind v4 CSS-first toàn bộ (không cần migrate v3→v4)cả haiDS-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 → 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).