Module · WS đào tạo · 20/7/2026

training — Học viên & đào tạo MVP GỘP student+course

Module gộp student + course thành một bounded context "ghi danh → đào tạo" — quản lý học viên, vòng đời hồ sơ, khóa học, ghi danh + phân công GV–xe, kế hoạch trình Sở. Quyết định 20/7, trước go-live.

⚠️ Bản cũ giữ để đối chiếu: student · course — chưa xóa, sẽ xóa khi hoàn tất chuyển đổi. Sơ đồ tổng thể & quan hệ module vẫn vẽ theo bản tách — cập nhật khi chốt xong scaffold.
0

Vì sao gộp — quyết định lớn nhất đợt tối ưu

Căn cứChi tiết
Rớt cả 4 điều kiện tách của Sơ đồ §0 ① không ai mua course rời student · ② cùng nhịp nâng cấp · ③ cùng người dùng (giáo vụ) · ④ gỡ một cái là cái kia vô nghĩa. Ranh giới cũ tồn tại chỉ vì bám bảng legacy QLHS V2 (migrate 1:1)
Ranh giới nóng nhất hệ hoso ↔ enrollment ↔ course transition là callback P3 hai chiều — loại ranh giới đắt nhất trong OpenGate (service API + outbox + job đối soát)
Lợi ích sau gộp Transition thành gọi hàm trong module — bỏ hẳn outbox/đối soát giữa hai bên; bỏ 2 contract view nội bộ (course_v_khoa_hoc, course_v_enrollment chỉ còn cần cho consumer ngoài như report/hrm.timesheet-dat)
Vì sao phải làm NGAY Quy tắc prefix bảng theo key module ⇒ đổi student_*/course_*training_* phải xong trước lần migrate dữ liệu Vĩnh An đầu tiên — sau go-live thì đắt gấp nhiều lần
TRƯỚC (2 module, callback P3 hai chiều) SAU (1 module, gọi hàm nội bộ) student ◀──ma_kh──── course ┌─────────── training ───────────┐ hoso ──xep_khoa──▶ enrollment │ student · hoso · course · │ hoso ◀─da_bao_so── plan │ enrollment · plan │ (outbox + đối soát 2 chiều) │ transition = function call │ └────────────────────────────────┘ Ranh giới NGOÀI không đổi (vẫn P3/P1): tuition ─da_thu_dot1─▶ · report ─da_bao_so─▶ · crm ─convert─▶ Consumer ngoài đọc qua view mới: training_v_hoso · training_v_khoa_hoc · training_v_enrollment
1

Feature / BO / Action — giữ đúng chuẩn 5 feature

FeatureBO chính (+ BO phụ)Action
studentHọc viên (danh bạ người)viewcreateeditdeleteexport
hosoHồ sơ ghi danh theo khóa (state machine)
BO phụ: Giấy tờ (scan, hạn) · Lịch sử trạng thái (append-only)
viewcreateeditapprovetransferverifyexport
courseKhóa họcviewcreateeditcloseexport
enrollmentGhi danh + phân công GV–xeviewcreateeditassign
planKế hoạch đào tạo (trình Sở)viewcreateapprovereport
⚠️ Delta so với bản tách: giaytolichsu hạ từ feature xuống BO phụ của hoso — quyền duyệt giấy tờ giữ bằng custom action hoso.verify, xuất lịch sử bằng hoso.export; xóa file scan đi qua hoso.edit. Trade-off chấp nhận: ai có hoso.view sẽ thấy cả lịch sử (bản tách chặn TUYEN_SINH xem lichsu). Theo phép thử ① của Sơ đồ §0: nếu thực tế cần bộ quyền riêng cho giấy tờ/lịch sử → thăng cấp lại thành feature — việc tách feature trong cùng module rẻ (chỉ đổi manifest, không đổi bảng).
2

Vòng đời hồ sơ — không đổi, chỉ đổi cách thực thi

tu_van → tiep_nhancho_bo_sunghop_leda_thu_dot1 (tuition xác nhận — P3, giữ nguyên) → xep_khoa (nội bộ — gọi hàm enrollment, hết outbox) → da_bao_so (report xác nhận — P3, giữ nguyên) → dang_hoc Nhánh dừng: huy · chuyen_khoa — mỗi bước ghi lịch sử (ai · khi nào · lý do)
Transition / ràng buộcTrước (2 module)Sau (training)
hoso xep_khoa ↔ tạo enrollmentP3 callback + outboxGọi hàm nội bộ, cùng transaction
Khai giảng khóa cần plan da_bao_soJOIN view chéoQuery nội bộ
Đóng khóa khi mọi hồ sơ ra trạng thái cuốicourse đọc student_v_hosoQuery nội bộ
da_thu_dot1 ← tuition · da_bao_so ← report · convert ← crmP3P3 giữ nguyên — ranh giới ngoài chính đáng (người dùng khác)
3

Dữ liệu chính & bảng đổi prefix

Nội dung trường giữ nguyên như bản tách (xem chi tiết trong student/course cũ) — thay đổi duy nhất là prefix theo key module mới:

Bảng cũ (scaffold)Bảng mớiGhi chú
student_nguoi_lxtraining_nguoi_lxUNIQUE (ma_dk, ma_kh, ma_csdt) — 1 dòng = 1 lượt đăng ký theo khóa
student_ho_so_giaytotraining_ho_so_giaytoBO phụ của hoso — loại giấy tờ ref catalog
student_ho_so_lichsutraining_ho_so_lichsuappend-only, thay audit chung ở MVP
course_khoa_hoctraining_khoa_hocmã khóa ma_kh theo quy tắc catalog
(mới — chưa scaffold)training_ghi_danhenrollment: ma_dk · ma_gv · ma_xe — khớp đăng ký Sở
(mới — chưa scaffold)training_ke_hoachplan: nội dung mẫu Sở (jsonb/file) · reported_at

▸ Contract view — chỉ publish cho consumer NGOÀI

View cũView mớiConsumer ngoài
student_v_hosotraining_v_hosotuition (công nợ) · report (DS báo Sở) · portal
course_v_khoa_hoctraining_v_khoa_hocreport · dat (đối soát theo khóa) · portal
course_v_enrollmenttraining_v_enrollmentdat (đối soát phân công GV–xe) · hrm.timesheet-dat

Tuân quy tắc cứng Quan hệ module §4: view chỉ chứa cột định danh + nhãn hiển thị; học phí thỏa thuận, file scan giấy tờ không vào view — đọc qua service API check quyền.

4

Quy tắc & liên kết — gộp từ 2 module cũ

Quy tắc nghiệp vụ (không đổi)

  • Chống trùng CCCD trong khóa · đủ tuổi theo hạng (catalog)
  • Thiếu giấy tờ theo checklist → tự chuyển cho_bo_sung
  • Đổi trạng thái bắt buộc ghi lịch sử — không sửa/xóa
  • Khóa chỉ khai giảng sau khi kế hoạch đã báo Sở
  • Phân công GV–xe khớp đăng ký Sở XD — lệch → cảnh báo + phiên DAT không hợp lệ
  • Đóng khóa chỉ khi mọi hồ sơ ra trạng thái cuối · sĩ số theo giới hạn (config catalog)

Liên kết chéo còn lại (đều ra NGOÀI)

  • teacher/vehiclema_gv/ma_xe (P1, chỉ-đọc)
  • catalog — mã hạng, checklist giấy tờ, quy tắc mã
  • tuition(ma_dk, ma_kh, ma_csdt) · callback da_thu_dot1 (P3)
  • report — DS báo Sở · callback da_bao_so (P3)
  • datma_dk, ma_kh (đối soát km/giờ, P1)
  • crm — convert lead → hồ sơ (P3) · rfcard/dat.cardrfid

⚠ Câu hỏi mở (thừa kế)

  • Ánh xạ trạng thái từ cờ legacy khi migrate (chờ DB V2)
  • Có dùng bàn giao liên phòng? (chờ DS phòng ban Vĩnh An)
  • Quy tắc ma_kh Vĩnh An (13 ký tự legacy?) — giữ khi migrate
Quyền

Ma trận phân quyền — gộp 2 ma trận cũ

Permission key đầy đủ: training.main.<feature>.<action> — thay cả student.main.* lẫn course.main.*.

▸ permissions[] — manifest.json

[ { "group": "main", "feature": "student", "label": "Học viên", "actions": ["view","create","edit","delete","export"] }, { "group": "main", "feature": "hoso", "label": "Hồ sơ ghi danh", "actions": ["view","create","edit","approve","transfer","verify","export"] }, { "group": "main", "feature": "course", "label": "Khóa học", "actions": ["view","create","edit","close","export"] }, { "group": "main", "feature": "enrollment", "label": "Ghi danh & phân công", "actions": ["view","create","edit","assign"] }, { "group": "main", "feature": "plan", "label": "Kế hoạch đào tạo", "actions": ["view","create","approve","report"] } ]

⚠️ Action đặc thù (transfer, verify, close) cần bổ sung vào validator manifest — như plan data-scope P1.

▸ Ma trận vai trò × feature

FeatureQTHTGIAM_DOCQL_DAO_TAOTUYEN_SINHGIAO_VUGIAO_VIENKE_TOANHOC_VIEN
studentRRWWWR¹R³R²
hosoRRWAW³AWAR¹R³R²
courseRRWRWR¹R²
enrollmentRRWWR¹
planRRWAW

R xem · W tạo/sửa · A duyệt · không có quyền · ¹ dữ liệu phân công · ² của chính mình · ³ theo trạng thái hồ sơ. Vai trò không liệt kê = không có quyền.

Đặc thù: hoso +transfer (QL_DAO_TAO, TUYEN_SINH, GIAO_VU) · A ở hoso = verify giấy tờ (thay ma trận giayto cũ) · course +close, enrollment +assign (QL_DAO_TAO) · hủy hồ sơ = bước workflow, không phải action quyền.

▸ Quyền mức record (row-level)

Port nguyên từ 2 bản cũ (student §Quyền · course §Quyền), chỉ đổi "module": "training" và gộp fields/scopeVars. Điều kiện record theo vai trò sau gộp:

Vai tròFeature (action)Điều kiện record
TUYEN_SINHhoso (view, edit)trạng thái ∈ {tu_van, tiep_nhan, cho_bo_sung, hop_le}
KE_TOANstudent, hoso (view)trạng thái ∈ {hop_le, da_thu_dot1, xep_khoa, da_bao_so, dang_hoc}
GIAO_VIENstudent, hoso (view)trang_thai_ho_so = 'dang_hoc' giao_vien_id = ctx.current_giao_vien_id
GIAO_VIENenrollment (view)ma_gv = ctx.current_ma_gv
GIAO_VIENcourse (view)khoa_hoc_id ∈ ctx.current_assigned_khoa_ids
HOC_VIENstudent, hoso (view)nguoi_lxid = ctx.current_nguoi_lxid
HOC_VIENcourse (view)khoa_hoc_id ∈ ctx.current_khoa_ids

Biến ngữ cảnh không đổi: current_giao_vien_id/current_ma_gv (teacher tra) · current_nguoi_lxid/current_ma_dk_list/current_khoa_ids (nay do training tra thay vì student) · current_assigned_*.

Checklist chuyển đổi (trước migrate Vĩnh An)

Scaffold ws_suns

  • Gộp 2 module thành training (manifest: 5 feature, permissions, scopes)
  • Migrations: đổi prefix bảng + index theo bảng mục 3
  • Publish 3 contract view training_v_* · thêm bảng training_ghi_danh, training_ke_hoach
  • Seed lại rt_role.grants: đổi module: student/coursetraining

Tài liệu cập nhật theo (khi chốt)

  • Schema dữ liệu (prefix mới) · migration đối chiếu hiện trạng (đích mới)
  • Sơ đồ WS/Module (bản đồ MVP 9→8) · Quan hệ module (bỏ callback student↔course)
  • Consumer đổi tên view: report, dat, tuition, portal, hrm.timesheet-dat
  • Xóa student.html / course.html khi hoàn tất — chờ yêu cầu