SRDsExercise AIData Entry API
DraftDT-4662Exercise AISRDAPIRESTDataEntryAuthoring

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.

FieldKiểuÝ nghĩa
exerciseTypeAiExerciseTypeDạng bài (xác định subtype content).
variantAiExerciseVariantBiến thể trong cùng dạng.
contentBaseAiExerciseContentNội dung đa hình theo dạng bài (câu hỏi gốc, gợi ý…). Khác BaseAiExerciseProgressContent của runtime.
totalQuestionintTổng số câu.
importUrlStringNguồn Google Sheet nếu import.

Command (mutate)

Method & pathBodyResponseMô tả
POST /CreateUpdateAiExerciseDTO (exerciseType*, variant, content, importUrl)DocumentIdOnlyTạo bài (draft). Có importUrl → tự nạp câu hỏi từ sheet (REPLACE). Xem luồng tạo/sửa.
PUT /CreateUpdateAiExerciseDTO204Cập nhật bài. importUrl bị bỏ qua khi bài đã có id (không re-import).
DELETE /{id}204Xóa bài.
POST /{id}/clone204Nhân bản bài.
PATCH /{id}/publish204Publish bản hiện tại (qua DocumentHistoryComponent).
PATCH /{id}/publish-forUpdatePublishForRequestDto204Đặt phạm vi publish (AvailableFor).
PATCH /usedIDsDTO (ids)204Đánh dấu bulk “đã dùng” theo danh sách id.
POST /importImportAiExerciseFromUrlRequestDTO (exerciseId, url, type)DocumentIdOnlyImport câu hỏi từ sheet vào bài đã có. type = APPEND (thêm dồn) | OVERRIDE (thay hết).

Query (read)

Method & pathParams / BodyResponseMô tả
GET /{id}AiExerciseDTOLấy bài theo id.
POST /bulkIDsDTO (ids)List<AiExerciseDTO>Lấy nhiều bài theo danh sách id.
POST /import/previewPreviewImportAiExerciseRequestDTO (url, exerciseType)ImportPreviewDTOXem trước import: thống kê cột/dòng + câu hỏi parse được, trước khi ghi.
GET /pagedsearch, exerciseType, publishFor, used, statuses, status, fromDate, toDate, PageablePage<AiExercisePageDTO>Danh sách bài (admin) — lọc đa chiều.
GET /published/pagednhư 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)

  1. Tạo bài mới từ payload (loại bài, biến thể, nội dung).
  2. Nếu có importUrl: đọc sheet → parse câu hỏi theo exerciseType. Sheet rỗng → IMPORT_EMPTY.
  3. 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.
  4. Lưu draft → trả id.

Sửa — PUT / (có id)

  1. Tìm bài theo id, cập nhật nội dung.
  2. importUrl bị bỏ qua (vì đã có id) — sửa bài không tự nạp lại câu hỏi.
  3. Lưu draft/editing.

Gate thật là id == null, không phải HTTP verb: cùng applyImportIfPresent chạy ở cả create lẫn update, và skip khi id != null. Muốn nạp lại câu cho bài đã có → dùng POST /import.

Import cho bài đã có — POST /import

  1. Tìm bài theo exerciseId, đọc sheet, parse. Rỗng → IMPORT_EMPTY.
  2. 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.
  3. 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ệnCâu cũKết quả
POST / + importUrlid == null(bài mới, rỗng)REPLACE bằng sheet
PUT / + importUrlid != nullGiữ nguyênimportUrl bỏ qua
POST /import APPENDbài đã cóGiữ + thêmcũ ∪ mới
POST /import OVERRIDEbài đã cóXóachỉ sheet
POST /import/previewKhông đụngChỉ preview

Import preview (ImportPreviewDTO)

FieldÝ nghĩa
exerciseTypeDạng bài suy ra từ sheet.
statusImportPreviewStatus.
canImportCó import được không (đủ cột bắt buộc).
totalRowsSố dòng trong sheet.
statisticsList<ImportPreviewStatItemDTO> — mỗi field: field, count, missingColumn.
questionsList<BaseAiExerciseQuestionDTO> — câu hỏi parse được (preview).

Lưu ý: content / BaseAiExerciseContentBaseAiExerciseQuestionDTO ở đâ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.