<aside> <img src="/icons/checklist_green.svg" alt="/icons/checklist_green.svg" width="40px" />
</aside>
Table lessons [note: 'Bảng quản lý lesson (bài học) trong module']
{
id uuid [pk, note: 'Khóa chính của lesson']
module_id uuid [ref: > modules.id, note: 'Thuộc module nào']
title varchar [not null, note: 'Tiêu đề bài học']
description text [not null]
type lesson_types [not null, note: 'Loại: video/article/quiz/practice']
is_previewable bool [default: false, note: 'Cho phép xem preview không']
status lesson_status [default: 'draft', note: 'draft/published/archived']
order int [default: 0, note: 'Thứ tự trong module']
attachment varchar [null]
created_at timestamp [default: `now()`, note: 'Tạo lúc']
updated_at timestamp [default: `now()`, note: 'Cập nhật lần cuối']
deleted_at timestamp [null, note: 'Soft-delete']
}
Table video_lessons [note: 'Chi tiết lesson loại video']
{
lesson_id uuid [pk, ref: > lessons.id, note: 'Liên kết lesson loại video']
video_url varchar [not null, note: 'Link Vimeo lưu trữ video']
duration int [not null, note: 'Độ dài video (giây)']
notes text [note: 'Nội dung HTML chi tiết']
}
Table article_lessons [note: 'Chi tiết lesson loại bài viết HTML']
{
lesson_id uuid [pk, ref: > lessons.id, note: 'Liên kết lesson loại article']
html_content text [note: 'Nội dung HTML chi tiết']
duration int [not null, note: 'Thời gian đọc đề xuất']
}
Table practice_lessons [note: 'Chi tiết lesson dạng bài tập (practice)']
{
lesson_id uuid [pk, ref: > lessons.id, note: 'Liên kết lesson practice']
title varchar [not null, note: 'Tiêu đề bài tập']
description text [not null, note: 'Nội dung yêu cầu bài tập']
type practice_type [not null, note: 'coding/writing/upload_file']
deadline timestamp [note: 'Hạn nộp bài (nếu có)']
}
Table quiz_lessons [note: 'Chi tiết lesson loại quiz']
{
lesson_id uuid [pk, ref: > lessons.id, note: 'Liên kết lesson quiz']
passing_score int [note: 'Điểm tối thiểu để qua (%)']
deadline timestamp [null, note: 'Hạn nộp bài (nếu có)']
time_limit_min int [null, note: 'Giới hạn thời gian làm (phút)']
}
Table quiz_questions [note: 'Câu hỏi trong quiz']
{
id uuid [pk, note: 'Khóa chính câu hỏi']
lesson_id uuid [ref: > quiz_lessons.lesson_id, note: 'Thuộc quiz nào']
content text [not null, note: 'Nội dung câu hỏi']
order int [default: 0, note: 'Thứ tự trong quiz']
type quiz_type [default: 'single_choice', note: 'single/multi/short_answer']
status product_status [default: 'draft']
}
Table quiz_options [note: 'Các lựa chọn cho mỗi câu hỏi quiz']
{
id uuid [pk, note: 'Khóa chính đáp án']
question_id uuid [ref: > quiz_questions.id, note: 'Thuộc câu hỏi nào']
content text [not null, note: 'Nội dung đáp án']
is_correct bool [default: false, note: 'Đánh dấu đáp án đúng']
explanation text [note: 'Giải thích đáp án đúng']
}
lesson.module_id phải tham chiếu đến một modules.id tồn tại và deleted_at IS NULL.title: Bắt buộc, độ dài 1–150 ký tự.description: Bắt buộc, độ dài ≥ 10 ký tự.type: Enum video | article | quiz | practice.is_previewable: Boolean, mặc định false. Chỉ cho preview với video hoặc article.status: Enum draft → published → archived.
draft → published (khi nội dung đủ điều kiện)published → archivedarchived → (chỉ qua draft bởi command phục hồi)order: Số nguyên ≥ 0; trong cùng Module phải unique.