Daeseon Yoo
Back to project
·Update·2 min

U1 mastery 데이터 레이어와 스파링 리포트 클라이언트

8개 정적 SRS 팩의 mastery를 한 selector로 집계하고 F1 스파링 리포트 API를 shared core에 연결했다. 오늘 reps를 주간 합계로 오인하지 않도록 표시 계약도 분리했다.

문제

SRS 상태는 카드별로 있었지만 전체와 팩별로 mastered, learning, total을 계산하는 공용 데이터 레이어가 없었다. 전체 Vitest도 cardIndex()가 4,233개를 반환하는 현재 코드와 달리 pattern·collocation 두 팩의 448개만 기대해 실패했다.

또한 PracticeProgress.reps는 코드와 백엔드 DTO에서 모두 오늘 횟수다. 7일 history가 없는 상태에서 이 값을 weeklyReps로 바꾸면 화면에는 근거 없는 주간 숫자가 표시된다.

구현

packages/core/src/practice-mastery.ts가 정적 콘텐츠 8개 팩의 크기를 원본 배열에서 계산한다. selectMastery()cardIndex()에 존재하는 SRS 키만 받아 다음 규칙으로 집계한다.

같은 계약을 React/React Native가 함께 import할 수 있도록 useMastery()는 React를 새 dependency로 넣지 않는 얇은 wrapper다. 리듬 selector는 오늘 횟수를 repsToday로 명시하고 streak, longestStreak, totalReps를 그대로 보존한다.

practiceApi.sparringReport(userTurns, targets)도 shared core에 추가했다. 입력 target에는 F1 백엔드 요청 DTO와 같은 cardKey, label, 선택적 ko가 있고, 응답은 usedTargets, missedTargets, corrections, recurringMistakes를 타입으로 고정한다.

검증 범위

최종 frontend Vitest 출력은 다음과 같았다.

Test Files  8 passed (8)
Tests  40 passed (40)

box 3/4 경계, 팩별 집계, 빈 상태, 상태 없는 카드, 중복·알 수 없는 키, 리듬 요약, F1 POST body를 테스트했다. npx tsc --noEmit --pretty false --incremental false는 stdout 없이 exit 0이었다. 이는 함수/타입 수준 검증이다. 모바일 화면 통합, 실제 인증된 F1 호출, 사용자 workflow 개선은 [unverified]다.

구현 커밋: f2055fa8b28270fb74f41b22936cc43638b16fac.