버그 수정부터 TDD, Redis 캐시, 기록 시스템 개선까지
최근 축덕 퀴즈를 다듬으면서 단순히 기능을 추가하기보다 실제 서비스에서 발생하는 문제를 수정하고 구조를 개선하는 작업을 많이 했다.
이번에는 버그 수정, 캐시 최적화, TDD, 프론트·백엔드 연결까지 정리해 봤다.
1. CORS 오류 수정 — origin 문자열 하나의 차이
배포 후 랭킹 조회 요청에서 브라우저가 요청을 차단했다.
원인을 확인해 보니 백엔드 허용 origin에 /가 하나 더 붙어 있었다.
브라우저 Origin
https://football-quiz-web.vercel.app
서버 허용 Origin
https://football-quiz-web.vercel.app/
눈에 잘 안 보이는 차이였지만 CORS는 문자열 기준이라 완전히 다른 origin으로 인식했다.
수정
origin: ['https://football-quiz-web.vercel.app']
배운 점
- CORS는 문자열 비교다
- 배포 환경은 실제 요청 헤더 확인이 가장 빠르다
2. 무한 퀴즈 개선 — 난이도 큐 + 편법 방지
난이도 기반 문제 순서
처음부터 어려운 문제가 나오면 이탈률이 높을 것 같아서 문제 흐름을 조정했다.
1~5 easy
6~8 normal
9~10 hard
11번 이후 random
랜덤만 쓰지 않고 초반 경험을 어느 정도 설계했다.
편법 방지 추가
무한 퀴즈는 랭킹이 있기 때문에 최소한의 방어 장치를 넣었다.
적용한 것:
- 탭 전환 감지 → 게임 종료
- BroadcastChannel 기반 다중 탭 감지
- 붙여넣기 차단
다만 카카오톡·음악 앱 같은 네이티브 앱 이동은 감지 불가능해서 규칙 안내도 같이 추가했다.
배운 점
기술로 완벽하게 막는 것보다 규칙과 UX 설계가 먼저다.
3. Prisma 마이그레이션 + Redis 캐시 개선
QuestionAttempt 테이블 추가
문제별 정답률 추적을 위해 스키마를 추가했다.
npx prisma migrate dev --name add_question_attempt
이후 방향이 바뀌면서 서비스 코드는 제거했지만, 마이그레이션 히스토리는 유지했다.
Redis 캐시 개선
랭킹 캐시를 정리했다.
ranking:top50
↓
ranking:top10
그리고 테스트로 캐시 히트/미스를 먼저 검증했다.
실제 배포 후 측정:
| 첫 호출 | 933ms |
| 재호출 | 430ms |
캐시가 들어간 뒤 체감 차이가 꽤 컸다.
4. 치명적인 버그 두 개 수정
번역 딜레이 → 이전 문제가 보이는 버그
다음 문제로 넘어가도 이전 힌트가 잠깐 보였다.
원인은 비동기 번역 완료 전까지 이전 데이터가 남아 있었기 때문.
해결:
- 번역 시작 전 화면 초기화
- 오래 걸린 이전 요청 결과 무시
useEffect cleanup + cancelled 플래그
이 패턴은 fetch, timer에서도 동일하게 사용할 수 있다.
복구 코드 초기화 버그
내 기록 화면에 들어갈 때마다 복구 코드가 바뀌는 문제가 있었다.
원인은:
sameSite: strict
프론트와 백엔드가 다른 도메인이어서 쿠키가 전송되지 않았다.
수정:
sameSite: none
secure: true
추가로 CSRF 방어를 위해 커스텀 헤더 검증도 넣었다.
5. TDD로 개인 기록 기능 추가
기존에는 10연속 이상만 저장됐다.
조건 변경:
기존
streak ≥ 10
변경
streak ≥ 1
진행 순서:
Red
테스트 먼저 작성
Green
최소 구현으로 통과
Refactor
중복 제거
특히 submit과 record 저장 로직을 하나로 묶었다.
private createRecord()
쓰기 작업에서는 Redis 캐시를 삭제하도록 유지했다.
6. 프론트 연결 + UX 개선
백엔드 API만 있고 프론트 연결이 빠져 있었다.
추가:
POST /ranking/record 연결
그리고 닉네임은 localStorage에 저장하도록 변경.
결과:
- 매번 입력 안 해도 됨
- 개인 기록 저장 흐름 단순화
게임 종료 후:
개인 기록 저장
↓
조건 만족 시 공개 랭킹 등록
7. 문제 난이도 재조정 — 기준 먼저 정하고 일괄 수정
축덕 퀴즈 문제 수가 늘어나면서 기존 난이도 분류가 점점 일관성을 잃기 시작했다.
같은 체감 난이도인데 easy와 hard가 섞이거나, 초반부터 어려운 선수가 등장하는 경우가 있었다.
그래서 선수 데이터를 하나씩 수정하는 대신 난이도 기준을 먼저 정의하고 전체 데이터를 재정리했다.
기준:
easy
- 유명한 현역 축구 선수 / 감독
- 유명한 레전드 선수 / 감독
normal
- EPL
- 라리가
- 분데스리가
- 리그앙
- 세리에 A
- K리그
hard
- 그 외 리그 및 상대적으로 인지도가 낮은 선수
이 기준을 바탕으로 player.json 전체 데이터를 대상으로 난이도를 다시 분류했다.
결과적으로 초반에는 접근하기 쉬운 문제가 나오고, 뒤로 갈수록 점진적으로 난도가 올라가도록 구조를 맞췄다.
예전에는 감으로 난이도를 조절했다면, 이번에는 규칙 → 일괄 적용 → 검수 흐름으로 바꿨다.
느낀 점
문제 수가 많아질수록 개별 수정보다 기준을 먼저 만드는 작업이 더 중요했다.
퀴즈 서비스에서는 문제 개수보다 난이도 곡선과 플레이 경험의 일관성이 더 큰 영향을 준다는 걸 체감했다.
📚 참고한 이전 글
이전 작업부터 이어지는 내용이라 함께 보면 흐름 이해가 쉽습니다.
- [글 제목]
https://ksc-dev.tistory.com/21
LLM을 “정확하고 효율적으로” 사용하는 방법 정리
OpenAI 및 Gemini 기반 LLM 활용 경험을 실제 개발 관점에서 정리한 내용이다.💡 시작하며 (느낀 점)LLM 최적화 가이드를 읽기 전까지는“내가 LLM을 잘못 쓰고 있는 건가?”라는 고민이 있었다.프롬프
ksc-dev.tistory.com
이번 작업에서 배운 것
- React에서 async race condition 방어 패턴
- CORS와 CSRF의 차이
- Redis 캐시 무효화 시점
- TDD의 Red → Green → Refactor 흐름
- DTO와 서비스 책임 분리
- 작은 기능도 실제 서비스 관점으로 설계하기
오늘의 한 줄
기능을 추가하는 것보다 이미 돌아가는 코드를 안전하게 바꾸는 게 더 어렵고 더 많이 배운다.
🔗 직접 플레이해보기
이번 글에서 정리한 내용은 실제 서비스에 반영되어 있습니다.
아래 링크에서 확인할 수 있습니다.
→ https://football-quiz-web.vercel.app/
축덕 퀴즈
football-quiz-web.vercel.app
'프로젝트 > 축덕 퀴즈' 카테고리의 다른 글
| 축덕 퀴즈: 복구코드 추가 구현 + UI 개선 + UX 개선 기록 (0) | 2026.06.16 |
|---|---|
| 축덕 퀴즈 개발 일지 - 20일간의 기능 추가 (0) | 2026.05.12 |
| 축덕 퀴즈 개발기 - V1 확장을 결심한 이유 (0) | 2026.05.11 |
| Football Quiz Web 개발 기록 (0) | 2026.05.05 |