Tài liệu dự án · Sách ôn thi Hybrid TNTHPT

#06 – Mô hình miền & dữ liệu

Giai đoạn: Thiết kế hệ thống · Phiên bản 0.1 – 29/10/2026

Mô hình logic, độc lập công nghệ. Tên thực thể dùng tiếng Anh để dùng thẳng trong mã nguồn; mô tả tiếng Việt.

#1. Các miền nghiệp vụ (Bounded contexts)

flowchart LR
    subgraph ID["Định danh & Quyền"]
        U["User / Role"]
        ENT["Entitlement"]
    end
    subgraph CAT["Nội dung (Catalog)"]
        BOOK["Book / ContentNode"]
        RES["LearningResource"]
        CODE["ContentCode (ID)"]
        VID["Video"]
        TAX["Taxonomy (ma trận)"]
    end
    subgraph ASM["Đánh giá (Assessment)"]
        Q["Question / Rubric"]
        A["Assessment / Section / Item"]
        AT["Attempt / Answer"]
        REC["Recommendation"]
    end
    subgraph ACT["Kích hoạt"]
        BATCH["ActivationBatch / Code"]
    end
    subgraph CLS["Lớp học"]
        C["Class / Assignment"]
    end
    subgraph COM["Thương mại"]
        P["Package / Order / Payment"]
    end
    subgraph ANA["Phân tích"]
        EV["Event"]
    end
    ACT -- "cấp" --> ENT
    COM -- "cấp" --> ENT
    CODE --> RES
    RES --> A
    A --> Q
    Q --> TAX
    AT --> REC
    REC --> TAX
    C --> A
    ID -.-> ANA

#2. Sơ đồ quan hệ thực thể (ERD)

erDiagram
    USER ||--o{ ENTITLEMENT : "có"
    USER ||--o{ ATTEMPT : "thực hiện"
    USER ||--o{ ORDER : "đặt"
    USER ||--o{ CLASS_MEMBER : "thuộc"
    BOOK ||--o{ CONTENT_NODE : "gồm"
    BOOK ||--o{ ACTIVATION_BATCH : "có"
    BOOK ||--o{ CONTENT_CODE : "in"
    ACTIVATION_BATCH ||--o{ ACTIVATION_CODE : "sinh"
    ACTIVATION_CODE |o--o| ENTITLEMENT : "tạo"
    CONTENT_NODE ||--o{ CONTENT_NODE : "con"
    CONTENT_NODE ||--o{ LEARNING_RESOURCE : "chứa"
    CONTENT_CODE }o--|| LEARNING_RESOURCE : "trỏ tới"
    LEARNING_RESOURCE |o--o| VIDEO : "dùng"
    LEARNING_RESOURCE |o--o| ASSESSMENT : "là"
    ASSESSMENT ||--o{ ASSESSMENT_SECTION : "chia"
    ASSESSMENT_SECTION ||--o{ ASSESSMENT_ITEM : "gồm"
    ASSESSMENT_ITEM }o--|| QUESTION : "dùng"
    QUESTION }o--o| PASSAGE : "thuộc ngữ liệu"
    QUESTION |o--o| RUBRIC : "chấm theo"
    QUESTION |o--o| VIDEO : "lời giải video"
    QUESTION ||--o{ QUESTION_TAG : "gắn"
    TAXONOMY_TAG ||--o{ QUESTION_TAG : "được gắn"
    TAXONOMY_TAG ||--o{ TAXONOMY_TAG : "con"
    TAXONOMY_TAG |o--o{ CONTENT_NODE : "ứng với chuyên đề"
    ATTEMPT }o--|| ASSESSMENT : "của"
    ATTEMPT }o--o| ASSIGNMENT : "theo bài giao"
    ATTEMPT ||--o{ ATTEMPT_ANSWER : "gồm"
    ATTEMPT_ANSWER }o--|| QUESTION : "trả lời"
    ATTEMPT ||--o{ RECOMMENDATION : "sinh"
    RECOMMENDATION }o--|| TAXONOMY_TAG : "về"
    CLASS ||--o{ CLASS_MEMBER : "có"
    CLASS ||--o{ ASSIGNMENT : "được giao"
    ASSIGNMENT }o--|| ASSESSMENT : "giao"
    PACKAGE ||--o{ PACKAGE_ITEM : "gồm"
    PACKAGE_ITEM }o--|| ASSESSMENT : "đề"
    ORDER }o--|| PACKAGE : "mua"
    ORDER ||--o{ PAYMENT : "thanh toán"
    ORDER |o--o| ENTITLEMENT : "tạo"
    USER ||--o{ EVENT : "phát sinh"

#3. Cơ chế ID nội dung và QR

#3.1 Yêu cầu đối với ID

  • Ngắn, gõ được trên điện thoại trong < 5 giây; không có ký tự dễ nhầm.
  • Học sinh và nhân viên hỗ trợ đọc được ý nghĩa (môn, loại).
  • Không trùng trong phạm vi một phiên bản sách; không bao giờ thay đổi sau khi in.
  • Không phụ thuộc vào cấu trúc kỹ thuật (đổi tài nguyên đích mà không đổi ID).

#3.2 Định dạng đề xuất (ADR-002)

 T  V  0 1 2
 │  │  └┴┴── Số thứ tự 3 chữ số trong (môn, loại): 001–999
 │  └─────── Loại tài nguyên (1 chữ)
 └────────── Môn (1 chữ)
Vị trí Giá trị Ý nghĩa
Môn T Toán
V Ngữ văn
A Tiếng Anh
Loại L Lý thuyết / mind map / chuyên đề (THEORY)
V Ví dụ minh hoạ (EXAMPLE)
B Bài tập thực hành / vận dụng (EXERCISE_SET)
D Đề thi thử / đề luyện tập (MOCK_EXAM, PRACTICE_EXAM)
K Kiểm tra đầu vào – placement test (PLACEMENT_TEST)

Ví dụ: TL021 – lý thuyết Toán số 21; TV045 – ví dụ Toán số 45; TD003 – đề thi thử Toán số 3; AK002 – placement test Tiếng Anh số 2; VB007 – bài vận dụng Ngữ văn số 7.

Phạm vi phiên bản: khoá duy nhất của ID là (book_edition_id, code). Học sinh chỉ gõ TV045; hệ thống tra trong các sách học sinh đã kích hoạt (BR-06). QR chứa phiên bản để không mơ hồ: https://<tên miền>/27/TV045 (27 = phiên bản 2027).

Phương án thay thế (nếu HEID muốn ID không mang nghĩa): mã ngẫu nhiên 5 ký tự từ bảng 31 ký tự (≈ 28,6 triệu tổ hợp) – an toàn trước việc đoán ID nhưng khó hỗ trợ qua điện thoại. Vì nội dung đã được bảo vệ bằng quyền sử dụng (BR-03), việc đoán được ID không làm lộ nội dung → khuyến nghị dùng ID có nghĩa.

#3.3 Vòng đời ID

stateDiagram-v2
    [*] --> RESERVED: BTV sinh ID
    RESERVED --> ASSIGNED: Gán tài nguyên
    ASSIGNED --> RESERVED: Bỏ gán (chưa khoá)
    ASSIGNED --> LOCKED: Trưởng ban khoá khi chốt in
    LOCKED --> LOCKED: Đổi tài nguyên đích (lưu vết)
    LOCKED --> RETIRED: Ngừng dùng (chuyển hướng tới tài nguyên thay thế)
    RESERVED --> [*]: Xoá (chỉ khi chưa khoá)

#3.4 Mã kích hoạt

  • 10 ký tự từ bảng 23456789ABCDEFGHJKMNPQRSTUVWXYZ (31 ký tự), in dạng XXXX-XXXX-XX và kèm QR https://<tên miền>/kich-hoat/<mã>.
  • Lưu băm của mã để tra cứu (HMAC-SHA256 với khoá bí mật) và bản mã hoá để xuất lại cho nhà in khi cần; không lưu bản rõ trong log.
  • Trạng thái: NEW → EXPORTED → REDEEMED / REVOKED.

#4. Từ điển dữ liệu (thực thể chính)

#4.1 Định danh & quyền

USER

Trường Kiểu Mô tả
id UUID Khoá chính
sso_subject string, nullable Định danh từ Hoclieu SSO
full_name string Họ tên
phone / email string, nullable Ít nhất một trường có giá trị nếu không dùng SSO
password_hash string, nullable Argon2/bcrypt
roles enum[] STUDENT, TEACHER, EDITOR, CHIEF_EDITOR, ADMIN
grade, school, province string, nullable Hồ sơ (FR-01.07)
consent_version, consent_at string, timestamp Đồng ý điều khoản
status enum ACTIVE, LOCKED, DELETED

ENTITLEMENT – quyền sử dụng

Trường Kiểu Mô tả
id UUID
user_id FK USER
scope_type enum BOOK, PACKAGE
scope_id UUID book_edition_id hoặc package_id
source enum ACTIVATION, PURCHASE, TEACHER, ADMIN_GRANT
source_ref UUID activation_code_id / order_id
valid_from, valid_to timestamp Thời hạn
status enum ACTIVE, REVOKED, EXPIRED

#4.2 Nội dung

BOOK (một phiên bản sách)

Trường Kiểu Mô tả
id UUID
subject enum MATH, LITERATURE, ENGLISH
title string "Ôn thi TNTHPT Toán"
edition string "2027" – mã phiên bản dùng trong QR (27)
isbn string
cover_url string
entitlement_days int Thời hạn quyền sử dụng sau kích hoạt (hoặc valid_until cố định)
status enum DRAFT, PUBLISHED, ARCHIVED

CONTENT_NODE – cây nội dung sách

Trường Kiểu Mô tả
id, book_id, parent_id UUID
kind enum PART, TOPIC, SKILL, SECTION
title string "Phần 1 – Ôn luyện kiến thức", "Nguyên hàm – Tích phân"
order_no int Thứ tự
printed_page_from/to int Trang trên sách giấy
taxonomy_tag_id FK, nullable Chuyên đề tương ứng trong ma trận (để đề xuất dẫn về đúng nút)

LEARNING_RESOURCE

Trường Kiểu Mô tả
id, node_id UUID
kind enum THEORY, EXAMPLE, EXERCISE_SET, PLACEMENT_TEST, MOCK_EXAM, PRACTICE_EXAM, EXTENDED_EXAM
title string
body rich text (JSON/HTML có LaTeX) Nội dung text (lý thuyết, phân tích ví dụ)
video_id FK, nullable
assessment_id FK, nullable Với các loại có câu hỏi
is_preview bool Cho xem không cần kích hoạt
version, status int, enum DRAFT, IN_REVIEW, PUBLISHED (BR-20)

CONTENT_CODE – ID in trên sách

Trường Kiểu Mô tả
book_id + code khoá duy nhất TV045
resource_id FK Tài nguyên đích hiện tại
printed_page int Trang in
status enum RESERVED, ASSIGNED, LOCKED, RETIRED
redirect_resource_id FK, nullable Khi RETIRED
locked_by, locked_at

VIDEO

Trường Kiểu Mô tả
id UUID
provider, provider_asset_id string Dịch vụ video và mã tài sản
duration_sec int
thumbnail_url string
status enum UPLOADING, PROCESSING, READY, FAILED

TAXONOMY_TAG – ma trận kiến thức

Trường Kiểu Mô tả
id, parent_id UUID Cây phân cấp
subject enum
dimension enum TOPIC (chuyên đề), SKILL (kỹ năng), QUESTION_TYPE (dạng bài), COGNITIVE_LEVEL (mức độ)
code, name string T.GT.NH – "Nguyên hàm"
weight decimal Trọng số trong ma trận đề (tuỳ chọn)

#4.3 Đánh giá

QUESTION

Trường Kiểu Mô tả
id UUID
subject enum
type enum MCQ, TRUE_FALSE, SHORT_ANSWER, ESSAY
passage_id FK, nullable Ngữ liệu dùng chung (bài đọc)
stem rich text Đề bài
options JSON MCQ: [{key:"A", content}]; TRUE_FALSE: [{key:"a", content}]
answer JSON MCQ: "B"; TRUE_FALSE: {"a":true,"b":false,...}; SHORT_ANSWER: ["-1,5","-1.5"]; ESSAY: null
explanation rich text Lời giải
solution_video_id FK, nullable
rubric_id FK, nullable Với ESSAY
difficulty enum Mức độ nhận thức (song song với tag)
version, status

RUBRIC: id, criteria JSON [{code, name, max_points, levels:[{label, points, descriptor}]}], total_points.

ASSESSMENT

Trường Kiểu Mô tả
id UUID
kind enum Như LEARNING_RESOURCE.kind (các loại có câu hỏi)
duration_min int, nullable null = không giới hạn
scoring_scheme enum MATH_2025, ENGLISH_2025, RAW_COUNT, SELF_RUBRIC (09)
allowed_modes enum[] EXAM_VIEW, ANSWER_SHEET, ONE_PER_SCREEN, KEY_LOOKUP
allow_back_navigation bool false với placement test
max_score decimal 10

ASSESSMENT_SECTION: id, assessment_id, title ("Phần I"), order_no, question_type, points_rule JSON. ASSESSMENT_ITEM: section_id, question_id, question_version, order_no, points.

ATTEMPT

Trường Kiểu Mô tả
id UUID
user_id, assessment_id FK
assignment_id FK, nullable Bài giao của GV
mode enum EXAM_VIEW, ANSWER_SHEET, ONE_PER_SCREEN
timed bool
started_at, deadline_at, submitted_at timestamp deadline tính phía máy chủ
submit_type enum MANUAL, AUTO_TIMEOUT
status enum IN_PROGRESS, SUBMITTED, ABANDONED
score, max_score decimal Điểm tự động
self_score decimal, nullable Điểm tự đánh giá (Văn)
section_scores JSON Điểm theo phần
duration_sec int

ATTEMPT_ANSWER

Trường Kiểu Mô tả
attempt_id, question_id khoá
response JSON Câu trả lời
image_urls string[] Ảnh bài viết tay
is_correct bool, nullable null với tự luận
correct_parts int, nullable Số ý đúng (TRUE_FALSE)
points decimal
self_grade JSON, nullable Mức chọn theo tiêu chí rubric
time_spent_ms int Đặc biệt quan trọng với ONE_PER_SCREEN
flagged bool Đánh dấu xem lại
updated_at timestamp Phục vụ đồng bộ ngoại tuyến (last-write-wins theo client timestamp hợp lệ)

RECOMMENDATION: attempt_id, tag_id, items_total, items_wrong, items_slow, error_rate, rank, resource_ids (lý thuyết/ví dụ/bài tập gợi ý).

#4.4 Kích hoạt, lớp học, thương mại, phân tích

Thực thể Trường chính
ACTIVATION_BATCH id, book_id, quantity, created_by, exported_at, note
ACTIVATION_CODE id, batch_id, code_hmac, code_encrypted, status, redeemed_by, redeemed_at, revoked_reason
CLASS id, teacher_id, name, school_year, lms_class_id, join_code
CLASS_MEMBER class_id, user_id, joined_at
ASSIGNMENT id, class_id, assessment_id, open_at, due_at, allowed_modes, created_by
PACKAGE id, subject, title, price_vnd, duration_days, status
PACKAGE_ITEM package_id, assessment_id, order_no
ORDER id, user_id, package_id, amount_vnd, status (PENDING, PAID, FAILED, CANCELLED, REFUNDED), created_at, paid_at
PAYMENT id, order_id, provider, provider_txn_id (duy nhất), raw_payload, status, received_at
EVENT id, user_id (nullable), anonymous_id, session_id, name, properties JSON, occurred_at, received_at, device, app_version
AUDIT_LOG id, actor_id, action, entity, entity_id, before, after, at

#5. Ràng buộc & chỉ mục quan trọng

Ràng buộc Mục đích
UNIQUE (book_id, code) trên CONTENT_CODE ID duy nhất theo phiên bản sách
UNIQUE (code_hmac) trên ACTIVATION_CODE Tra mã kích hoạt nhanh, không trùng
UNIQUE (provider, provider_txn_id) trên PAYMENT Xử lý IPN trùng lặp (idempotent)
Partial unique (user_id, assessment_id) WHERE status = 'IN_PROGRESS' trên ATTEMPT Tối đa một lượt đang làm (BR-15)
Trigger/ứng dụng: không cho sửa code khi status ∈ {LOCKED, RETIRED} BR-04
Index (user_id, submitted_at) trên ATTEMPT Lịch sử, biểu đồ
Index (name, occurred_at) trên EVENT, phân vùng theo tháng Báo cáo

#6. Phân loại dữ liệu & lưu trữ

Nhóm dữ liệu Ví dụ Mức nhạy cảm Biện pháp
Dữ liệu cá nhân cơ bản Họ tên, SĐT, email, trường Cá nhân Mã hoá khi truyền, giới hạn quyền xem, che một phần trong trang quản trị
Dữ liệu học tập Bài làm, điểm Cá nhân Chỉ học sinh, giáo viên của lớp (với bài giao) và Admin xem
Mã kích hoạt Bí mật kinh doanh Băm + mã hoá, xuất file có mật khẩu
Đáp án, lời giải Bí mật nội dung Không gửi xuống trình duyệt trước khi nộp
Sự kiện hành vi Cá nhân (bút danh) Ẩn danh hoá khi xoá tài khoản
Giao dịch Tài chính Không lưu dữ liệu thẻ; lưu chứng từ theo quy định kế toán