# Phân Hệ Quản Lý Chấm Thủ Công (Web Exam Grading)
## 04. Cơ Sở Dữ Liệu & Lược Đồ Chi Tiết (Database & Schema Design)

---

### 1. Sơ Đồ Quan Hệ Thực Thể (Entity Relationship Diagram - ERD)

```mermaid
erDiagram
    TEACHER_ASSIGNED_HISTORIES ||--|| STUDENT_EXAM_HISTORIES_TEACHERS : "student_exam_histories_teacher_id"
    TEACHER_ASSIGNED_HISTORIES }o--|| STUDENT_SCORE : "student_score_id"
    TEACHER_ASSIGNED_HISTORIES }o--|| USERS : "user_id (Giáo viên)"
    TEACHER_ASSIGNED_HISTORIES }o--|| USERS : "assigned_by (Cán bộ gán)"
    
    STUDENT_SCORE ||--o{ STUDENT_EXAM_HISTORIES : "student_score_id"
    STUDENT_SCORE ||--o{ STUDENT_SCORE_GRADING_HISTORIES : "student_score_id"
    STUDENT_SCORE }o--|| STUDENTS : "student_id"
    STUDENT_SCORE }o--|| API_MOODLE : "quiz_id (moodle_id)"
    
    STUDENTS ||--o{ COURSE_STUDENT : "student_id"
    CLASSES ||--o{ COURSE_STUDENT : "class_id"

    API_MOODLE ||--o{ API_MOODLE : "parent_id (Category -> Course -> Section -> Quiz)"

    TEACHER_ASSIGNED_HISTORIES {
        bigint id PK "ID Khóa chính"
        bigint student_score_id FK "ID bài thi (student_score.id)"
        bigint student_exam_histories_teacher_id FK "ID phân công kỹ năng (seht.id)"
        bigint user_id FK "ID Giáo viên được phân công (users.id)"
        bigint assigned_by FK "ID Người thực hiện phân công"
        tinyint assign_type "1: Chấm lần 1 (Grading), 2: Chấm phúc khảo (Regrading)"
        datetime assigned_at "Thời điểm bắt đầu phân chấm"
        datetime expires_at "Hạn chót hoàn thành chấm (Deadline)"
        tinyint status "0: Đang chấm, 1: Đã hoàn thành, 2: Đã thu hồi/chuyển giao"
        timestamp created_at "Thời gian tạo"
        timestamp updated_at "Thời gian cập nhật"
    }

    STUDENT_EXAM_HISTORIES_TEACHERS {
        bigint id PK "ID Khóa chính"
        bigint student_score_id FK "ID bài thi (student_score.id)"
        bigint student_exam_history_id FK "ID part thi (student_exam_histories.id)"
        int skill "Mã kỹ năng: 15 (Writing), 16 (Speaking)"
        timestamp created_at "Thời gian tạo"
        timestamp updated_at "Thời gian cập nhật"
    }

    STUDENT_SCORE_GRADING_HISTORIES {
        bigint id PK "ID Khóa chính"
        bigint student_score_id FK "ID bài thi"
        tinyint assign_type "1: Chấm lần 1, 2: Phúc khảo"
        longtext data_ems_snapshot "JSON Snapshot điểm thi sau khi chấm"
        decimal overall_score "Điểm tổng chốt của lượt chấm"
        timestamp created_at "Thời điểm chốt điểm"
    }

    STUDENT_SCORE {
        bigint id PK "ID Khóa chính"
        bigint student_id FK "ID Học viên"
        bigint quiz_id FK "ID Bài Quiz (api_moodle.moodle_id)"
        tinyint exam_status "0: Chờ nộp, 1: Đã nộp, 2: Không nộp"
        tinyint score_processing_status "0: Đang xử lý, 1: Hoàn tất, 2: Giao chấm lại"
        longtext abnormal_reasons "JSON lưu lý do bài thi bất thường"
        timestamp created_at "Thời gian nộp bài"
    }
```

---

### 2. Chi Tiết Lược Đồ Bảng (Data Dictionary & Column Comments)

#### 2.1. Bảng `teacher_assigned_histories` (Bảng Phân Công Chấm Thi - Bảng Gốc)
- **Mô tả**: Lưu trữ chi tiết từng lượt gán giáo viên chấm thi cho từng kỹ năng của bài làm học viên.
- **Engine**: InnoDB | **Charset**: `utf8mb4_unicode_ci`

| Tên Cột | Kiểu Dữ Liệu | Nullable | Mặc định | Chú Thích (Comment) Chi Tiết |
| :--- | :--- | :---: | :---: | :--- |
| `id` | `BIGINT UNSIGNED` | NO | Auto Increment | Khóa chính của bản ghi phân công chấm. |
| `student_score_id` | `BIGINT UNSIGNED` | NO | | ID bài thi gốc trong bảng `student_score.id`. |
| `student_exam_histories_teacher_id` | `BIGINT UNSIGNED` | YES | `NULL` | ID liên kết sang bảng `student_exam_histories_teachers.id` để xác định kỹ năng chấm (`skill`). |
| `user_id` | `BIGINT UNSIGNED` | YES | `NULL` | ID tài khoản Giáo viên được phân công chấm (`users.id`). |
| `assigned_by` | `BIGINT UNSIGNED` | YES | `NULL` | ID Cán bộ vận hành thực hiện thao tác phân công (`users.id`). |
| `assign_type` | `TINYINT` | NO | `1` | Phân loại lượt chấm:<br>• `1`: Chấm lần 1 (Dành riêng cho module `web_exam_grading`)<br>• `2`: Chấm phúc khảo (Module `web_exam_regrading`) |
| `assigned_at` | `DATETIME` | YES | `NULL` | Mốc thời gian bắt đầu phân công chấm cho giáo viên. |
| `expires_at` | `DATETIME` | YES | `NULL` | Mốc thời hạn chót giáo viên phải hoàn thành bài chấm (Deadline). |
| `status` | `TINYINT` | NO | `0` | Trạng thái lượt phân công:<br>• `0`: Chờ chấm / Đang chấm<br>• `1`: Đã hoàn thành chấm<br>• `2`: Đã thu hồi / Chuyển giao giáo viên khác |
| `created_at` | `TIMESTAMP` | YES | `NULL` | Thời điểm tạo bản ghi phân công. |
| `updated_at` | `TIMESTAMP` | YES | `NULL` | Thời điểm cập nhật trạng thái phân công. |

##### Danh sách Chỉ Mục (Indexes):
- `PRIMARY KEY (`id`)`
- `INDEX idx_student_score (`student_score_id`)`
- `INDEX idx_seht_id (`student_exam_histories_teacher_id`)`
- `INDEX idx_user_id (`user_id`)`: Tối ưu lọc danh sách bài chấm theo giáo viên.
- `INDEX idx_assign_type (`assign_type`)`: Tối ưu lọc theo lượt chấm lần 1 vs phúc khảo.
- `INDEX idx_status (`status`)`
- `INDEX idx_assigned_at (`assigned_at`)`

---

#### 2.2. Bảng `student_exam_histories_teachers` (Kỹ Năng Phân Công Chấm)
- **Mô tả**: Bảng trung gian định nghĩa kỹ năng (Writing / Speaking) được giao chấm cho bài thi.

| Tên Cột | Kiểu Dữ Liệu | Nullable | Chú Thích (Comment) Chi Tiết |
| :--- | :--- | :---: | :--- |
| `id` | `BIGINT UNSIGNED` | NO | Khóa chính. |
| `student_score_id` | `BIGINT UNSIGNED` | NO | ID bài thi gốc (`student_score.id`). |
| `student_exam_history_id`| `BIGINT UNSIGNED`| YES | ID Part kỹ năng trong `student_exam_histories.id`. |
| `skill` | `INT` | NO | Mã định danh kỹ năng: `15` (Writing), `16` (Speaking). |
| `created_at` | `TIMESTAMP` | YES | Thời điểm khởi tạo. |
| `updated_at` | `TIMESTAMP` | YES | Thời điểm cập nhật. |

---

#### 2.3. Bảng `student_score_grading_histories` (Snapshot Điểm Sau Review)
- **Mô tả**: Lưu trữ snapshot toàn bộ cấu trúc điểm thi sau khi giáo viên hoặc QA hoàn thành chấm.

| Tên Cột | Kiểu Dữ Liệu | Nullable | Chú Thích (Comment) Chi Tiết |
| :--- | :--- | :---: | :--- |
| `id` | `BIGINT UNSIGNED` | NO | Khóa chính. |
| `student_score_id` | `BIGINT UNSIGNED` | NO | ID bài thi gốc. |
| `assign_type` | `TINYINT` | NO | `1`: Chấm lần 1, `2`: Chấm phúc khảo. |
| `data_ems_snapshot`| `LONGTEXT` | YES | Chuỗi JSON chứa toàn bộ điểm số các vòng thi (`rounds`), điểm tiêu chí và điểm Overall tại thời điểm chốt kết quả. |
| `overall_score` | `DECIMAL(4,2)` | YES | Điểm Overall chính thức của bài thi. |
| `created_at` | `TIMESTAMP` | YES | Thời điểm lưu snapshot kết quả chấm. |
