Skip to content

fix: 배지 조회 응답 상태코드 정정 — 미가입 404 통일 및 라우팅 미스 4xx - #21

Merged
kobenlys merged 3 commits into
developfrom
feature/badge-unregistered-404
Sep 15, 2026
Merged

kobenlys merged 3 commits into
developfrom
feature/badge-unregistered-404

Conversation

@kobenlys

Copy link
Copy Markdown
Contributor

🏷️ 작업 유형

  • 🐛 버그 픽스
  • ✨ 개발
  • 📝 문서 추가 및 수정
  • ♻️ 리팩터링
  • 🔧 ETC

📋 변경 사항

배지 조회가 잘못된 상태코드를 주던 문제 두 건을 고쳤습니다.

1. 미가입 사용자 응답을 404로 통일 (cc71356)

미가입 username은 이제 모든 테마에서 404 BADGE_001을 받습니다. 가입했지만 자격이 없는 경우는 기존대로 200 잠금 SVG입니다.

요청 이전 이후
미가입 + ?theme=gpu 404 BADGE_001 404 BADGE_001
미가입 + ?theme=beta-tester 200 잠금 SVG 404 BADGE_001
가입 + 미자격 + ?theme=beta-tester 200 잠금 SVG 200 잠금 SVG

자격 게이트가 사용자 조회보다 먼저 걸려 오타 username이 "전용 배지" 안내로 지나갔습니다. findGrant 네이티브 쿼리에 userExists 컬럼을 더해 DB 왕복을 늘리지 않고 판별하고, BadgeRenderService가 자격 분기보다 앞에서 BADGE_001을 던집니다.

2. 라우팅 미스가 500 대신 올바른 4xx 반환 (193b976)

develop에도 있던 기존 결함으로, 1번 검증 중에 발견했습니다.

요청 이전 이후
GET /badge/, /badge, /badge/{u}/ 500 SERVER_ERROR 404 NOT_FOUND
POST /badge/{u} 500 SERVER_ERROR 405 METHOD_NOT_ALLOWED

GlobalExceptionHandler의 @ExceptionHandler(Exception.class) catch-all이 Spring MVC 표준 예외까지 삼켰습니다. /badge/**가 permitAll이라 미인증 요청만으로 ERROR 스택트레이스를 쌓을 수 있었습니다. ErrorResponse를 구현하는 예외 5종을 전용 핸들러로 잡고, 응답 코드와 메시지를 예외가 지정한 상태에서 파생해 매핑 표 없이 처리합니다.

3. .omc/를 gitignore에 추가 (33acaf9)

에이전트 하네스가 생성하는 로컬 디렉터리입니다.

리뷰 시 알아둘 점

  • 배포하면 BADGES.md:209의 locked 배지 예시 이미지가 깨집니다. octocat이 미가입이라 200 잠금 SVG를 받고 있었는데, 1번 변경으로 404가 됩니다. 문서를 그대로 두고 배포하기로 결정된 사항입니다.
  • HttpMediaTypeNotAcceptableException 등 3종은 현재 라우트에서 도달 불가라 테스트가 없습니다. 같은 ServletException implements ErrorResponse 계열이라 핸들러 목록에만 넣어둔 방어 코드입니다.

✅ 테스트

TDD로 진행했고 사이클마다 RED를 확인했습니다.

사이클 RED 실패 메시지
쿼리 계약 Null return value from advice ... getUserExists()
판정 로직 Expecting value to be false but was true
미가입 404 Expecting code to raise a throwable.
라우팅 미스 Status expected:<404> but was:<500>
./mvnw test     # 504건 통과 (기존 490 + 신규 14)
./mvnw verify   # 통합 39건 통과 (Testcontainers Postgres)

신규 테스트가 실제로 태우는 계약입니다.

  • UserBadgeGrantRepositoryIntegrationTest — 실 Postgres로 userExists alias ↔ getter 매핑 검증
  • GlobalExceptionHandlerWebMvcTest — @WebMvcTest로 실제 디스패치를 태워 핸들러 도달 경로 검증
  • BadgeRenderServiceTest — 미가입 시 잠금 렌더·캐시·집계 조회 미호출 검증

미가입 username은 이제 모든 테마에서 404 BADGE_001을 받는다.
가입했지만 자격이 없는 경우는 기존대로 200 잠금 SVG다.

기존에는 자격이 필요한 테마(beta-tester)만 200 잠금 SVG를 반환했다.
자격 게이트가 사용자 조회보다 먼저 걸려 오타 username이 걸러지지 않았다.

findGrant 쿼리에 userExists 컬럼을 더해 DB 왕복을 늘리지 않고 판별하며,
BadgeRenderService가 자격 분기보다 앞에서 BADGE_001을 던진다.
/badge/ 같은 라우팅 미스는 404 NOT_FOUND를, POST /badge/{username} 은
405 METHOD_NOT_ALLOWED를 반환한다. ERROR 스택트레이스도 남지 않는다.

기존에는 GlobalExceptionHandler의 catch-all이 Spring MVC 표준 예외까지
삼켜 전부 500 SERVER_ERROR로 나갔다. /badge/** 가 permitAll이라
미인증 요청만으로 ERROR 로그를 쌓을 수 있었다.

ErrorResponse를 구현하는 예외 5종을 전용 핸들러로 잡고, 응답 코드와
메시지를 예외가 지정한 상태에서 파생해 매핑 표 없이 처리한다.
@kobenlys kobenlys self-assigned this Sep 15, 2026
@kobenlys
kobenlys merged commit c583e55 into develop Sep 15, 2026
2 checks passed
@kobenlys
kobenlys deleted the feature/badge-unregistered-404 branch September 15, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant