Conversation
Test Results12 files 12 suites 0s ⏱️ Results for commit 7a93107. ♻️ This comment has been updated with latest results. |
...rc/main/java/com/nexters/boolti/presentation/screen/prequestionedit/PreQuestionEditScreen.kt
Show resolved
Hide resolved
mangbaam
left a comment
There was a problem hiding this comment.
Recommended Action
- [필수] putPreQuestionAnswer()의 unsafe cast → safe cast 수정 (크래시 방지)
- [필수] receiveGift()에서 recordExceptionHandler 대신 explicit try-catch로 변경하여 실패 이벤트 전송
- [필수] fetchGiftAndPreQuestions() 실패 시 Error 상태 전환 + Loading UI 추가
- [중요] 선물 등록 성공 + 사전질문 실패를 구분하는 별도 이벤트/UX 검토
- [중요] cachedUser null 시 에러 피드백 추가
- [권장] receiveGift() 성공 후 캐시 무효화
| .retry(2) | ||
| .catch { throwable -> | ||
| FirebaseCrashlytics.getInstance().recordException(throwable) | ||
| _events.send(GiftPreQuestionEvent.GiftRegistrationFailed) |
There was a problem hiding this comment.
선물 받기 API 성공 → 사전질문 제출 실패 시 GiftRegistrationFailed 이벤트가 발생합니다. 사용자는 "등록 실패"를 보지만, 실제로 서버에는 선물이 이미 등록된 상태입니다. 사전질문 답변만 누락된 상태로 티켓이 존재하게 됩니다.
또한 .catch가 CancellationException도 잡아서 structured concurrency를 위반합니다.
There was a problem hiding this comment.
권장:
- PreQuestionSubmitFailed 같은 별도 이벤트를 만들어 사전질문 수정 화면으로 안내
- .retry(2) { it !is CancellationException } 조건 추가
- .catch에서 CancellationException은 rethrow
|
|
||
| private fun fetchGiftAndPreQuestions() { | ||
| viewModelScope.launch(recordExceptionHandler) { | ||
| _uiState.update { GiftPreQuestionUiState.Loading } |
There was a problem hiding this comment.
fetchGiftAndPreQuestions() - 실패 시 무한 로딩
GiftPreQuestionViewModel.kt
recordExceptionHandler가 예외를 잡으면 UI 상태가 Loading에 머물러 사용자는 빈 화면만 보게 됩니다. 에러 상태도 없고 재시도 버튼도 없습니다.
There was a problem hiding this comment.
권장:
- GiftPreQuestionUiState.Error 상태 추가
- 명시적 try-catch로 에러 상태 전환 및 재시도 UI 제공
|
|
||
| val senderId = gift.senderUserId | ||
| val hasPreQuestion = ticketingRepository.getPreQuestions(gift.showId).first().isNotEmpty() | ||
| val myUserId = authRepository.cachedUser.first()?.id ?: return@launch |
There was a problem hiding this comment.
authRepository.cachedUser.first()?.id ?: return@launch로 cachedUser가 null이면 아무 피드백 없이 종료됩니다. 딥링크로 진입한 사용자가 아무 반응 없이 막히게 됩니다.
There was a problem hiding this comment.
권장: GiftStatus.FAILED 이벤트를 보내서 에러 다이얼로그 표시
|
|
||
| fun putPreQuestionAnswer(questionId: Long, answer: String) { | ||
| _uiState.update { | ||
| val state = it as GiftPreQuestionUiState.Success |
There was a problem hiding this comment.
val state = it as GiftPreQuestionUiState.Success // unsafe cast!
receiveGift()에서는 as?를 사용하는데 여기만 as를 사용합니다. Loading 상태에서 호출되면 ClassCastException으로 앱이 크래시합니다.
수정: as? ... ?: return@update it 패턴으로 변경
|
|
||
| pendingGift = null | ||
|
|
||
| giftRepository.receiveGift(giftUuid) |
There was a problem hiding this comment.
giftRepository.receiveGift() 자체가 예외를 던지면 recordExceptionHandler가 잡아서 Crashlytics에만 기록합니다. GiftRegistrationFailed 이벤트가 전송되지 않아 사용자에게 아무 피드백이 없습니다.
권장: recordExceptionHandler 대신 명시적 try-catch로 실패 이벤트 전송
| ) { | ||
| val state = uiState | ||
|
|
||
| if (state is GiftPreQuestionUiState.Success) { |
There was a problem hiding this comment.
Success 상태만 렌더링하고, Loading 시 빈 화면이 표시됩니다. 로딩 인디케이터도 에러 UI도 없습니다.
| ) : GiftRepository { | ||
| private data class CacheEntry<T>(val value: T, val cachedAt: Long) | ||
|
|
||
| private val giftCache = ConcurrentHashMap<String, CacheEntry<Gift>>() |
There was a problem hiding this comment.
receiveGift() 후 캐시 무효화 없음
선물 등록 후에도 60초간 이전 상태의 캐시를 반환합니다. receiveGift() 성공 시 giftCache.remove(giftUuid) 추가를 권장합니다
| } | ||
|
|
||
| private fun processGiftWhenLoggedIn(giftUuid: String) { | ||
| viewModelScope.launch(recordExceptionHandler) { |
There was a problem hiding this comment.
recordExceptionHandler로 모든 에러 무시
선물 정보/사전질문 조회 실패 시 다이얼로그가 안 뜹니다. 사용자는 딥링크 후 아무 반응이 없습니다.
| val deepLink = intent.data.toString() | ||
| intent.data = null | ||
| val regex = "^boolti://gift/([\\w-])+$".toRegex() | ||
| if (regex.matches(deepLink)) { |
There was a problem hiding this comment.
딥링크 regex 미매칭 시 로깅 없음
HomeScreen.kt에서 boolti://gift/ 패턴 미매칭 시 사일런트 드롭됩니다. 디버깅이 어렵습니다.
Issue
작업 내용
BE 논의 내용