Skip to content

통계 상세 API 연동 및 인터렉션 적용#111

Merged
dogmania merged 27 commits intodevelopfrom
feat/#110-stats-detail-api
Feb 26, 2026
Merged

통계 상세 API 연동 및 인터렉션 적용#111
dogmania merged 27 commits intodevelopfrom
feat/#110-stats-detail-api

Conversation

@chanho0908
Copy link
Member

@chanho0908 chanho0908 commented Feb 25, 2026

이슈 번호

#110

작업내용

  • 통계 상세 화면 API를 캘린더/요약으로 분리 연동했습니다.
  • StatsRepository/StatsDetail 모델을 서버 응답 구조에 맞게 정리
  • Stats 상세 진입 경로를 날짜 필수 파라미터로 통일
  • StatsDetailViewModel 초기 로딩을 요약/캘린더 데이터 분리 처리로 개선
  • 인증된 목표에 한해 인증샷 상세 화면 이동 기능
  • 목표 편집/삭제/끝내기
  • 인증샷 수정 후 상세 화면 복귀시 내 사진이 먼저 뜨도록 수정
image

결과물

인증샷 촬영 후 내 사진이 먼저뜨게 수정 통계 화면에서 목표 수정
진행중인 목표 끝내기 진행중인 목표 삭제하기
종료된 목표 삭제하기
:--:

리뷰어에게 추가로 요구하는 사항 (선택)

@chanho0908 chanho0908 linked an issue Feb 25, 2026 that may be closed by this pull request
1 task
@chanho0908 chanho0908 changed the title ✨ Feat: 통계 상세 API 연동 및 상세 화면 구조 개편 통계 상세 API 연동 Feb 25, 2026
@chanho0908 chanho0908 self-assigned this Feb 25, 2026
@chanho0908 chanho0908 added the Feature Extra attention is needed label Feb 25, 2026
coderabbitai[bot]

This comment was marked as resolved.

@chanho0908 chanho0908 requested a review from dogmania February 25, 2026 20:33
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt (1)

64-66: ⚠️ Potential issue | 🟠 Major

collectLatest 취소가 실제 네트워크 요청 취소로 이어지지 않습니다.

이전 리뷰에서도 지적된 내용이지만, 아직 해결되지 않아 다시 언급합니다.

왜 문제인가요?

  • fetchStatsDetail(yearMonth) (Line 115)은 일반 함수로, 내부에서 launchResultviewModelScope.launch독립적인 코루틴을 띄운 뒤 즉시 반환합니다.
  • 결과적으로 collectLatest 블록이 새로운 월 선택으로 취소될 시점에는, fetchStatsDetail()은 이미 리턴된 상태이고 네트워크 요청 코루틴은 viewModelScope에 살아 있습니다.
  • 느린 이전 월 요청이 빠른 새 월 요청보다 늦게 완료되면 UI 상태가 오래된 데이터로 덮어씌워지는 응답 역전(response ordering) 문제가 발생합니다.

어떻게 개선할 수 있나요?

fetchStatsDetailsuspend 함수로 변경하여 collectLatest 스코프 내에서 완료를 기다리도록 하는 방법이 가장 깔끔합니다.

🔧 개선 방안: fetchStatsDetail을 suspend 함수로 리팩터링
-    private fun fetchStatsDetail(date: YearMonth) {
-        if (checkCache(date)) return
-        launchResult(
-            block = { statsRepository.fetchStatsDetail(currentState.goalId, date) },
-            onSuccess = { handleFetchStatsDetailSuccess(it) },
-            onError = {
-                reduceDetailWithEmptyCompletedDate(date)
-                showToast(R.string.toast_fetch_stats_failed, ToastType.ERROR)
-            },
-        )
-    }
+    private suspend fun fetchStatsDetail(date: YearMonth) {
+        if (checkCache(date)) return
+        when (val result = statsRepository.fetchStatsDetail(currentState.goalId, date)) {
+            is AppResult.Success -> handleFetchStatsDetailSuccess(result.data)
+            is AppResult.Error -> {
+                handleError(result.error)
+                reduceDetailWithEmptyCompletedDate(date)
+                showToast(R.string.toast_fetch_stats_failed, ToastType.ERROR)
+            }
+        }
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt`
around lines 64 - 66, The collectLatest cancellation isn't cancelling the actual
network request because fetchStatsDetail(yearMonth) starts a new independent
coroutine via launchResult/viewModelScope.launch and returns immediately; change
fetchStatsDetail to a suspend function that performs the network call in the
caller coroutine (remove the internal viewModelScope.launch/launchResult usage),
have it use structured concurrency (e.g., suspend functions + withContext or
coroutineScope) to perform the request and return the result or update state
before returning, and then call the new suspend fetchStatsDetail(yearMonth)
directly inside collectLatest so cancellation of collectLatest cancels the
in-flight request and prevents stale UI updates.
🧹 Nitpick comments (1)
feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt (1)

191-199: 변수명과 실제 타입 간의 의미 불일치를 개선하면 어떨까요?

previousMonthnextMonth는 이름만 보면 YearMonth 타입처럼 느껴지지만, 실제로는 LocalDate (해당 월의 특정 일 포함)입니다. 이후 YearMonth.from(previousMonth)로 다시 변환하는 것도 이 때문인데, 처음부터 YearMonth 타입으로 계산하면 의도가 더 명확해집니다.

✨ 타입 명확화 제안
 private fun fetchPreviousMonth() {
-    val previousMonth = currentState.detail.yearMonth.minusMonths(1)
-    reduce { copy(detail = detail.copy(yearMonth = previousMonth)) }
-    monthChangeFlow.tryEmit(YearMonth.from(previousMonth))
+    val previousYearMonth = YearMonth.from(currentState.detail.yearMonth).minusMonths(1)
+    reduce { copy(detail = detail.copy(yearMonth = previousYearMonth.atDay(1))) }
+    monthChangeFlow.tryEmit(previousYearMonth)
 }

 private fun fetchNextMonth() {
-    val nextMonth = currentState.detail.yearMonth.plusMonths(1)
-    reduce { copy(detail = detail.copy(yearMonth = nextMonth)) }
-    monthChangeFlow.tryEmit(YearMonth.from(nextMonth))
+    val nextYearMonth = YearMonth.from(currentState.detail.yearMonth).plusMonths(1)
+    reduce { copy(detail = detail.copy(yearMonth = nextYearMonth.atDay(1))) }
+    monthChangeFlow.tryEmit(nextYearMonth)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt`
around lines 191 - 199, previousMonth and nextMonth are being treated as
LocalDate then converted back to YearMonth; instead compute and keep them as
YearMonth directly in fetchPreviousMonth and fetchNextMonth by using
currentState.detail.yearMonth.minusMonths(1) / .plusMonths(1), change the
variable types to YearMonth, and emit monthChangeFlow.tryEmit(previousMonth) /
tryEmit(nextMonth) (remove the YearMonth.from(...) conversions) while keeping
the existing reduce { copy(detail = detail.copy(yearMonth = ...)) } updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt`:
- Around line 64-66: The collectLatest cancellation isn't cancelling the actual
network request because fetchStatsDetail(yearMonth) starts a new independent
coroutine via launchResult/viewModelScope.launch and returns immediately; change
fetchStatsDetail to a suspend function that performs the network call in the
caller coroutine (remove the internal viewModelScope.launch/launchResult usage),
have it use structured concurrency (e.g., suspend functions + withContext or
coroutineScope) to perform the request and return the result or update state
before returning, and then call the new suspend fetchStatsDetail(yearMonth)
directly inside collectLatest so cancellation of collectLatest cancels the
in-flight request and prevents stale UI updates.

---

Nitpick comments:
In
`@feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt`:
- Around line 191-199: previousMonth and nextMonth are being treated as
LocalDate then converted back to YearMonth; instead compute and keep them as
YearMonth directly in fetchPreviousMonth and fetchNextMonth by using
currentState.detail.yearMonth.minusMonths(1) / .plusMonths(1), change the
variable types to YearMonth, and emit monthChangeFlow.tryEmit(previousMonth) /
tryEmit(nextMonth) (remove the YearMonth.from(...) conversions) while keeping
the existing reduce { copy(detail = detail.copy(yearMonth = ...)) } updates.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db56c7e and b426e92.

📒 Files selected for processing (1)
  • feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt

@chanho0908 chanho0908 changed the title 통계 상세 API 연동 통계 상세 API 연동 및 인터렉션 적용 Feb 26, 2026
coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

- `GoalManageViewModel`에서 목표 완료 또는 삭제 성공 시 `StatsRefreshBus`를 통해 통계 화면 갱신을 알리는 로직 추가
coderabbitai[bot]

This comment was marked as resolved.

@YAPP-Github YAPP-Github deleted a comment from coderabbitai bot Feb 26, 2026
@YAPP-Github YAPP-Github deleted a comment from coderabbitai bot Feb 26, 2026
Copy link
Member

@dogmania dogmania left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다! 이제 각자 구현한 게 많아졌다 보니까 코드 읽기에 도움되는 방향으로 리뷰 남겨봤어요!

Comment on lines 7 to 11
enum class Target {
InProgress,
End,
All,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이제 각자 구현한 코드도 많아졌고, 기존에 존재하던 파일을 수정했을 때 좀 더 수월하게 리뷰할 수 있도록 주석을 추가하면 좋을 것 같아요! Target이 어디에 쓰이는 건지 간단한 설명이 있으면 코드 읽을 때 도움될 것 같슴다

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 생각인 것 같아 ! 주석을 남기면 나중에 내가 봤을 때도 다시 코드의 의도를 떠올리기 좋은 것 같아
우선 여기만 반영하고 데모 끝나면 전체적으로 리팩터링 하면서 주석 추가하도록 할게 👍

리뷰 반영 커밋 : 4da8df8

val status: String,
val monthDate: LocalDate,
val isCompleted: Boolean,
val yearMonth: LocalDate,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 변수 타입이랑 사용되는 용도를 봤을 때 yearMonth보다는 currentDate가 더 직관적일 거 같아요! StatsCalendarUiModel에서도 currentDate라는 변수명을 사용하고 있으니까 통일성에도 좋을 것 같습니다

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리뷰 반영 커밋 : 5231b18

coderabbitai[bot]

This comment was marked as resolved.

@YAPP-Github YAPP-Github deleted a comment from coderabbitai bot Feb 26, 2026
@chanho0908 chanho0908 requested a review from dogmania February 26, 2026 17:38
@YAPP-Github YAPP-Github deleted a comment from coderabbitai bot Feb 26, 2026
Copy link
Member

@dogmania dogmania left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다~!!

@dogmania dogmania merged commit 4b62fbc into develop Feb 26, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature Extra attention is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

통계 상세 API 연동

2 participants