Exercise AI — Data Entry API
Hợp đồng REST cho soạn nội dung bài Exercise AI (admin/teacher): tạo / sửa / publish bài và import câu hỏi
từ Google Sheet. Base path: /api/v1/exercise-ai (khác /dotest của runtime làm bài). Ý đồ sản phẩm:
Type 1 — Data Entry, Linear Note — Data Entry.
Aggregate: AiExercise
AiExercise extends BaseEditingDocument<AiExercise> (@Document("ai_exercise")) → có vòng đời
draft / editing / published (publish qua DocumentHistoryComponent). Khác với AiUserExerciseProgress
(runtime, một phiên làm bài của học viên) — đây là bài gốc do giáo viên soạn.
| Field | Kiểu | Ý nghĩa |
|---|---|---|
exerciseType | AiExerciseType | Dạng bài (xác định subtype content). |
variant | AiExerciseVariant | Biến thể trong cùng dạng. |
content | BaseAiExerciseContent | Nội dung đa hình theo dạng bài (câu hỏi gốc, gợi ý…). Khác BaseAiExerciseProgressContent của runtime. |
totalQuestion | int | Tổng số câu. |
importUrl | String | Nguồn Google Sheet nếu import. |
Command (mutate)
| Method & path | Body | Response | Mô tả |
|---|---|---|---|
POST / | CreateUpdateAiExerciseDTO (exerciseType*, variant, content, importUrl) | DocumentIdOnly | Tạo bài (draft). Có importUrl → tự nạp câu hỏi từ sheet (REPLACE). Xem luồng tạo/sửa. |
PUT / | CreateUpdateAiExerciseDTO | 204 | Cập nhật bài. importUrl bị bỏ qua khi bài đã có id (không re-import). |
DELETE /{id} | — | 204 | Xóa bài. |
POST /{id}/clone | — | 204 | Nhân bản bài. |
PATCH /{id}/publish | — | 204 | Publish bản hiện tại (qua DocumentHistoryComponent). |
PATCH /{id}/publish-for | UpdatePublishForRequestDto | 204 | Đặt phạm vi publish (AvailableFor). |
PATCH /used | IDsDTO (ids) | 204 | Đánh dấu bulk “đã dùng” theo danh sách id. |
POST /import | ImportAiExerciseFromUrlRequestDTO (exerciseId, url, type) | DocumentIdOnly | Import câu hỏi từ sheet vào bài đã có. type = APPEND (thêm dồn) | OVERRIDE (thay hết). |
Query (read)
| Method & path | Params / Body | Response | Mô tả |
|---|---|---|---|
GET /{id} | — | AiExerciseDTO | Lấy bài theo id. |
POST /bulk | IDsDTO (ids) | List<AiExerciseDTO> | Lấy nhiều bài theo danh sách id. |
POST /import/preview | PreviewImportAiExerciseRequestDTO (url, exerciseType) | ImportPreviewDTO | Xem trước import: thống kê cột/dòng + câu hỏi parse được, trước khi ghi. |
GET /paged | search, exerciseType, publishFor, used, statuses, status, fromDate, toDate, Pageable | Page<AiExercisePageDTO> | Danh sách bài (admin) — lọc đa chiều. |
GET /published/paged | như trên (mặc định publishFor=ALL, ép status=PUBLISHED) | Page<AiExercisePageDTO> | Danh sách bài đã publish. |
Luồng tạo / sửa / import
Câu hỏi của bài có thể nạp từ Google Sheet. Điều kiện nạp không phụ thuộc verb mà theo id: import chỉ tự chạy khi request chưa có id (bài mới) và có importUrl.
Tạo mới — POST / (không id)
- Tạo bài mới từ payload (loại bài, biến thể, nội dung).
- Nếu có
importUrl: đọc sheet → parse câu hỏi theoexerciseType. Sheet rỗng →IMPORT_EMPTY. - REPLACE toàn bộ câu hỏi bằng câu từ sheet (bài mới vốn rỗng), set
totalQuestion+importUrl. - Lưu draft → trả
id.
Sửa — PUT / (có id)
- Tìm bài theo
id, cập nhật nội dung. importUrlbị bỏ qua (vì đã cóid) — sửa bài không tự nạp lại câu hỏi.- Lưu draft/editing.
Gate thật là
id == null, không phải HTTP verb: cùngapplyImportIfPresentchạy ở cả create lẫn update, và skip khiid != null. Muốn nạp lại câu cho bài đã có → dùngPOST /import.
Import cho bài đã có — POST /import
- Tìm bài theo
exerciseId, đọc sheet, parse. Rỗng →IMPORT_EMPTY. - Ghép theo
type:APPEND— giữ câu cũ, nối câu mới vào sau.OVERRIDE— xóa câu cũ, chỉ giữ câu từ sheet.
- Cập nhật
totalQuestion+importUrl, lưu draft/editing.
Xem trước — POST /import/preview: parse sheet và trả thống kê + câu parse được, chưa ghi gì vào bài (kiểm tra định dạng trước khi import thật).
| Đường | Điều kiện | Câu cũ | Kết quả |
|---|---|---|---|
POST / + importUrl | id == null | (bài mới, rỗng) | REPLACE bằng sheet |
PUT / + importUrl | id != null | Giữ nguyên | importUrl bỏ qua |
POST /import APPEND | bài đã có | Giữ + thêm | cũ ∪ mới |
POST /import OVERRIDE | bài đã có | Xóa | chỉ sheet |
POST /import/preview | — | Không đụng | Chỉ preview |
Import preview (ImportPreviewDTO)
| Field | Ý nghĩa |
|---|---|
exerciseType | Dạng bài suy ra từ sheet. |
status | ImportPreviewStatus. |
canImport | Có import được không (đủ cột bắt buộc). |
totalRows | Số dòng trong sheet. |
statistics | List<ImportPreviewStatItemDTO> — mỗi field: field, count, missingColumn. |
questions | List<BaseAiExerciseQuestionDTO> — câu hỏi parse được (preview). |
Lưu ý:
content/BaseAiExerciseContentvàBaseAiExerciseQuestionDTOở đây là mô hình nội dung bài gốc (authoring), tách biệt với mô hình progress của runtime (xem Domain Model). Chi tiết shape nội dung theo từng dạng bài là phần TBD của SRD này.