Skip to content

Mô hình dữ liệu

Lược đồ nằm trong apps/api/migrations, chạy theo thứ tự tên file.

Migration

FileNội dung
0001_init.sqlTừ điển dùng chung và các thực thể Giai đoạn 1
0002_graph.sqlThực thể Giai đoạn 2 và bảng cạnh tổng quát
0003_search.sqlsearch_docs và bảng ảo FTS5
0004_admissions_detail.sqlChi tiết tuyển sinh (môn thi, vòng, mốc thời gian, hồ sơ) và học phí

Bảng Giai đoạn 1

provinces ──┐
            ├──< schools ──< school_subjects >── subjects
subjects ───┘      │
                   ├──< admissions
                   ├──< exams >── subjects
                   ├──< teachers
                   ├──< school_activities
                   └──< competition_schools >── competitions >── subjects

schools — hồ sơ trường: slug, name, short_name, alt_names (các tên gọi khác, phân tách bằng |), type, province_id, grades, founded_year, website, summary, verification.

admissions — một dòng cho mỗi (trường, năm, khối lớp, phương thức), có ràng buộc duy nhất trên tổ hợp đó. Chứa places, applicants, cutoff_score, exam_structure, weighting, source_url.

exams — đề thi; topics là danh sách chuyên đề phân tách bằng |.

competitions — kỳ thi và olympic, level nhận truong | tinh | quoc-gia | quoc-te.

teachers, school_activities — hồ sơ giáo viên và dòng hoạt động của trường.

Chi tiết tuyển sinh (migration 0004)

Trước migration này, một đợt tuyển sinh chỉ có vài trường văn bản tự do (exam_structure, weighting). Chúng mô tả được nhưng không so sánh được: không thể trả lời "trường nào thi mấy môn", "môn nào hệ số 2", "hạn nộp hồ sơ đến khi nào". Bốn bảng con tách các phần đó thành dữ liệu có cấu trúc:

admissions ──┬──< admission_subjects    (môn thi: vai trò, thời lượng, hình thức, thang điểm, hệ số)
             ├──< admission_rounds      (các vòng: cách đánh giá, cách tính điểm, ngưỡng qua vòng)
             ├──< admission_timeline    (mốc thời gian: phát hành, nộp, thi, chấm, công bố, phúc khảo)
             └──< admission_documents   (hồ sơ dự tuyển, bắt buộc hay tuỳ chọn)

schools ─────────< school_fees          (học phí theo năm và khối lớp)

admission_subjects.role phân biệt bốn vai trò: dieu-kien (môn điều kiện), chuyen (môn chuyên), nang-luc (bài đánh giá năng lực tổng hợp) và khac. Đây là trường cho phép so sánh chéo giữa trường thi ba môn viết và trường chỉ có một bài đánh giá năng lực.

Bảng admissions cũng được bổ sung: classes (số lớp), scope (phạm vi tuyển sinh), application_fee + application_fee_note (lệ phí), result_date, announcement_url, contact.

Học phí

school_fees lưu tuition_monthly (VND/tháng) và months_per_year thay vì một con số "học phí cả năm", vì các trường công bố theo tháng và số tháng thu khác nhau. Cột is_estimate đánh dấu mức dự kiến — nhiều trường công bố học phí trước khi có hướng dẫn chính thức về mức thu.

Số liệu học phí trong seed

Chỉ THCS Năng khiếu ĐHSP năm 2025 dùng số công bố thật (4.000.000đ/tháng, thu 9 tháng, nguồn hnue.edu.vn) và mang verification = 'official'. Học phí các trường còn lại là số liệu mẫu: is_estimate = 1, verification = 'unverified' và cột note ghi rõ điều đó. Giao diện hiển thị mức xác thực ở mọi nơi có số tiền.

Bảng Giai đoạn 2 (đã tạo, chưa có giao diện)

universities, organizations, people, alumni_records, opportunities.

Ngoài ra có bảng cạnh tổng quát cho những quan hệ chưa cần bảng riêng:

sql
edges (from_type, from_id, relation, to_type, to_id, meta)

Các quan hệ dự kiến mô hình hoá: Person → studied_at → School, Person → graduated_from → University, School → participates_in → Competition, Alumni → mentors → Student, University → recruits_from → School, Center → prepares_for → Exam.

Quy ước

  • Ngày tháng luôn là chuỗi ISO YYYY-MM-DD, so sánh trực tiếp bằng >= trong SQL.
  • Danh sách ngắn (tên gọi khác, chuyên đề) lưu chuỗi phân tách bằng | thay vì bảng phụ, vì chúng chỉ dùng để hiển thị chứ không dùng để lọc.
  • verification có ràng buộc CHECK trên mọi bảng thực thể.
  • id cố định trong seed để mỗi lần nạp lại cho ra cùng khoá — tiện so sánh giữa các lần chạy.

Sinh dữ liệu mẫu

seed/data.mjs là nguồn duy nhất. scripts/build-seed.mjs sinh ra seed/seed.sqlseed/search.sql. Bộ sinh số ngẫu nhiên là một LCG gieo bằng chuỗi (không dùng Math.random) nên kết quả tất định: chạy lại cho ra đúng số liệu cũ.

bash
pnpm db:build-seed   # sinh lại SQL
pnpm db:reset:local  # xoá state, migrate, nạp lại

Tài liệu nội bộ dự án Chuyên Chọn.