15 KiB
15 KiB
20260430 채팅 쿼터 충전 확장 계획
작업 체크리스트
- 기존 채팅 쿼터 UI, 응답 DTO, 구매 API, Yandex 광고 사용 패턴을 근거 파일 기준으로 조사한다.
QA:ChatRoomActivity,ChatMessageAdapter,ChatQuotaPurchaseRequest,TalkApi,ChatRepository,AudioContentDetailActivity,app/build.gradle를 근거로 현재 구조를 설명할 수 있어야 한다. - 쿼터 안내 노출 조건을
nextRechargeAtEpoch != null에서totalRemaining <= 0기준으로 전환한다.
QA: 채팅방 입장, 메시지 전송 응답, 쿼터 상태 조회, 쿼터 구매 응답 모두에서updateQuotaUi가totalRemaining기준으로만 노출 여부를 결정해야 한다. - 무료 충전 제거에 맞춰 카운트다운 및 무료 대기 문구 관련 로직을 제거한다.
QA:CountDownTimer,tv_time,nextRechargeAtEpoch기반 갱신,checkQuotaStatus()의 무료 충전 재조회 목적 로직이 더 이상 남지 않아야 한다. item_chat_quota_notice를 2단 구성의 신규 구매 UI로 교체한다.
QA: 상단에는 광고 버튼 1개, 하단에는 캔 구매 버튼 2개가 가로 배치되어야 하며, 기존 시간/무료 안내 문구 영역은 제거되어야 한다.- 광고 버튼과 캔 구매 버튼의 텍스트/스타일을 요청 사양대로 반영한다.
QA: 광고 버튼은광고 / 5채팅, 하단 버튼은10 / 15채팅,20 / 40채팅구조를 가지며, 각 캔 숫자 앞에ic_can아이콘이 표시되고 캔 숫자는 bold, 채팅 개수는 medium이어야 한다. - 쿼터 구매 요청 DTO를 광고/캔 구매 구분이 가능하도록 확장한다.
QA: 요청 본문에container,chargeType,canOption이 포함되고, 캔 구매 시CAN_10,CAN_20, 광고 구매 시AD타입을 표현할 수 있어야 한다. - Yandex 채팅 쿼터 전용 rewarded ad unit id를 buildType별
BuildConfig로 추가한다.
QA:debug/release에서 채팅 쿼터 광고용 별도BuildConfig키가 생성되어야 하며, 기존 오디오 콘텐츠 전면 광고 id와 분리되어야 한다. totalRemaining == 1일 때 광고를 미리 준비하고, 광고 버튼 터치 시 rewarded 광고를 표시한 뒤onRewarded()시점에 쿼터 충전 API를 호출하도록 흐름을 추가한다.
QA: 광고 미로드/표시 실패 시에는 API가 호출되지 않아야 하고, 사용자가 reward 조건을 충족했을 때만AD타입 구매 요청이 한 번만 전송되어야 한다.- 캔 구매 버튼 2종이 각각 올바른 구매 옵션으로 API를 호출하고, 성공 시 헤더 캔 수와 쿼터 UI를 갱신하도록 정리한다.
QA: 10캔 버튼은 15채팅, 20캔 버튼은 40채팅과 연결되고, 성공 후SharedPreferenceManager.can및tvCanBadge가 실제 차감값에 맞게 갱신되어야 한다. - 변경 결과를 문서 하단 검증 기록에 누적한다.
QA: 최소 빌드, 테스트, 수동 확인 계획과 실제 실행 결과가 한국어로 누적되어야 한다.
범위 메모
- 이번 요청은
ChatRoomActivity의 채팅 쿼터 부족 안내와 구매 흐름을 광고/캔 3가지 선택지로 확장하는 작업으로 한정한다. - 무료 충전은 제거되므로, 기존
nextRechargeAtEpoch기반 표시 판단과 카운트다운 UI/로직은 제거 대상으로 본다. - 안내 노출 여부는
totalRemaining <= 0일 때만 표시하는 방향으로 고정한다. - 광고 버튼은 Yandex rewarded ad를 사용하고, reward 지급 콜백인
onRewarded()시점에 쿼터 충전 API를 호출한다. - reward 기준으로 처리하므로, 광고가 단순히 표시되거나 닫힌 것만으로는 보상을 지급하지 않는다.
- 광고 unit id는 기존
app/build.gradle의buildConfigField패턴을 유지하되, 채팅 쿼터 지면은 별도 키로 분리한다. - 캔 구매 옵션은 요청에 맞춰
10캔→15채팅,20캔→40채팅두 가지만 제공한다. AD타입 쿼터 지급은 서버가 광고 보상 완료를 검증할 수 있는 구조(예: SSV, 검증 토큰, nonce/idempotency)인지 별도 확인이 필요하다.- 요청 범위를 넘는 별도 결제 화면 추가, 무료 충전 대체 UX 확장, 다른 화면 공통화 리팩터링은 제외한다.
조사 근거
- 현재 채팅 쿼터 흐름
app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.ktapp/src/main/res/layout/item_chat_quota_notice.xml
- 쿼터 응답/구매 DTO
app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomEnterResponse.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/SendChatMessageResponse.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/quota/ChatQuotaStatusResponse.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/quota/ChatQuotaPurchaseRequest.kt
- API/Repository
app/src/main/java/kr/co/vividnext/sodalive/chat/talk/TalkApi.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRepository.kt
- 기존 Yandex 광고/전면광고 패턴
app/src/main/java/kr/co/vividnext/sodalive/audio_content/detail/AudioContentDetailActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/app/SodaLiveApp.ktapp/build.gradle
- 공식 문서
https://ads.yandex.com/helpcenter/en/dev/android/interstitialhttps://ads.yandex.com/helpcenter/en/dev/android/rewarded
구현 계획
1. 쿼터 상태 판단 기준 전환
- 수정 대상:
app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomEnterResponse.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/SendChatMessageResponse.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/quota/ChatQuotaStatusResponse.kt
- 계획:
updateQuotaUi시그니처와 호출부를nextRechargeAtEpoch대신totalRemaining중심으로 재구성한다.- 입장 응답, 메시지 전송 응답, 쿼터 조회/구매 응답에서 모두 동일한 판단식을 사용한다.
inputContainer표시 여부도totalRemaining > 0기준으로 정리한다.
2. 무료 충전/카운트다운 제거
- 수정 대상:
app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.ktapp/src/main/res/layout/item_chat_quota_notice.xml
- 계획:
quotaTimer,startQuotaCountdown,stopQuotaCountdown,formatEpochToHms,formatMillisToHms,checkQuotaStatus의 역할을 재평가하고, 무료 충전용 로직은 제거한다.ChatListItem.QuotaNotice가 시간 텍스트를 들고 다니는 구조를 단순화한다.QuotaNoticeViewHolder의tv_time의존성을 제거하고, 버튼 클릭만 처리하는 형태로 바꾼다.
3. QuotaNotice 레이아웃 교체
- 수정 대상:
app/src/main/res/layout/item_chat_quota_notice.xml- 필요 시 관련 drawable / string 리소스
- 계획:
- 상단 시간/무료 안내 블록을 제거하고 광고 버튼 1개를
match_parent로 배치한다. - 하단에는 좌우 2개 버튼을 동일 행에 둔다.
- 광고 버튼 배경색
RGB(254, 248, 227), borderRGB(247, 203, 80)를 기존 코드 스타일에 맞춰 hex로 정의한다. - 버튼 텍스트는 국제화 리소스로 분리하되, 요청 문구를 그대로 반영한다.
- 상단 시간/무료 안내 블록을 제거하고 광고 버튼 1개를
4. 캔 구매 DTO 및 API 호출 확장
- 수정 대상:
app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/quota/ChatQuotaPurchaseRequest.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/TalkApi.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRepository.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt
- 계획:
- 기존
ChatQuotaPurchaseRequest를 요청 사양에 맞게 확장하고, 필요하면 내부 클래스명도 API 계약과 맞는 방향으로 정리한다. ChatRoomQuotaChargeType,ChatRoomQuotaCanOptionenum을 추가한다.purchaseChatQuota(...)가 광고/캔 버튼별로 다른 요청 본문을 받을 수 있게 repository 시그니처를 확장한다.
- 기존
5. 채팅 쿼터 전용 Yandex rewarded 흐름 추가
- 수정 대상:
app/build.gradleapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt
- 계획:
debug/release각각에 채팅 쿼터 rewarded ad unit idBuildConfig키를 추가한다.- 기존 Yandex 광고 초기화 구조는 유지하고, rewarded ad의 loader / load listener / event listener /
show(activity)패턴을 채팅방에 맞게 적용한다. totalRemaining == 1시점에 preload를 시도하고, 광고 버튼 터치 시 로드된 광고가 있으면 표시한다.onRewarded()콜백에서AD타입 쿼터 구매 API를 호출한다.onAdFailedToShow,onAdDismissed,onDestroy에서 listener와 ad 참조를 정리한다.
6. 버튼별 구매 액션과 로컬 상태 갱신 정리
- 수정 대상:
app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt
- 계획:
- 어댑터 콜백을 광고/10캔/20캔으로 구분 가능한 형태로 확장하거나, 단일 콜백에 옵션 인자를 전달하도록 바꾼다.
- 캔 구매 성공 시에는 선택한
needCan만큼SharedPreferenceManager.can을 차감하고tvCanBadge를 갱신한다. - 광고 구매 성공 시에는 캔 차감 없이 쿼터 UI만 갱신한다.
- 응답의
totalRemaining기준으로 입력창 복구 여부와 QuotaNotice 제거 여부를 결정한다.
예상 수정 파일
docs/20260430_채팅쿼터충전확장계획.mdapp/build.gradleapp/src/main/res/layout/item_chat_quota_notice.xmlapp/src/main/res/values/strings.xmlapp/src/main/res/values-en/strings.xmlapp/src/main/res/values-ja/strings.xmlapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/quota/ChatQuotaPurchaseRequest.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/quota/ChatQuotaStatusResponse.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomEnterResponse.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/SendChatMessageResponse.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/TalkApi.ktapp/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRepository.kt
검증 계획
./gradlew :app:assembleDebug./gradlew :app:testDebugUnitTest- 필요 시
./gradlew :app:ktlintCheck - 수동 확인:
totalRemaining > 0상태에서 입력창이 보이고 QuotaNotice가 사라지는지 확인한다.totalRemaining <= 0상태에서 신규 QuotaNotice UI가 노출되는지 확인한다.totalRemaining == 1일 때 rewarded 광고 preload가 준비되는지 로그 또는 디버그 포인트로 확인한다.- 광고 버튼 탭 시 rewarded 광고가 뜨고
onRewarded()직후AD타입 구매 요청이 1회 호출되는지 확인한다. - 10캔/20캔 버튼 각각이 15채팅/40채팅 구매와 연결되고, 성공 후 헤더 캔 수와 입력창 상태가 갱신되는지 확인한다.
검증 기록
- 2026-04-30
- 무엇: 채팅 쿼터 충전 확장 작업의 계획 문서를 생성했다.
- 왜: 저장소 규칙에 따라 구현 전에
docs아래 계획 문서를 먼저 만들고, 그 문서를 기준으로 범위·근거·검증 기준을 고정해야 하기 때문이다. - 어떻게:
- 생성 파일:
docs/20260430_채팅쿼터충전확장계획.md - 근거 파일:
ChatRoomActivity.kt,ChatMessageAdapter.kt,item_chat_quota_notice.xml,ChatQuotaPurchaseRequest.kt,ChatQuotaStatusResponse.kt,TalkApi.kt,ChatRepository.kt,ChatRoomEnterResponse.kt,SendChatMessageResponse.kt,AudioContentDetailActivity.kt,app/build.gradle - 근거 문서:
https://ads.yandex.com/helpcenter/en/dev/android/interstitial,https://ads.yandex.com/helpcenter/en/dev/android/rewarded - 결과: 무료 충전 제거,
totalRemaining기준 노출 전환, 광고/캔 3가지 구매 UI, DTO 확장, Yandex rewarded 연동 범위, 예상 수정 파일과 검증 계획을 구현 전에 먼저 확정했다.
- 생성 파일:
- 2026-04-30
- 무엇: 채팅 쿼터 충전 확장 구현과 검증을 완료했다.
- 왜: 무료 충전 제거 이후에도 채팅 쿼터 부족 상태에서 rewarded 광고와 2종의 캔 구매 옵션으로 다시 충전할 수 있어야 했기 때문이다.
- 어떻게:
- 수정 파일:
app/build.gradle,app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt,app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.kt,app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/quota/ChatQuotaPurchaseRequest.kt,app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRepository.kt,app/src/main/res/layout/item_chat_quota_notice.xml,app/src/main/res/drawable/bg_chat_quota_rewarded_ad_button.xml,app/src/main/res/values/strings.xml,app/src/main/res/values-en/strings.xml,app/src/main/res/values-ja/strings.xml,app/src/test/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapterTest.kt - 구현 내용:
totalRemaining기준 QuotaNotice 노출 전환, countdown/free-wait 로직 제거, rewarded 광고 preload/show/onRewarded 구매 호출, 10캔/20캔 구매 분기, 채팅 쿼터 전용 rewarded ad unit id 추가, QuotaNotice 3버튼 UI 적용 - 실행 명령:
./gradlew :app:testDebugUnitTest :app:assembleDebug - 실행 결과:
BUILD SUCCESSFUL - 실행 명령:
./gradlew :app:ktlintCheck - 실행 결과:
BUILD SUCCESSFUL - 진단 도구:
lsp_diagnostics - 진단 결과:
.ktLSP 서버 미설정으로No LSP server configured for extension: .kt - 수동 확인 시도:
adb devices - 수동 확인 결과: 연결된 Android 기기가 없어 앱 실행 기반의 광고 노출/버튼 동작 수동 검증은 이번 세션에서 진행하지 못했다.
- 수정 파일:
- 2026-04-30
- 무엇: 리뷰 피드백을 반영해 중복 요청 방지와 rewarded preload 조건을 보강하고, 서버 검증 리스크를 문서에 기록했다.
- 왜: 빠른 연속 탭으로 인한 중복 구매/중복 광고 시도와, 이미 quota가 소진된 상태에서 첫 광고 탭이 항상 실패하는 UX를 줄여야 했기 때문이다.
- 어떻게:
- 수정 파일:
app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt,docs/20260430_채팅쿼터충전확장계획.md - 로직 보강:
isQuotaPurchaseInFlight,isChatQuotaRewardedAdShowing가드 추가, rewarded preload 조건을totalRemaining <= 1로 확장 - 문서 반영:
AD타입 쿼터 지급의 서버 검증/SSV/idempotency 확인 필요성을 범위 메모에 기록
- 수정 파일: