# Module `vehicle` — Xe tập lái

> 07/7/2026 · Giai đoạn: **MVP** · Bản HTML: [vehicle.html](vehicle.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 code: **đã scaffold** bảng xe (port legacy) — cần thêm `license-doc`, hoàn thiện `device-bind`.

## 1. Vai trò
Quản lý **xe tập lái**: đăng ký hành chính, **giấy tờ + hạn** (giấy phép xe tập, đăng kiểm, bảo hiểm), và **gắn thiết bị DAT**. Vận hành chi phí (nhiên liệu, bảo dưỡng) thuộc `fleet` (v1.5).

## 2. Feature / BO / Action

| Feature | BO chính | Action |
|---|---|---|
| `vehicle` | Xe tập lái | view·create·edit·delete·export |
| `license-doc` | Giấy phép xe tập, đăng kiểm, bảo hiểm (hạn) | view·create·edit·configure |
| `device-bind` | Gắn/tháo thiết bị DAT | view·**assign** |

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

### Xe tập lái (`vehicle`) — *bảng đã có*
Mã xe (`ma_xe`), biển số, chủ sở hữu, hạng GPLX, năm SX, loại xe, số đăng ký, số giấy phép + ngày cấp/hết hạn, thiết bị DAT (`seri_dat`), trạng thái. UNIQUE `(ma_xe, ma_csdt)`.

### Giấy tờ xe (`license-doc`) — *mới, tách bảng riêng để 1 xe nhiều loại giấy*
| Trường | Kiểu | Ghi chú |
|---|---|---|
| Xe | ref | |
| Loại giấy tờ | enum | giấy phép xe tập lái / đăng kiểm / bảo hiểm TNDS / phù hiệu |
| Số hiệu, nơi cấp | text | |
| Ngày cấp / **ngày hết hạn** | date | nguồn cho notify nhắc hạn |
| File scan | file | |

### Gắn thiết bị (`device-bind`) — *lịch sử gắn/tháo*
Xe × thiết bị DAT (`seri_dat`), ngày gắn / ngày tháo, người thao tác — giữ lịch sử để đối chiếu phiên DAT theo thời điểm.

## 4. Quy tắc nghiệp vụ
1. Xe dạy thực hành phải có **giấy phép xe tập lái còn hạn + đăng kiểm còn hạn + đã gắn DAT hợp quy** — thiếu một điều kiện → chặn phân công.
2. Xe phải **khớp danh sách xe đã đăng ký với Sở** — lệch → cảnh báo (đồng bộ quy tắc với course/teacher).
3. Lịch sử gắn/tháo DAT là **append-only** — căn cứ xác định phiên học thuộc thiết bị nào tại thời điểm nào.
4. Hết hạn giấy tờ → notify nhắc trước theo ngưỡng cấu hình (30/15/7 ngày).

## 5. Liên kết chéo module
| Module | Khóa | Ghi chú |
|---|---|---|
| course | `ma_xe` | phân công xe theo khóa |
| dat | `seri_dat` | phiên học thuộc thiết bị → xe |
| notify | hạn giấy tờ xe | nhắc hạn |
| fleet (v1.5) | `ma_xe` | nhiên liệu, bảo dưỡng, chi phí |

## 6. Câu hỏi mở
- Danh mục loại giấy tờ xe đầy đủ theo quy định (phù hiệu? camera giám sát?).
- Xe thuê ngoài/liên kết có quản lý khác xe sở hữu không?

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

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

```json
[
  {
    "group": "main",
    "feature": "vehicle",
    "label": "Xe tập lái",
    "actions": [
      "view",
      "create",
      "edit",
      "delete",
      "export"
    ]
  },
  {
    "group": "main",
    "feature": "license-doc",
    "label": "Giấy tờ xe",
    "actions": [
      "view",
      "create",
      "edit",
      "configure"
    ]
  },
  {
    "group": "main",
    "feature": "device-bind",
    "label": "Gắn/tháo DAT",
    "actions": [
      "view",
      "assign"
    ]
  }
]
```


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

| Feature | `QTHT` | `GIAM_DOC` | `KY_THUAT` | `QL_DAO_TAO` | `GIAO_VU` |
|---|:--:|:--:|:--:|:--:|:--:|
| `vehicle` | R | R | W | R | R |
| `license-doc` | R | R | W | — | — |
| `device-bind` | R | R | W | 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 đủ: `vehicle.main.<feature>.<action>`.
> Đặc thù: device-bind +assign (KY_THUAT)
