11 KiB
11 KiB
20260430 채팅 쿼터 충전 확장
작업 체크리스트
ChatRoomViewModel의 쿼터 안내 표시 기준을nextRechargeAtEpochnull 여부에서totalRemaining <= 0기준으로 전환한다.- 무료 충전이 없어진 정책에 맞춰 채팅방 쿼터 카운트다운/무료 대기 관련 상태와 타이머 로직을 제거한다.
ChatQuotaNoticeItemView를 2단 구성으로 재작성하고, 광고 버튼 1개 + 캔 구매 버튼 2개 UI를 요구사항 스펙에 맞게 반영한다.- 채팅 쿼터 구매 요청 DTO를
CAN/AD충전 타입과 캔 옵션을 전달할 수 있도록 확장한다. ChatRoomQuotaChargeType,ChatRoomQuotaCanOption모델을 iOS 코드베이스 규칙에 맞게 추가한다.- 채팅방 쿼터 구매 흐름을 광고 보상 충전과 캔 옵션 충전으로 분기한다.
totalRemaining <= 1일 때 채팅 쿼터 전용 Yandex rewarded 광고를 준비하도록 채팅방 진입/상태 갱신 흐름을 확장한다.- 광고 버튼 탭 시 Yandex rewarded 광고를 표시하고, 리워드 지급 가능 시점에만 쿼터 충전 API를 호출하도록 연결한다.
- 채팅방 쿼터 관련 문자열/I18n 사용 여부를 정리하고, 제거/추가가 필요한 문구를 반영한다.
- 수정 파일 진단과 빌드를 실행하고 결과를 검증 기록에 남긴다.
작업 기준
- 사용자 요청 대상 화면:
SodaLive/Sources/Chat/Talk/Room/ChatRoomView.swiftSodaLive/Sources/Chat/Talk/Room/Quota/ChatQuotaNoticeItemView.swift
- 현재 쿼터 상태/로직:
SodaLive/Sources/Chat/Talk/Room/ChatRoomViewModel.swiftSodaLive/Sources/Chat/Talk/Room/Quota/ChatQuotaStatusResponse.swiftSodaLive/Sources/Chat/Talk/Room/Enter/ChatRoomEnterResponse.swiftSodaLive/Sources/Chat/Talk/Room/Message/SendChatMessageResponse.swift
- 쿼터 구매 API/DTO:
SodaLive/Sources/Chat/Talk/Room/ChatRoomRepository.swiftSodaLive/Sources/Chat/Talk/TalkApi.swiftSodaLive/Sources/Chat/Talk/Room/Quota/ChatQuotaPurchaseRequest.swift
- 광고 공용 지원:
SodaLive/Sources/Common/YandexAdSupport.swiftSodaLive/Sources/App/AppDelegate.swift
- 문자열 경로:
SodaLive/Sources/I18n/I18n.swift
- 공식 문서:
https://ads.yandex.com/helpcenter/en/dev/ios/rewarded
QA 기준
ChatRoomViewModel은nextRechargeAtEpochnull 여부와 무관하게totalRemaining <= 0일 때만showQuotaNoticeView를true로 만든다.- 채팅방 쿼터 안내 영역에는 더 이상 시간 아이콘, 카운트다운 텍스트,
기다리면 무료 이용이 가능합니다문구가 표시되지 않는다. - 상단 광고 버튼은
광고 / 5채팅라벨로 표시되고, 배경색은 hexFEF8E3(RGB254, 248, 227), 보더는 hexF7CB50(RGB247, 203, 80)로 적용된다. - 하단에는 가로 2개 버튼이 표시되고, 왼쪽은
ic_can + 10 / 15채팅, 오른쪽은ic_can + 20 / 40채팅구성이 적용된다. - 버튼 내 캔 숫자는 bold, 채팅 개수 텍스트는 medium 폰트로 구분된다.
- 채팅 쿼터 구매 요청은 광고 충전 시
chargeType = AD, 캔 충전 시chargeType = CAN과 선택한canOption을 함께 전송한다. totalRemaining <= 1상태 진입 시 채팅 쿼터 전용 rewarded 광고가 준비되고, 광고 버튼 탭 시 로드된 광고가 있으면 표시된다.- rewarded 광고 보상 가능 콜백에서만 쿼터 충전 API가 호출되고, 로드 실패/표시 실패/보상 미지급 시에는 API가 호출되지 않는다.
- 광고/캔 충전 성공 후 채팅 쿼터 UI와 사용자 can 잔액이 응답 기준으로 올바르게 갱신된다.
- 변경 파일
lsp_diagnostics확인과xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build,xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build가 통과한다.
구현 메모
- 현재
ChatRoomViewModel.updateQuota(nextRechargeAtEpoch:)는 epoch 존재 여부와 타이머로 쿼터 안내 노출을 제어하므로,totalRemaining을 받는 형태로 시그니처와 호출부 전체를 함께 정리해야 한다. ChatRoomEnterResponse,SendChatMessageResponse,ChatQuotaStatusResponse에는 이미totalRemaining이 있으므로, UI 분기와 광고 준비 판단은 이 값을 기준으로 통일한다.- 현재
ChatQuotaPurchaseRequest는container만 전송하므로, 요청 스펙 확장 시 기존 기본값(ios)은 유지하고 charge type / can option만 추가한다. ChatQuotaNoticeItemView의 기존I18n.Chat.Room.quotaWaitForFreeNotice,quotaPurchaseAction(chatCount:)는 신규 UI에 맞지 않을 수 있으므로 재사용 여부를 점검하고 필요 시 신규 문자열을 추가한다.- 기존
YandexAdSupport.swift에는YandexInlineBannerView,YandexInterstitialAdManager만 있으므로, rewarded 광고는 동일 파일에 공용 매니저를 추가하는 방향을 우선 검토한다. - Yandex 공식 rewarded 문서 기준으로 SDK 호출은 메인 스레드에서 수행하고,
RewardedAdLoader로드 성공 후 광고 객체를 유지한 뒤didReward시점에만 보상 API를 연결한다. - 광고 unit id는 기존 배너/전면광고 unit id를 재사용하지 않고, 채팅 쿼터 rewarded 광고 전용 상수를 Constants 계층에 별도로 추가한다. 실제 상수 추가 위치는 구현 시 운영/디버그 Constants 파일 확인 후 확정한다.
totalRemaining <= 1에서 “광고 준비”를 요구하므로, 채팅방 진입 직후/메시지 전송 응답/쿼터 상태 재조회/충전 완료 이후까지 동일 조건으로 preload 경로가 유지되어야 한다.
검증 기록
-
2026-04-30 / 계획 수립
- 무엇/왜/어떻게: 채팅 쿼터 충전 확장 구현 전에 현재 채팅방 쿼터 표시 로직, 구매 DTO, Yandex 광고 지원 범위를 확인하고 실제 수정 범위를 계획 문서로 정리했다.
- 확인 근거:
SodaLive/Sources/Chat/Talk/Room/ChatRoomView.swiftSodaLive/Sources/Chat/Talk/Room/Quota/ChatQuotaNoticeItemView.swiftSodaLive/Sources/Chat/Talk/Room/ChatRoomViewModel.swiftSodaLive/Sources/Chat/Talk/Room/Quota/ChatQuotaPurchaseRequest.swiftSodaLive/Sources/Common/YandexAdSupport.swiftSodaLive/Sources/I18n/I18n.swifthttps://ads.yandex.com/helpcenter/en/dev/ios/rewarded- 기존 계획 문서 패턴:
docs/20260320_채팅창얼림버튼및문구수정.md,docs/20260428_채팅탭Yandex배너추가.md,docs/20260428_Yandex광고화면배치구현.md
- 결과:
- 현재 쿼터 안내는
nextRechargeAtEpoch기반 카운트다운 구조임을 확인 totalRemaining은 응답 모델에 존재하지만 UI 분기에는 아직 미사용임을 확인- 공용 Yandex 지원은 배너/인터스티셜까지 구현되어 있고 rewarded 지원은 별도 추가가 필요함을 확인
- 위 범위를 기준으로 구현 체크리스트와 QA 기준을 확정
- 현재 쿼터 안내는
-
2026-04-30 / 구현 및 검증
- 무엇/왜/어떻게: 무료 충전 제거 정책에 맞춰 채팅 쿼터 안내 노출 기준을
totalRemaining <= 0으로 전환하고, 광고/캔 충전 UI와CAN/AD구매 요청 DTO, Yandex rewarded 광고 보상 콜백 기반 API 호출 흐름을 구현했다. - 실행 명령/도구:
lsp_diagnostics:SodaLive/Sources/Chat/Talk/Room/ChatRoomViewModel.swiftSodaLive/Sources/Chat/Talk/Room/ChatRoomView.swiftSodaLive/Sources/Common/YandexAdSupport.swiftSodaLive/Sources/Chat/Talk/Room/Quota/ChatQuotaPurchaseRequest.swiftSodaLive/Sources/I18n/I18n.swiftSodaLive/Sources/Chat/Talk/Room/Quota/ChatQuotaNoticeItemView.swift
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug buildxcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug buildxcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" testxcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" testrg "countdownText|quotaWaitForFreeNotice|quotaPurchaseAction|remainingTime|stopTimer|startTimer\(" "SodaLive/Sources/Chat/Talk/Room" "SodaLive/Sources/I18n/I18n.swift"rg "totalRemaining <= 0|totalRemaining <= 1|ChatRoomQuotaChargeType|ChatRoomQuotaCanOption|YandexRewardedAdManager|YANDEX_CHAT_ROOM_QUOTA_REWARDED_AD_UNIT_ID|quotaAdAction|quotaChatCount" "SodaLive/Sources"
- 결과:
ChatQuotaPurchaseRequest.swift는 LSP 진단 없음.- 나머지 SwiftUI/네트워크/광고 파일은 SourceKit 단독 해석 환경에서
Kingfisher,Moya,YandexMobileAds, 프로젝트 확장 심볼을 해석하지 못하는 환경성 오류가 있었지만, 실제xcodebuild실컴파일은 두 스킴 모두 통과했다. SodaLive-devDebug 빌드 성공.SodaLiveDebug 빌드 성공. Crashlytics dSYM 관련 기존 빌드 경고는 있었지만 빌드는 성공했다.- 테스트는 두 스킴 모두
Scheme ... is not currently configured for the test action으로 실행 불가했다. - 제거 대상 카운트다운/무료 대기 심볼 검색 결과는 없음.
- 신규 쿼터 기준/DTO/광고/I18n 심볼 검색 결과가 기대 위치에서 확인됨.
- 채팅 쿼터 rewarded ad unit id는 별도 상수로 추가했으며, 실제 운영 unit id가 제공되지 않아 현재 값은 Yandex 공식 demo rewarded unit id(
demo-rewarded-yandex)로 둔다.
- 무엇/왜/어떻게: 무료 충전 제거 정책에 맞춰 채팅 쿼터 안내 노출 기준을
-
2026-04-30 / rewarded 콜백 미호출 수정
- 무엇/왜/어떻게: rewarded 광고가 표시된 뒤
didReward/didDismiss콜백이 호출되지 않는 문제를 공식 문서 기준으로 점검하고, 로드 성공 직후RewardedAd.delegate를 설정하며 광고 표시 중RewardedAd강한 참조를 유지하도록 수정했다. - 실행 명령/도구:
- 공식 문서 확인:
https://ads.yandex.com/helpcenter/en/dev/ios/rewarded,https://ads.yandex.com/helpcenter/en/dev/ios/demo-blocks rg "loadedAd.delegate = self|rewardedAd.show|rewardedAd = nil|didReward|purchaseChatQuota\(chargeType: \.ad" "SodaLive/Sources/Common/YandexAdSupport.swift" "SodaLive/Sources/Chat/Talk/Room/ChatRoomViewModel.swift"lsp_diagnostics:SodaLive/Sources/Common/YandexAdSupport.swiftxcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
- 공식 문서 확인:
- 결과:
- 공식 문서에는 iOS Simulator에서 rewarded 콜백이 동작하지 않는다는 제한이 명시되어 있지 않다.
- 공식 문서는
RewardedAd와RewardedAdLoader의 강한 참조 유지, 로드 성공 후 delegate 설정을 권장한다. YandexRewardedAdManager.preloadAd에서 로드 성공 직후loadedAd.delegate = self를 설정하도록 변경했다.showAdIfAvailable에서 광고 표시 직전rewardedAd를 nil로 만들지 않도록 변경해 표시 생명주기 동안 강한 참조를 유지했다.SodaLive-devDebug 빌드 성공.- SourceKit 단독 LSP는 기존과 동일하게
YandexMobileAds모듈 미해결 환경성 오류를 보고했으나, 실제xcodebuild는 통과했다.
- 무엇/왜/어떻게: rewarded 광고가 표시된 뒤