오픈챌린지 개발 명세 (FRD)¶
요지¶
오픈챌린지는 별도 도메인이 아니라 challenge 도메인의 공개(PUBLIC) 경로다. 풀이 상태머신·채점·AI 위임 같은 핵심 백엔드는 챌린지식-풀이와 그대로 공유하고, 여기서는 공개 유입에서만 다른 부분(공개 API 표면, 집계 규칙, visibility)만 따로 정리한다.
상위 PRD¶
기획(5화면, 비로그인 전환, 집계·랭킹 정책)은 prd v3이며, 바뀌면 이 문서도 갱신한다.
기술 접근 · 아키텍처¶
visibility¶
Challenge.visibility = PUBLIC (오픈챌린지) vs STUDYROOM(스터디룸 한정). 오픈은 studyRoomId = null, 운영자 시드. 초기 MVP는 모든 문제 AI 지원(isAiSupported=true).
집계 규칙¶
엔티티 필드 자체는 challenge가 기준이고, 여기서는 공개 채널에서 숫자를 어떻게 세는지를 정한다. 핵심은 "끝까지 푼 것만 센다"이다 — 들어와서 도중에 나간 건 통계에 넣지 않는다.
- participantCount = COMPLETED 기준(실제 완료만 카운트). passRate = COMPLETED 중 정답 비율.
- ANSWER_SELECTED는 DB 저장 X, UI 상태로만 관리 → 제출(answer PATCH) 시 확정.
- 다시 풀기: 새 attempt 생성. ChallengeReview: COMPLETED만 작성, 추천순 정렬, 추천 중복 방지. 타 사용자는 최신 COMPLETED 풀이만 노출(피드 품질), 본인은 전체 이력.
- UserRanking(배치 집계): 1순위 연속 참여일수 → 2순위 참여 횟수 → 3순위 정답률(COMPLETED only). KST 기준, 하루 미참여 시 streak reset, Grace Day 없음.
예외·검증¶
답을 고르지 않으면 제출할 수 없고, 로그인이 만료되면 재로그인 후 풀던 attempt를 복구한다. 도중에 나가면 UNRESOLVED로, 문제가 없으면 빈 화면으로, 정답률 표본이 부족하면 "집계 중"으로 처리한다. 한 명이라도 푼 문제는 수정·삭제 없이 비노출만 한다.
API · 데이터 모델¶
엔티티는 challenge가 기준이고, 여기서는 공개 유입에 필요한 API 표면(리스트·상세·결과·랭킹·어드민)만 정리한다.
| 동작 | 메서드·경로 | 요청/쿼리 | 응답 핵심 |
|---|---|---|---|
| 문제 리스트 | GET /challenges |
subject, difficulty, sort(최신/인기/정답률) | 카드 목록 + participantCount·passRate |
| 문제 상세 | GET /challenges/:id |
— | 문제 이미지·choices·메타·isAiSupported |
| attempt 생성 | POST /challenge-attempt |
challengeId | {attemptId, status} |
| 답 제출 | PATCH /challenge-attempt/:id/answer |
selectedAnswer | {isCorrect, correctAnswer, participantCount, passRate} |
| 다른 사람 풀이 | GET /challenge-reviews/:challengeId |
sort=recommend | 풀이 목록(베스트 고정) |
| 풀이 작성 | POST /challenge-review |
content (COMPLETED only) | review |
| AI 만족도 | POST /challenge-feedback |
rating·comment(opt) | 저장 |
| 사용자 랭킹 | GET /challenge-ranking |
— | streakDays·challengeCount·correctRate |
| 어드민 | POST /admin/challenge, PATCH /admin/challenge/:id/hide, DELETE /admin/challenge/:id |
— | (참여자 발생 시 삭제 불가) |
- 공개 리스트/상세는
/api/public/**permitAll — 비로그인 접근. attempt·제출·풀이 작성·만족도는 인증 필요(비로그인 시작 시 로그인 유도 = 전환 지점). - 응답 목표: 리스트 < 200ms, 상세 < 300ms (Redis 캐시 후보).
의존성 · 영향 범위¶
챌린지 도메인(challenge)을 기반으로 하고, 풀이 단계(상태머신·채점·AI 위임)는 챌린지식-풀이와, 막혔을 때의 AI 코칭은 사고력-답변구조와 흐름을 공유한다.
트래픽이 변수다. 6월 모의고사 시즌에 한꺼번에 몰릴 수 있는데, 1차 MVP는 단일 인스턴스를 가정하되 모니터링 알림 임계를 미리 걸어 둔다. 2026-05-26 기준 백엔드·프런트 MVP는 완성됐고, 드로잉·성능(Lighthouse)·모바일 최적화가 후속 과제로 남아 있다.
테스트 계획¶
공통 전략은 qa-playbook을 따른다. 이 기능의 핵심은 로그인 경계와 집계 정확성이다 — 비로그인은 리스트·상세까지만 보이고 attempt·제출·만족도는 401로 막혀 로그인으로 유도되어야 하며, participantCount·passRate가 COMPLETED 기준으로만 늘어야 한다. 한 명이라도 푼 문제의 수정·삭제 차단(비노출만), 답 미선택 제출 차단도 확인한다.
작업 분해¶
완료 추적은 GitHub 이슈에서 한다. 방향 전환의 근거는 ADR-0009에 있고, 비로그인 공개 엔드포인트의 Security 정책은 별도 ADR로 정할 예정이다.