Appearance
Quản lý học viên (Students)
Student là căn cước "học viên trường" — entity riêng tách khỏi User (tài khoản). Một User có thể là học viên nhiều trường (đa tenant), nhưng trong mỗi tenant, mỗi User có tối đa một Student record với mã học viên + lifecycle riêng.
Một dòng tóm tắt
User = tài khoản đăng nhập; Student = "đã được trường nhận học". Khi attach User vào Batch lần đầu, listener EnsureStudentForBatchMember tự tạo Student record với student_code + status active. Sau đó bạn quản lý lifecycle (admit / graduate / withdraw) qua Học viên trong sidebar.
Khác biệt User vs Student
| Khía cạnh | User (tài khoản) | Student (học viên trường) |
|---|---|---|
| Định danh | student_code (mã do trường cấp) | |
| Phạm vi | Đăng nhập + truy cập toàn tenant | Học viên thuộc trường |
| Lifecycle | Active / suspended / deleted | Active / Graduated / Withdrawn |
| Số bản ghi | 1 user = 1 row | 1 user = 0 hoặc 1 student record |
| Quản lý | Tenant Admin | Training Manager |
Student là rich data, không phải vai trò
Student record là dữ liệu hồ sơ với lifecycle, code, dates — không phải vai trò đăng nhập. Một học viên có cả: tài khoản User (để đăng nhập) + Student record (mã học viên + lifecycle trường).
Vào quản lý Students
Sidebar → Đào tạo → Học viên (URL: /admin/students).
Bảng list hiển thị:
| Cột | Mô tả |
|---|---|
Mã học viên (student_code) | Searchable, sortable, copyable |
| Họ tên | users.first_name + last_name |
users.email | |
| Trạng thái | Active / Graduated / Withdrawn — badge màu |
| Lớp đang học | active_batches_count — số batch_user ở trạng thái active |
| Ngày nhập học | admitted_at |
Filter: status, soft-deleted records (TrashedFilter).
Mặc định sort theo admitted_at desc — học viên mới nhất lên đầu.
Auto-admit khi attach Batch
Listener EnsureStudentForBatchMember chạy mỗi khi event UserJoinedBatch dispatch:
- User được attach vào một Batch (qua BatchResource Users tab, import CSV, hoặc tạo trực tiếp).
- Hệ thống kiểm tra: User đã có Student record chưa?
- Chưa → tạo mới với:
user_id= Userstudent_code= auto-generate theo pattern (xem Student code)status=activeadmitted_at=now()
- Đã có → giữ nguyên (idempotent).
→ Bạn không cần tạo Student thủ công cho cohort B2B import — chỉ cần attach vào Batch là đủ.
Tạo Student thủ công
Trường hợp cần tạo Student không qua Batch (vd: học viên đã đăng ký nhưng chưa vào lớp):
- Click Tạo mới trong Học viên.
- Form:
- Tài khoản (
user_id) — chọn User đã có (autocomplete email/tên). User chưa có → đề nghị Tenant Admin tạo trước qua User Management. - Mã học viên (
student_code) — để trống để auto-generate, hoặc nhập tay (unique). - Trạng thái (
status) — mặc địnhActive. - Ngày nhập học (
admitted_at) — mặc định hôm nay. - Ngày tốt nghiệp / Ngày thôi học (tuỳ chọn — set khi cần).
- Ghi chú (text — note nội bộ ngắn gọn).
- Section Thông tin cá nhân (tuỳ chọn) — xem Thông tin cá nhân bên dưới.
- Tài khoản (
- Click Lưu.
Thông tin cá nhân
Form học viên có section Thông tin cá nhân:
| Trường | Ràng buộc |
|---|---|
| Ngày sinh | Không quá hôm nay |
| Số CCCD | 12 chữ số (hoặc CMND cũ 9 chữ số) |
| Ngày cấp CCCD | Không trước ngày sinh, không quá hôm nay |
| Địa chỉ | Tự do |
Ai thấy số CCCD?
Số CCCD và Ngày cấp CCCD chỉ hiện cho người có quyền sửa hồ sơ học viên (Quản lý đào tạo, Tenant Admin). Giảng viên xem hồ sơ trong Trainer Panel hay trong cửa sổ xem nhanh ở trang lớp không thấy hai trường này; ngày sinh và địa chỉ thì vẫn thấy. Quy tắc này áp cả cho file xuất danh sách.
UNIQUE constraint
user_idUNIQUE trongstudents— một User chỉ có một Student record. Lỗi khi cố tạo duplicate.student_codeUNIQUE — mã học viên không trùng. Lỗi nếu nhập trùng.- Trường
user_idkhông sửa được sau khi tạo (tránh phá liên kết).
Student code
student_code là định danh trường cấp cho học viên — hiển thị trên hồ sơ, certificate (nếu cấu hình), báo cáo gửi B2B.
Auto-generate pattern
Khi để trống ở form, hệ thống generate theo pattern cấu hình với atomic counter:
- Mặc định:
CGA{seq:4}→CGA0001,CGA0002, ... - Cấu hình ở Cài đặt → Chung → tab Mã học viên (Tenant Admin, quyền
configure_student_code). - Counter atomic per-tenant — không trùng dù nhiều admin tạo cùng lúc.
Token dùng được trong mẫu:
| Token | Nghĩa | Ví dụ (tháng 5/2026, số thứ tự 1) |
|---|---|---|
{YYYY} | Năm 4 chữ số | 2026 |
{YY} | Năm 2 chữ số | 26 |
{MM} | Tháng 2 chữ số | 05 |
{seq:N} | Số thứ tự, đệm 0 cho đủ N chữ số | {seq:4} → 0001 |
Token không nhận ra được giữ nguyên nguyên văn. Ví dụ: SA{MM}{YY}{seq:3} → SA0526001.
Ghi đè thủ công
Nhập student_code tuỳ ý khi tạo / edit — vd: tổ chức có sẵn mã 2026-MARKETING-001. Validation:
- UNIQUE check trong tenant.
- Max 64 ký tự.
- Cho phép số, chữ, dấu gạch.
Khi nào nên ghi đè?
- Migration từ hệ thống cũ — giữ mã cũ để học viên không bị lạ.
- Cohort doanh nghiệp với mã của khách hàng — vd:
ACME-2026-CTO. - Pattern khác mặc định — vd: theo lớp
K12-CN-001.
Lifecycle: Admit → Graduate / Withdraw
Status enum StudentStatus:
| Status | Khi nào | Kèm field |
|---|---|---|
| Active | Mặc định khi tạo | admitted_at |
| Graduated | Đánh dấu tốt nghiệp | graduated_at |
| Withdrawn | Đánh dấu thôi học | withdrawn_at |
Học viên ở status Graduated / Withdrawn không xuất hiện ở danh sách lớp đang học (filter UI).
Action: Tốt nghiệp (Graduate)
Action chỉ hiện khi student Active.
- Trong bảng list → row → Tốt nghiệp.
- Modal:
- Ngày tốt nghiệp (mặc định hôm nay).
- Confirm.
- Hệ thống:
status=Graduatedgraduated_at= ngày bạn chọn.- Không tự động đóng các BatchEnrollment đang active. Bạn có thể tách bằng cách Complete enrollment trước hoặc để hệ thống tự auto-complete khi Batch chuyển sang Completed.
Action: Cho thôi học (Withdraw)
- Action Cho thôi học → modal xác nhận:
- Ngày thôi học (mặc định hôm nay).
- Confirm.
status=Withdrawn,withdrawn_at= ngày chọn.- Không tự huỷ BatchEnrollment. Cần Drop từng BatchEnrollment thủ công nếu muốn (qua tab Lớp học của student hoặc qua Batch).
Withdraw ≠ Drop khỏi lớp
Withdraw là school-level (rời trường). Drop là batch-level (rời một lớp). Học viên có thể:
- Drop khỏi lớp A nhưng vẫn Active ở trường (vì còn lớp B).
- Withdraw khỏi trường nhưng không tự động Drop lớp đang học.
Quy ước thực tế: thường khi Withdraw, bạn cũng Drop tất cả lớp active của họ. Workflow đề xuất: Withdraw → mở tab Ghi danh → Drop từng BatchEnrollment.
Action: Khôi phục (Reactivate)
Action chỉ hiện khi status là Graduated hoặc Withdrawn:
- Click Khôi phục → modal confirm.
status=Active, cleargraduated_at/withdrawn_at.
Hữu ích khi:
- Quay lại học sau thời gian gián đoạn.
- Nhầm tốt nghiệp / thôi học (bấm sai).
Bulk actions
Bảng list hỗ trợ:
- Tốt nghiệp đã chọn (bulk) — tick nhiều rows → bulk graduate với cùng
graduated_at. - Cho thôi học đã chọn — tương tự cho withdraw.
Cuối cohort
Khi cohort kết thúc + tất cả học viên pass:
- Bulk graduate học viên cohort đó.
- Optionally — Complete BatchEnrollment riêng từng người.
- Chuyển Batch → status
Completed(auto-complete remaining enrollments).
Hồ sơ chi tiết Student
Click vào dòng → trang Xem (/admin/students/{id}).
Hồ sơ Student vs Hồ sơ học tập 360°
Trang này là hồ sơ học viên của trung tâm — mã, lifecycle, điểm danh, đơn từ. Muốn nhìn TOÀN BỘ việc học của người đó (kể cả khoá tự học, chứng chỉ, gói thuê bao, luyện tập, lộ trình) thì mở Hồ sơ học tập 360° từ danh sách Người dùng. Tỉ lệ điểm danh ở hai nơi dùng chung một công thức nên luôn khớp.
Trang hồ sơ có 3 section + 3 relation managers:
Section 1 — Hồ sơ (Profile)
Read-only metadata:
- Mã học viên (copyable)
- Họ tên + email
- Trạng thái (badge)
- Ngày nhập học / tốt nghiệp / thôi học
- Ghi chú (free text)
- Số điện thoại (lấy từ tài khoản) và section Thông tin cá nhân (số CCCD chỉ hiện cho người có quyền sửa hồ sơ)
Section 2 — Tóm tắt điểm danh (Cross-batch attendance)
Tự động tính qua StudentAttendanceSummaryService:
- Tỉ lệ điểm danh tổng thể — session-weighted (không phải avg đơn giản).
- Phân tích theo từng lớp — % per batch.
- 5 buổi vắng gần nhất — với ngày + tên buổi + lý do.
Color-coded:
- ≥ 85% — xanh (success)
- 70–84% — vàng (warning)
- < 70% — đỏ (danger)
Session-weighted khác avg đơn giản
Học viên qua 2 lớp:
- Lớp A: 8/10 buổi (80%) — held 10 sessions.
- Lớp B: 5/5 buổi (100%) — held 5 sessions.
Avg đơn giản: (80 + 100) / 2 = 90%. Session-weighted: (8+5) / (10+5) = 86.7%.
Service dùng session-weighted — phản ánh đúng tải học thật.
Empty state: nếu chưa có buổi nào held trong các lớp của học viên, hiển thị "Chưa có buổi học nào trong các lớp của học viên này."
Section 3 — Bảng điểm tổng hợp (Transcript)
Per-batch transcript qua StudentTranscriptService. Mặc định collapsed — click để mở.
Mỗi batch hiển thị:
- Tên + mã lớp
joined_at/exited_at(nếu có)- BatchEnrollment status (Active / Suspended / Transferred Out / Dropped / Completed)
- Cho mỗi khoá thuộc Program:
- Tên khoá
- % tiến độ + completion flag
- Hoạt động gần nhất (timestamp)
Bao gồm cả enrollment đã đóng
Transcript bao gồm cả transferred_out, dropped, completed — đây là bản ghi authoritative "học viên đã đi qua đâu", không phải snapshot hiện tại. Nếu chỉ muốn xem nơi đang học, dùng widget active_batches_count trong list.
Relation manager 1 — Ghi danh (BatchEnrollments)
Tab/section quản lý ghi danh từng lớp của học viên:
- Bảng tất cả
batch_userrecords (active + closed). - Header action Ghi danh vào lớp — mở modal chọn Batch active → tạo enrollment mới.
- Per-row actions: Chuyển lớp, Tạm dừng, Khôi phục, Cho thôi học (Drop), Hoàn tất.
Chi tiết quy trình: xem Ghi danh & Chuyển lớp và Chuyển lớp (Batch Transfer).
Relation manager 2 — Ghi chú (StudentNotes)
Notes timeline cho học viên này. Xem Ghi chú học viên cho chi tiết.
Relation manager 3 — Lịch sử chuyển lớp (Transfers)
Read-only audit log của tất cả lần chuyển lớp:
- Lớp đi → lớp đến
- Người thực hiện (
transferred_by) - Thời điểm
- Lý do
Không sửa được record này (chỉ tạo qua Transfer action).
Import học viên CSV (cho roster)
Khác với Import học viên vào Batch (tạo User + attach Batch), import vào StudentResource chỉ tạo Student record cho User đã tồn tại.
Khi nào dùng?
- Migration từ hệ thống cũ — bạn có CSV với danh sách học viên + mã cũ + ngày nhập học.
- Backfill data sau khi tạo nhiều User qua kênh khác mà chưa có Student record.
Format CSV
csv
email,student_code,admitted_at,notes,date_of_birth,citizen_id,citizen_id_issued_on,address
hung@example.com,STD-2024-001,2024-09-01,Chuyển từ chi nhánh HCM,15/03/2001,001201012345,20/05/2021,Hà Nội
lan@example.com,,2026-04-15,,,,,| Cột | Bắt buộc | Mô tả |
|---|---|---|
email | ✅ | Phải khớp với User đã tồn tại |
student_code | ⬜ | Trống → auto-generate |
admitted_at | ⬜ | Trống → now() |
notes | ⬜ | Free text |
date_of_birth | ⬜ | Ngày sinh |
citizen_id | ⬜ | Số CCCD 12 số (hoặc CMND 9 số) |
citizen_id_issued_on | ⬜ | Ngày cấp CCCD — không trước ngày sinh |
address | ⬜ | Địa chỉ |
Ngày ghi dạng 2001-03-15 hoặc 15/03/2001; không nhận ngày trong tương lai. Tệp tối đa 10MB, mã hoá UTF-8.
Bổ sung thông tin cho học viên đã có
Với người đã là học viên, dòng có ít nhất một ô thông tin cá nhân sẽ được xếp loại Cập nhật hồ sơ: chỉ các ô có giá trị được ghi vào hồ sơ, ô trống giữ nguyên dữ liệu cũ, mã học viên không đổi. Việc cập nhật này chỉ dành cho người có quyền sửa hồ sơ học viên; người không có quyền đó sẽ thấy những dòng này ở loại Đã là học viên (bỏ qua).
Quy trình
- Header Nhập học viên → upload CSV.
- Preview hiển thị tóm tắt:
- Sẵn sàng (
ready) — sẽ được tạo - Cập nhật hồ sơ (
update) — học viên đã có, bổ sung thông tin cá nhân - Đã là học viên (
already_student) — User đã có Student record (skip) - Không có user (
no_user) — email không khớp User nào (skip) - Không hợp lệ (
invalid) — email malformed (skip) - Trùng lặp (
duplicate) — email xuất hiện 2 lần trong file (skip dòng sau)
- Sẵn sàng (
- Confirm → Import.
- Kết quả: "Đã nhập mới X, cập nhật Y trên tổng Z dòng."
Backfill từ legacy
Có lệnh artisan riêng php artisan training:backfill-students quét tất cả User đã thuộc Batch nhưng chưa có Student record → tạo bulk. Hữu ích khi update từ phiên bản cũ. Liên hệ Tenant Admin / Central Admin để chạy.
Export roster (xuất danh sách)
Header Xuất danh sách → modal:
- Định dạng: CSV / XLSX.
- Phạm vi: theo filter hiện tại (vd: filter
Activerồi export → chỉ xuất Active students). - Download → file kèm tất cả cột visible.
Dashboard widgets (Tenant Admin / Training Manager)
StudentStatsOverview
Stats overview widget hiển thị 4 ô:
| Ô | Ý nghĩa |
|---|---|
| Học viên đang học | count(status = active) — đang nhập học |
| Đã tốt nghiệp | count(status = graduated) — tích luỹ |
| Đã thôi học | count(status = withdrawn) — tích luỹ |
| Tỷ lệ thôi học | withdrawn / (active + graduated + withdrawn) — color-coded |
Tỉ lệ thôi học:
- < 5% — xanh (success)
- 5–15% — vàng (warning)
15% — đỏ (danger)
AdmissionsTrendChart
Bar chart số học viên nhập học mỗi tháng trong 12 tháng gần nhất.
Sort theo admitted_at. Buckets gom trong PHP để portable giữa MariaDB / SQLite test.
Đọc trend
- Đỉnh tháng 4 + tháng 9 — đầu kỳ học (đa số tổ chức trường).
- Sụt bất thường → có thể marketing yếu / sự kiện ảnh hưởng.
- Tăng đều → growth healthy.
Quan hệ với các module khác
Với UserManagement
- Student
belongsToUser. - Soft delete User → cascade soft delete Student (tuỳ migration config).
- Hard delete User → cascade FK rules.
Với TrainingManagement (Batch)
- Student có nhiều BatchEnrollment qua relation
batchEnrollments(FK quauser_id, không phảistudent_id— vì BatchUser pivot dùnguser_id). - Auto-create student listener:
EnsureStudentForBatchMember.
Với Gamification
- Student không có rule riêng — gamification dựa trên User.
- Có thể tạo rule custom "đạt huy hiệu khi tốt nghiệp" — đề nghị Tenant Admin cấu hình qua module Gamification.
Với Certificate
- Certificate gắn với
User + Course, không gắnStudent. - Tuy nhiên template chứng chỉ có thể nhúng
student_codequa biến — yêu cầu Course Manager template.
Với Notifications
- Auto-events:
StudentAdmitted,StudentTransferred,BatchEnrollmentStatusChanged— Tenant Admin có thể cấu hình email template tương ứng.
Câu hỏi thường gặp
Học viên cũ chưa có Student record — phải làm gì? Chạy php artisan training:backfill-students (Tenant Admin/Central Admin). Hoặc tạo thủ công từng người.
Một User có thể là 2 học viên với 2 mã khác nhau? Không. UNIQUE(user_id) trong students. Nếu cần đa-cohort với mã khác, đây là design choice — đề xuất Tenant Admin nếu thực sự cần.
Đổi student_code sau khi đã in chứng chỉ? Đổi được nhưng chứng chỉ đã cấp giữ mã cũ (hardcoded vào PDF khi sinh). Nếu cần cấp lại với mã mới, regenerate chứng chỉ — work qua Tenant Admin.
Tôi tạo Student rồi nhưng chưa attach Batch nào — họ có vào Learnspace được không? Có. User vào Learnspace bằng tài khoản — Student record không gate truy cập. Học viên thấy Learnspace trống cho đến khi có Batch / Course enrollment.
Soft-deleted student có hiện ở widget StudentStats không? Không. Widget query withoutTrashed. Tuy nhiên TrashedFilter trong list cho admin xem.
Pattern student_code custom? Cấu hình ở config/trainingmanagement.php hoặc settings — Central Admin set. Hỗ trợ placeholder {YYYY}, {MM}, {counter:N} (zero-padded N digits).
Tôi withdraw nhầm — sao revert nhanh? Action Khôi phục → status về Active, clear withdrawn_at. Đơn giản. BatchEnrollment đã đóng (nếu có) thì không tự mở lại.
Cross-batch attendance summary load chậm? Service query held_session_ids cho mỗi batch + count attended. Học viên qua 10+ batch lớn có thể chậm — nếu thường xuyên, đề xuất Tenant Admin cache/optimize.
Tôi muốn export student với điểm + attendance trong 1 file? Hiện chưa có "consolidated export" trong UI — phải export từng phần. Đề xuất tính năng nếu thường xuyên.
StudentNote có thấy được trong Trainer Panel? Trainer có thể đọc + tạo + sửa note (cùng giới hạn 24h). Tuy nhiên Trainer Panel hiện chưa expose hồ sơ Student riêng; trainer xem note qua Tenant Admin Panel (nếu được Tenant Admin gán quyền vào panel đó).