# Module `lms` — Lý thuyết đạt chuẩn giám sát

> 07/7/2026 · Giai đoạn: **v1.5** · WS đào tạo · Bản HTML: [lms.html](lms.html) · Sơ đồ tổng thể: [../so-do-ws-module-feature-2026-07-06.md](../so-do-ws-module-feature-2026-07-06.md)
> Trạng thái: Chưa có trong code — scaffold ở v1.5.

## 1. Vai trò
Dạy – học **lý thuyết đạt chuẩn giám sát học từ xa**: lớp/buổi học, điểm danh khuôn mặt, ngân hàng 600 câu (config), thi thử và kết quả xét điều kiện. Terminal khuôn mặt **mua ngoài** — chỉ viết tích hợp.

## 2. Feature / BO / Action

| Feature | BO chính | Action |
|---|---|---|
| `class` | Lớp / buổi học lý thuyết | view·create·edit |
| `attendance` | Điểm danh khuôn mặt (log hợp lệ) | view·export·**checkin** |
| `question-bank` | Ngân hàng 600 câu (config theo bộ đề) | view·import·configure |
| `mock-exam` | Thi thử + kết quả | view·create·**score** |
| `result` | Kết quả học lý thuyết (xét điều kiện) | view·approve·report |

## 3. Dữ liệu chính

| BO | Trường chính |
|---|---|
| **Lớp/buổi học** | Khóa · môn (ref catalog) · GV · phòng · lịch · hình thức (tập trung / từ xa) |
| **Điểm danh** | Buổi × học viên · phương thức (khuôn mặt/RFID) · ảnh chụp · thời điểm vào/ra — **log sinh dữ liệu hợp lệ theo chuẩn giám sát** |
| **Ngân hàng câu hỏi** | 600 câu theo bộ đề hiện hành · chương/mục · câu điểm liệt · phiên bản bộ đề (đổi đề = cập nhật config) |
| **Kết quả** | Học viên × môn · số giờ đã học · điểm thi thử · trạng thái đạt/chưa đạt |

## 4. Quy tắc nghiệp vụ
1. Học từ xa một phần được phép nhưng phải **sinh dữ liệu hợp lệ**: log thời gian học + điểm danh khuôn mặt
2. Ngân hàng 600 câu là **dữ liệu cấu hình** — bộ đề đổi thì cập nhật, không sửa code
3. Kết quả lý thuyết đạt là **điều kiện** trong hồ sơ xét hoàn thành (student/report)
4. Câu điểm liệt xử lý đúng luật thi (sai điểm liệt = trượt thi thử)

## 5. Liên kết chéo
- **student** — kết quả lý thuyết vào hồ sơ
- **catalog** — môn học, bộ đề
- **rfcard** — điểm danh kết hợp
- **report** — số giờ học vào báo cáo
- **portal** — ôn tập/thi thử trên app

## 6. Câu hỏi mở
- Chuẩn giám sát học từ xa chi tiết theo TT 17/2026-BXD (log gì, lưu bao lâu)?
- Terminal khuôn mặt chọn hãng nào — API tích hợp?

## 7. Ma trận phân quyền (→ manifest & seed role)

### 7.1 Khai báo `permissions[]` trong `manifest.json`

```json
[
  {
    "group": "main",
    "feature": "class",
    "label": "Lớp/buổi lý thuyết",
    "actions": [
      "view",
      "create",
      "edit"
    ]
  },
  {
    "group": "main",
    "feature": "attendance",
    "label": "Điểm danh",
    "actions": [
      "view",
      "export",
      "checkin"
    ]
  },
  {
    "group": "main",
    "feature": "question-bank",
    "label": "Ngân hàng 600 câu",
    "actions": [
      "view",
      "import",
      "configure"
    ]
  },
  {
    "group": "main",
    "feature": "mock-exam",
    "label": "Thi thử",
    "actions": [
      "view",
      "create",
      "score"
    ]
  },
  {
    "group": "main",
    "feature": "result",
    "label": "Kết quả lý thuyết",
    "actions": [
      "view",
      "approve",
      "report"
    ]
  }
]
```

> ⚠️ Action đặc thù (`checkin`, `score`) cần bổ sung vào validator manifest — xem [plan data-scope P1](../giai-doan-1-mvp/plan-data-scope-2026-07-06.md).

### 7.2 Ma trận vai trò × feature (seed `rt_role`)

| Feature | `QTHT` | `GIAM_DOC` | `QL_DAO_TAO` | `GIAO_VU` | `GIAO_VIEN` | `HOC_VIEN` |
|---|:--:|:--:|:--:|:--:|:--:|:--:|
| `class` | R | R | W | W | R¹ | — |
| `attendance` | R | R | R | R | R¹ | — |
| `question-bank` | R | R | W | — | — | — |
| `mock-exam` | R | R | R | W | — | R² |
| `result` | R | R | R·A | R | — | R² |

> **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. Permission key đầy đủ: `lms.main.<feature>.<action>`.
> Đặc thù: attendance +checkin (GIAO_VIEN, HOC_VIEN) · mock-exam score = hệ thống chấm tự động

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

**(a) Manifest — bổ sung `fields` + `scopeVars` vào các feature bị scope** *(mở rộng schema theo [plan data-scope P1](../giai-doan-1-mvp/plan-data-scope-2026-07-06.md) — manifest chỉ khai "cái gì scope được", KHÔNG chứa rule)*:

```json
[
  {
    "group": "main",
    "feature": "class",
    "fields": [
      "giao_vien_id"
    ],
    "scopeVars": [
      "current_giao_vien_id"
    ]
  },
  {
    "group": "main",
    "feature": "attendance",
    "fields": [
      "giao_vien_id",
      "nguoi_lxid"
    ],
    "scopeVars": [
      "current_giao_vien_id",
      "current_nguoi_lxid"
    ]
  },
  {
    "group": "main",
    "feature": "mock-exam",
    "fields": [
      "nguoi_lxid"
    ],
    "scopeVars": [
      "current_nguoi_lxid"
    ]
  },
  {
    "group": "main",
    "feature": "result",
    "fields": [
      "nguoi_lxid"
    ],
    "scopeVars": [
      "current_nguoi_lxid"
    ]
  }
]
```

**(b) Điều kiện record theo vai trò:**

| Vai trò | Feature (action) | Điều kiện record |
|---|---|---|
| `GIAO_VIEN` | class, attendance (view) | giao_vien_id = ctx.current_giao_vien_id (lớp mình dạy) |
| `HOC_VIEN` | mock-exam, result (view) | nguoi_lxid = ctx.current_nguoi_lxid |

**(c) Seed `rt_role.grants` (kind `rule` — nhiều rule cùng resource+action = OR):**

```json
[
  {
    "kind": "rule",
    "module": "lms",
    "feature": "class",
    "actions": [
      "view"
    ],
    "predicate": {
      "op": "cmp",
      "field": "giao_vien_id",
      "cmp": "=",
      "value": {
        "ctx": "current_giao_vien_id"
      }
    }
  },
  {
    "kind": "rule",
    "module": "lms",
    "feature": "attendance",
    "actions": [
      "view"
    ],
    "predicate": {
      "op": "cmp",
      "field": "giao_vien_id",
      "cmp": "=",
      "value": {
        "ctx": "current_giao_vien_id"
      }
    }
  },
  {
    "kind": "rule",
    "module": "lms",
    "feature": "result",
    "actions": [
      "view"
    ],
    "predicate": {
      "op": "cmp",
      "field": "nguoi_lxid",
      "cmp": "=",
      "value": {
        "ctx": "current_nguoi_lxid"
      }
    }
  }
]
```

> Biến ngữ cảnh: `current_user_id` — engine có sẵn · `current_giao_vien_id`/`current_ma_gv` — module teacher tra từ user đăng nhập (ctxVars, plan P3) · `current_nguoi_lxid`/`current_ma_dk_list` — module student tra (1 người nhiều lượt đăng ký) · `current_assigned_*` — danh sách phụ trách/được phân công.
