Skip to content

feat(ads): 보상형 광고 크리스탈 충전 기능 추가 - #242

Merged
coldsunn merged 5 commits into
developfrom
feat/ad-reward
Sep 20, 2026
Merged

coldsunn merged 5 commits into
developfrom
feat/ad-reward

Conversation

@coldsunn

Copy link
Copy Markdown
Collaborator

📝 요약(Summary)

크리스탈(인앱 재화)이 부족해 PDF 내보내기·물어보기를 이용할 수 없을 때, 보상형 광고(AdMob Rewarded)를 시청하면 AdMob의 서버 사이드 검증(SSV) 콜백을 받아 부족한 만큼 크리스탈을 지급하는 기능입니다. domain/ads 도메인을 신설했습니다.

동작 방식

  • 광고 검증/지급 서버는 크리스탈 지급만 담당하고, 실제 차감·기능 실행은 기존 기능 API가 그대로 처리합니다(광고 로직과 기능 로직 분리).
  • 지급량은 필요 비용 − 보유 크리스탈이며, 세션 생성 시 서버가 계산해 저장합니다. SSV 콜백에 담긴 reward_amount 값은 신뢰하지 않습니다.

요청 흐름

  1. GET /ad-rewards/quote — 필요 비용·보유·부족량 조회 (읽기 전용)
  2. POST /ad-rewards/sessions — 광고 시청 직전 세션 생성, sessionKey 반환 (사용자당 대기 세션 1개만 유지)
  3. 클라이언트가 sessionKey를 AdMob custom_data에 담아 광고 노출
  4. GET /ad-rewards/ssv — AdMob → 서버 SSV 콜백 (비인증, 서명으로 보호). 검증·중복 확인 후 지급
  5. GET /ad-rewards/sessions/{sessionKey} — 클라이언트가 지급 완료 여부 폴링

검증 · 중복 지급 방지

  • 서명 검증: Tink RewardedAdsVerifier로 AdMob 서명 확인(공개키는 gstatic에서 자동 조회). 요청 원본 쿼리스트링을 가공 없이 그대로 검증합니다.
  • 같은 광고 시청에 콜백이 여러 번 와도(구글 재시도·중복 전송) 한 번만 지급: 세션 행 비관적 락 + transaction_id UNIQUE + 세션 상태(REWARDED) 확인.
  • 확정된 결과(서명 무효·세션 만료·중복·지급 완료)는 HTTP 200으로 응답하고, 일시적 오류(공개키 조회 실패·DB 오류)만 5xx로 응답해 구글 재시도를 유도합니다.

데이터 · 개인정보

  • 세션 식별자로 내부 사용자 ID 대신 서버가 발급한 임의 토큰(128비트, URL-safe)을 사용해, 콜백 URL에 내부 식별자가 노출되지 않게 했습니다.
  • 처리 이력은 ad_reward_logs에 이벤트 단위로 기록하고, 크리스탈 변동은 CrystalLog에도 남깁니다. 사용자 하드 삭제 시 세션·로그는 FK ON DELETE CASCADE로 함께 삭제됩니다.

테스트: 지급 / 중복 / 만료 / 서명 무효 / 세션 생성·조회 / 콜백 분기 / 전체 흐름에 대한 통합·단위 테스트를 추가했습니다.

🔗 Related Issue

  • Closes:

💬 공유사항

  • 배포 후 AdMob 콘솔에 SSV 콜백 URL 등록(dev/prod 광고 유닛)이 필요합니다.
  • 클라이언트 연동: custom_data에 sessionKey만 설정(user_id는 비움), 서버에서 지급 완료(REWARDED)를 확인한 뒤 기능 API를 호출해야 합니다.

✅ PR Checklist

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • PR 제목을 커밋 메시지 컨벤션에 맞게 작성했습니다.

ad_reward_sessions(세션)·ad_reward_logs(감사 로그) 테이블 두개 추가 및 마이그레이션 추가, 엔티티·리포지토리(비관적 락 조회, 활성 세션 만료 포함)
추가
요청 받은 원본 쿼리 그대로 Tink로 SSV 콜백 서명 검증, 결과를 유효/무효/일시오류로 구분
quote(부족분 미리보기)·createSession(세션 발급)·getStatus(폴링) 세가지 서비스 로직 구현, 에러코드 3종 추가
SSV 콜백 처리 + 멱등 지급(비관적 락·txid·상태), 광고 보상 컨트롤러(/ad-rewards) 연결
지급/멱등/만료/세션 발급·조회/콜백 분기/E2E 흐름 검증
@coldsunn
coldsunn merged commit b348839 into develop Sep 20, 2026
1 check passed
@coldsunn
coldsunn deleted the feat/ad-reward branch September 20, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant