챌린지 도메인 (Challenge)¶
1. 한 줄 정의¶
학생이 객관식 문항을 풀고, 막히면 AI 코칭으로 사고를 유도받는 챌린지 도메인. 1차 MVP 핵심 채널 (오픈챌린지 v2/v3). 비로그인 학생은 공개 챌린지(status=PUBLIC)로 유입되고, 막힘 시 AI 코칭 세션(ai_coaching_*)이 붙는다. 코드상 챌린지는 패키지 open_challenge에 단일 도메인으로 존재하며, "스터디룸 전용 챌린지(visibility=STUDYROOM)"는 코드에 없다(노출 제어는 ChallengeStatus PUBLIC/HIDDEN). 기능 명세는 챌린지식 풀이 · 오픈챌린지 참조.
2. 핵심 개념 (실제 코드 — 패키지 open_challenge)¶
코드의 챌린지는 "여러 문제 묶음"이 아니라 단일 객관식 문항 모델이다. 한
Challenge가 하나의 문제(지문+보기+정답)이고, 시도는 답 1개를 고른다. 아래 wiki 옛 서술의ChallengeProblem·ChallengeRubric·ChallengeProblemAttempt·ChallengeScore·qnaContextId·visibility(PUBLIC/STUDYROOM)는 코드에 없다.
- Challenge (
challenge) — 단일 객관식 문항.subject(ChallengeSubject=MATH),difficulty(ChallengeDifficulty=TOP/HIGH/MID/LOW),wrongAnswerRate,title,sourceText,questionText,questionImageUrl/questionMediaId,choices(JSON 리스트),correctAnswer,type,isAiSupported,status(ChallengeStatus=PUBLIC/HIDDEN),participantCount/correctCount. soft delete는deleted_at컬럼만(엔티티에@SQLDelete미선언 —from()에서 수동 set) - ChallengeAttempt (
challenge_attempt) — 사용자 1회 시도.challengeId,userId,status(ChallengeAttemptStatus=IN_PROGRESS/AI_COACHING/UNRESOLVED/COMPLETED),selectedAnswer,isCorrect,usedAi,maxUsedHintStep,startedAt/completedAt - AiCoachingSession / AiCoachingMessage / AiCoachingPreference (
ai_coaching_*) — AI 코칭 서브시스템. 세션 status(AiCoachingSessionStatus=READY/COACHING/WAITING_ANSWER/GUIDE_TO_PROBLEM/FINISHED/ABANDONED), 메시지 role(AiCoachingMessageRole), 학습 선호(LearningGoal·LearningStage·DifficultArea·AiProvider) - ChallengeFeedback — 챌린지 피드백, ChallengeReview/ChallengeReviewRecommend — 풀이 후기·추천, UserRanking — 랭킹 집계
3. 관련 코드¶
구현 명세는 챌린지식 풀이 (스터디룸 챌린지) + 오픈챌린지 (비로그인 공개)에서 관리. 패키지 배치:
mvp-back/src/main/java/com/example/demo/
├─ domain/open_challenge/{challenge,challengeattempt,aicoaching,challengefeedback,challengereview,userranking}/
├─ application/service/open_challenge/...
├─ presentation/{controller,dto}/open_challenge/...
└─ infrastructure/persistence/{entity,repository}/open_challenge/...
mvp-front route group:
- (public)/challenge — 비로그인 공개 리스트
- (private)/challenge — 스터디룸 챌린지 + 진행
주요 API (실제 구현 — open_challenge 컨트롤러들)¶
| Method | Path | 설명 |
|---|---|---|
| GET | /api/public/challenges[/{challengeId}] |
비로그인 리스트·상세 |
| GET | /api/public/challenge-rankings |
공개 랭킹 |
| POST | /api/common/challenge-attempts |
시도 시작 |
| PATCH | /api/common/challenge-attempts/{attemptId}/{answer,abandon} |
답 제출·포기 |
| GET | /api/common/challenges/{challengeId}/my-active-attempt |
진행 중 시도 |
| POST/GET/PATCH | /api/common/ai-coaching-sessions[/{sessionId}/{messages,finish,abandon}] |
AI 코칭 세션·메시지 |
| GET/PUT | /api/common/ai-coaching-preferences/{enums,me} |
코칭 선호 |
| GET | /api/common/me/challenges[/{challengeId}] |
내 챌린지 기록 |
| POST | /api/common/challenge-feedbacks |
피드백 |
| POST/DELETE/GET | /api/common/challenge-reviews[/{reviewId}/recommends], /api/common/challenges/{id}/reviews |
후기·추천 |
| GET | /api/teacher/students/{studentId}/challenges/{challengeId}/ai-log |
선생 AI 로그 |
| PUT/PATCH/DELETE | /api/admin/challenges/{challengeId}[/{hide,show}] |
운영자 챌린지 관리(출제·숨김) |
로그인 사용자 진입은 대부분
/api/common/**(TEACHER·STUDENT·PARENT) prefix이고,/api/student/...attempts/.../problems/...같은 multi-problem 경로는 존재하지 않는다. 챌린지 출제·노출 제어는/api/admin/challenges/**.
4. 상태/생명주기¶
ChallengeAttempt.status (ChallengeAttemptStatus):
IN_PROGRESS → COMPLETED (답 제출, isCorrect 판정)
→ AI_COACHING (막힘 시 AI 코칭 진입)
→ UNRESOLVED (미해결 종료)
AiCoachingSession.status:
READY → COACHING → WAITING_ANSWER → GUIDE_TO_PROBLEM → FINISHED
→ ABANDONED
채점은 항상 서버 단일 진실원천. correctAnswer는 챌린지 엔티티에만 두고, 시도(selectedAnswer) 정오는 서버가 isCorrect로 판정한다.
5. 외부 의존¶
- LLM provider — AI 코칭 세션. 공통
external/ai(AiCoachingClient+ Anthropic/OpenAI/Stub)를 통해 호출. (객관식 채점은correctAnswer직접 비교라 LLM 불필요. 옛 서술의ChallengeRubricScoringService·rubric 채점은 코드에 없음) - S3 / MediaAsset — 문제 이미지(
questionMediaId/questionImageUrl) - Spring Security —
/api/public/challenges/**·/api/public/challenge-rankingspermitAll → member §7 비회원 정합
6. UI 노출¶
/challenge공개 리스트 (비로그인)/challenge/[id]챌린지 상세 안내/challenge/[id]/attempts/[attemptId]풀이 진행 (단계 인디케이터 + 사이드 패널)- 결과 화면 — 사용한 힌트 단계까지 노출해 사고력 가시화
- AI 코치 화면 흐름은 단계 인디케이터·사이드 패널 기반 진행 UI를 따른다
7. 권한 / 정책 요약¶
| 역할 | 권한 |
|---|---|
| 비회원 | status=PUBLIC 챌린지 리스트·상세·랭킹 (/api/public/challenges/**·challenge-rankings permitAll) |
| 로그인 사용자(공통) | 시도 시작·답 제출(answer)·포기(abandon)·AI 코칭·후기 — /api/common/**(TEACHER·STUDENT·PARENT) |
| 선생님 | 소속 학생 AI 로그 모니터링 (/api/teacher/students/{id}/challenges/{id}/ai-log) |
| 운영자(ADMIN) | 챌린지 출제·수정·숨김/노출·삭제 (/api/admin/challenges/**) |
- 채점·정답은 서버 단일 진실원천 (§5),
correctAnswer는 클라이언트에 미노출 - 챌린지 노출 제어는
ChallengeStatus(PUBLIC/HIDDEN)이며, 별도visibility(PUBLIC/STUDYROOM)컬럼은 코드에 없음 - 역할별 접근 권한 SSOT는 member §7
8. 결정 이력 / TODO¶
- 챌린지식 풀이 채택 (2026-05-20) → 챌린지식 풀이
- 오픈챌린지 백/프론트 MVP 완성 (2026-05-26) → 오픈챌린지
- (예정) ADR-0006 — 챌린지 vs homework 경계 (출제 주체·범위 다름으로 별개 유지)
- (예정) ADR-0007 — 비로그인 공개 엔드포인트 Spring Security 정책
- 챌린지가 studyroom 안인지 글로벌인지 → 코드는 글로벌 단일 도메인(
ChallengeStatus로 노출만 제어). 스터디룸 귀속은 미구현 - qna와의 관계 → 막힘 코칭은 QnA가 아니라 챌린지 자체의
ai_coaching_*서브시스템으로 구현됨(qnaContextIdFK는 코드에 없음) - 챌린지 출제 — 현재
/api/admin/challenges/**(운영자)로 출제·노출 제어. 선생님 직접 출제는 미구현 - 6모 시즌 트래픽 spike — 1차 MVP는 모니터링 알림만, 캐시·스케일은 2차