SRDsExercise AIDomain Model & State
DraftDT-4662Exercise AISRDDomainModelMongoDBStateMachine

Exercise AI — Domain Model & State

Mô tả entity, DTO đa hình, và state machine của runtime do-test. Nguồn: study-hub features/exercise_ai/dotest.

Progress (aggregate root)

AiUserExerciseProgress extends BaseDocument (id, audit fields, version optimistic lock). Một document = một phiên làm bài.

FieldKiểuÝ nghĩa
userResourceIdStringKhóa tài nguyên bài trong khóa học (LMS).
exerciseIdStringId bài Exercise AI.
versionKeyDocumentVersionKeyBản published của bài tại thời điểm bắt đầu.
exerciseTypeAiExerciseTypeDạng bài — discriminator cho content / questions.
teacherLanguageTypeTeacherLanguageTypeVIETNAMESE / ENGLISH.
startModeUserExerciseStartModeREAL_TEST (mặc định) / demo.
statusUserExerciseStatusIN_PROGRESSCOMPLETED.
currentIndexintCon trỏ câu hiện tại.
totalQuestionintTổng số câu.
completedAtZonedDateTimeSet một lần khi nộp bài (COMPLETED); null khi đang làm.
contentBaseAiExerciseProgressContentPayload đa hình theo exerciseType.

getQuestions() là accessor @Transient tiện ích trên progress, ủy quyền về content.getQuestions().

Content (đa hình theo dạng bài)

BaseAiExerciseProgressContent (abstract) → getQuestions(): List<? extends BaseAIExerciseQuestionProgress>.

SubtypeDạng bàiField riêng
LinearProgressContentLINEAR_TOOLquestions, tổng kết submit: totalAnswered, totalSkipped, totalNotAnswer, averageCorrectPercentage.
TurnBasedProgressContentSPEAK_A_SENTENCE, IMPROVE_A_SENTENCEquestions.
GuidedProgressContentGUIDED_PRACTICEquestions (TBD).

Các field tổng kết của LinearProgressContent được tính lúc submit qua content mapper factory (computeSubmitSummary) — xem Linear Tool.

Question (đa hình)

BaseAIExerciseQuestionProgress (abstract): questionId, order, state (QuestionState).

Subtype@TypeAliasField riêng
LinearQuestionProgresslinearQuestionProgresssnapshots (List<LinearCanvasSnapshot>), currentSnapshotId. Scoring nằm trong từng snapshot (không còn trên question).
TurnBasedQuestionProgressturnBasedQuestionProgressattemptsLeft, turns (List<AnswerTurn>).
GuidedQuestionProgressguidedQuestionProgress— (TBD).

Snapshot model (LINEAR_TOOL)

LinearQuestionProgress giữ nhiều version canvas qua snapshots + con trỏ currentSnapshotId (đã bỏ mô hình canvas/LinearCanvas đơn). Mỗi LinearCanvasSnapshot: id, ideaCards (List<LinearCard> — đổi tên từ cards), rootCardId, aggregates (total*, fullText), conceptualizedCards (List<LinearCard>), fullConceptualizedText, context, scoring per-snapshot (correctPercentage, speechCorrections, verdict), status (DocumentStatus: EDITINGPUBLISHED), originalSnapshotId, linearMode (LinearMode: IDEA_IMPLEMENTATION mặc định / SPEAKING_PRACTICE — working mode của canvas), createdAt/lastModifiedAt. LinearCard có thêm conceptualizedTextenhance (CardEnhance, @Transient — verdict coaching LIVE, không persist). Bảng field đầy đủ + luật DAG: xem Linear Tool.

DTO response đa hình (song ánh với entity)

BaseQuestionProgressDTO (abstract, chỉ questionId / order / state) → LinearQuestionProgressDTO / TurnBasedQuestionProgressDTO / GuidedQuestionProgressDTO. Mỗi question mapper trả về đúng subtype DTO của nó; factory dispatch theo entity. Type của câu không lặp lại trên question DTO — đã biết từ exerciseType ở mức content (discriminator một tầng phía trên). Đây là response-only nên không cần @JsonTypeInfo.

LinearQuestionProgressDTO thêm 2 field @Transient read-only: totalDoCoachingMenu, totalDoCoachingLive — số lần coaching (đọc từ base_tracking_seq qua CoachingCountReader, không lưu trên progress).

AnswerTurn (turn-based): turnId, clientTurnId (idempotency), answerText, status (TurnStatus), verdict, feedback, matchedStructure, transitionLine, markedBy, sendCount, sentMarking, createdAt, markedAt.

Enums & State machine

UserExerciseStatus

IN_PROGRESS ──submit──▶ COMPLETED   (terminal, immutable)

Mọi mutation bị từ chối khi đã COMPLETED (ensureProgressEditablePROGRESS_ALREADY_COMPLETED).

QuestionState

NOT_ANSWER ──▶ ANSWERING ──▶ ANSWERED
           └──────────────▶ SKIPPED
  • LINEAR_TOOL: nói cả câu (/speech-correction không kèm cardId) → ANSWERED.
  • SKIPPED: bỏ qua câu.

SpeechVerdict

correctPercentage >= 70GOOD, ngược lại NEED_IMPROVE. (Không còn ACCEPTABLE.)

TurnStatus

PROCESSING (vừa gửi chấm) → DONE (callback đã cập nhật kết quả); FAILED (chấm lỗi không phục hồi). MarkedBy (provenance chấm): DETERMINISTIC / AI / FALLBACK. SpeakAnswerVerdict: CORRECT, NOT_FOLLOW_STRUCTURE, WRONG_FILL, OFF_TOPIC, WRONG_LANGUAGE, TOO_SHORT. TurnAction (điều hướng FE): RETRY / NEXT / DONE.

LinearCardType / LinearCardState

  • Type: QUESTION, ANSWER, DESCRIPTION, CAUSE, EFFECT.
  • State: EMPTY, FILLED, ERROR.

Coaching (LINEAR_TOOL)

  • CoachingMode: MENU (gợi ý card mới) / LIVE (chấm lại toàn card + triển khai bài nói).
  • CoachBandVariant: BAND6 (target band, hardcode).
  • CoachingSituationType: KEEP, DIGRESS, TOO_SHORT, VAGUE, SHOULD_BE_CAUSE, SHOULD_BE_DESCRIPTION, EFFECT_NO_RESULT.
  • CoachingVariant (verdict tổng của LIVE, backend suy từ per-card): GOOD (mọi card KEEP → persist + PUBLISHED) / NEED_IMPROVE (không persist). Khác SpeechVerdict.
  • DocumentStatus (snapshot): EDITINGPUBLISHED.
  • Chi tiết flow coaching: xem Do-Test API — Linear Tool.

AiExerciseDoTestErrorCode

PROGRESS_NOT_FOUND (EAID001), QUESTION_NOT_FOUND (002), QUESTION_NOT_ANSWERABLE (003), NO_ATTEMPTS_LEFT (004), TURN_NOT_FOUND (005), MAX_TEST_ATTEMPTS_REACHED (006), CARD_NOT_FOUND (007), PROGRESS_ALREADY_COMPLETED (008), SELECTED_CARD_REQUIRED (009), COACHING_FAILED (010), SNAPSHOT_NOT_FOUND (011), SNAPSHOT_DELETE_NOT_ALLOWED (012), COACHING_GOOD_LIMIT_REACHED (013).