Skip to content

[DP-411] 퀴즈 이력 목록/상세 API + 제출 시 답안 저장#135

Merged
github-actions[bot] merged 1 commit intodevelopV2from
auto/feature/DP-411-quiz-history
Apr 24, 2026
Merged

[DP-411] 퀴즈 이력 목록/상세 API + 제출 시 답안 저장#135
github-actions[bot] merged 1 commit intodevelopV2from
auto/feature/DP-411-quiz-history

Conversation

@nYeonG4001
Copy link
Copy Markdown
Collaborator

작업 내용

퀴즈 이력 조회 및 결과 상세 API를 구현하고, 제출 시 문제별 선택 답안을 저장하는 기능을 추가합니다.


DB 스키마 변경

신규 테이블 quiz_attempt_answers:

CREATE TABLE quiz_attempt_answers (
    id                 UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    attempt_id         UUID NOT NULL REFERENCES quiz_attempts(id) ON DELETE CASCADE,
    question_id        VARCHAR(100) NOT NULL,
    selected_option_id VARCHAR(100),
    answer_text        TEXT,
    is_correct         BOOLEAN NOT NULL,
    created_at         TIMESTAMP NOT NULL DEFAULT now()
);
CREATE INDEX idx_quiz_attempt_answers_attempt_id ON quiz_attempt_answers(attempt_id);

제출 API 확장

POST /contents/{contentId}/quiz/submitQuizSubmitRequestanswers 배열 추가 (하위 호환: nullable)

{
  "level": "JUNIOR",
  "score": 2,
  "totalQuestions": 3,
  "passed": false,
  "answers": [
    { "questionId": "q-1", "selectedOptionId": "opt-2", "answerText": null, "isCorrect": false },
    { "questionId": "q-2", "selectedOptionId": "opt-1", "answerText": null, "isCorrect": true }
  ]
}

퀴즈 이력 목록 API (신규)

GET /users/me/quiz-history?sort=newest&page=0&size=10

  • contentId + level 기준 최신 attempt만 반환
  • 전부 맞힌 경우(score == totalQuestions)는 자동 제외
  • sort=newest(기본) / sort=oldest 서버사이드 정렬
  • preview: DynamoDB ai_quizzes에서 첫 번째 문제 텍스트 배치 조회 (없으면 null)
{
  "success": true,
  "data": {
    "content": [
      {
        "attemptId": "uuid",
        "contentId": "uuid",
        "contentTitle": "React hooks 완전 정복",
        "thumbnail": "https://...",
        "preview": "useActionState 훅의 주요 역할은 무엇인가요?",
        "level": "JUNIOR",
        "score": 2,
        "totalQuestions": 3,
        "passed": false,
        "attemptedAt": "2026-04-20T10:00:00Z"
      }
    ],
    "page": 0,
    "size": 10,
    "totalElements": 5,
    "totalPages": 1
  }
}

thumbnail, preview는 없으면 필드 자체 제외 (@JsonInclude(NON_NULL) 전역 설정)


퀴즈 결과 상세 API (신규)

GET /quiz-history/{attemptId}

  • 타인의 attempt 조회 → 403
  • 존재하지 않는 attemptId → 404
  • quiz.questions: DynamoDB에서 contentId+level로 조회
  • myAnswers: PostgreSQL quiz_attempt_answers에서 조회
  • pointsEarned: point_logs에서 해당 콘텐츠의 AI_QUIZ_PASS 적립 합계
{
  "success": true,
  "data": {
    "attemptId": "uuid",
    "contentId": "uuid",
    "score": 2,
    "totalQuestions": 3,
    "passed": false,
    "pointsEarned": 0,
    "quiz": {
      "questions": [
        {
          "id": "q-1",
          "type": "multiple_choice",
          "question": "Spring DI란 무엇인가요?",
          "options": [{ "id": "opt-1", "text": "의존성 주입" }, { "id": "opt-2", "text": "데이터 조회" }],
          "correctOptionId": "opt-1",
          "explanation": "DI는 Dependency Injection의 약자입니다.",
          "correctAnswer": ""
        }
      ],
      "passingCount": 2
    },
    "myAnswers": [
      { "questionId": "q-1", "selectedOptionId": "opt-2", "answerText": null, "isCorrect": false }
    ]
  }
}

신규 파일

파일 역할
QuizAttemptAnswer.java quiz_attempt_answers 엔티티
QuizAttemptAnswerRepository.java 답안 레포지토리
QuizHistoryController.java 이력 목록/상세 엔드포인트
QuizHistoryItemResponse.java 이력 목록 아이템 DTO
QuizHistoryListResponse.java 이력 목록 페이지 DTO
QuizResultResponse.java 결과 상세 DTO

수정 파일

파일 변경 내용
QuizSubmitRequest.java answers 필드 추가 (nullable, 하위 호환)
QuizAttemptRepository.java 이력 목록 쿼리 추가 (contentId+level 최신 + 미완료 필터)
AiQuizRepository.java batchFindFirstQuestions 배치 조회 메서드 추가
AiQuizService.java answers 저장 + getQuizHistory + getQuizResult 추가
AiSummaryService.java fromAiServerLevel 역변환 메서드 추가
ErrorCode.java QUIZ_ATTEMPT_NOT_FOUND, QUIZ_ATTEMPT_FORBIDDEN 추가

테스트 커버리지

클래스 LINE BRANCH
AiQuizService 96% 87%
QuizHistoryItemResponse 100% 100%
QuizHistoryController 100% -

AiQuizServiceTest 신규 케이스 (7개)

  • 답안 포함 제출 시 quiz_attempt_answers 저장 확인
  • 이력 없는 유저 → 빈 리스트 반환
  • 이력 있는 유저 → 항목 반환 (level MIDDLE 변환 확인)
  • sort=oldest → createdAt ASC 정렬 적용
  • DynamoDB preview 정상 조회 → preview 반영
  • DynamoDB preview blank → null 반환
  • DynamoDB 예외 시 preview null fallback
  • 타인 attempt 조회 → QUIZ_ATTEMPT_FORBIDDEN
  • 존재하지 않는 attempt → QUIZ_ATTEMPT_NOT_FOUND
  • 정상 결과 상세 → quiz + myAnswers 포함

QuizHistoryControllerTest (4개)

  • 이력 목록 정상 200
  • 빈 결과 200
  • 결과 상세 정상 200
  • 타인 attempt → 403
  • 없는 attempt → 404

@github-actions github-actions Bot merged commit 194bda8 into developV2 Apr 24, 2026
2 checks passed
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
74.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant