Conversation
Walkthrough챌린지 미션 진행 API 연동을 위해 DTO/모델/서비스/데이터소스/리포지토리와 DI 바인딩을 추가하고, 뷰모델 및 관련 UI를 실제 데이터 흐름에 맞춰 리팩터링했습니다. 또한 공유 Changes
Sequence Diagram(s)sequenceDiagram
participant VM as ViewModel
participant Repo as Repository
participant DS as DataSource
participant Svc as RetrofitService
participant API as Backend
VM->>VM: loadMissions()
VM->>Repo: getChallengeMissions()
Repo->>DS: getChallengeMissions()
DS->>Svc: getChallengeMissions()
Svc->>API: GET /api/demo/challenges
API-->>Svc: DTO
Svc-->>DS: BaseResponse<DTO>
DS-->>Repo: BaseResponse<DTO>
Repo->>Repo: dto.toModel()
Repo-->>VM: Result<Model>
VM->>VM: UiState.Success 업데이트
Note right of VM: onTodoClick flow
VM->>Repo: patchChallengeRoutinesComplete(routineId)
Repo->>DS: patchChallengeRoutinesComplete(routineId)
DS->>Svc: PATCH /api/demo/challenges/routines/{routineId}/toggle
API-->>Svc: RoutineCompleteDTO
Repo->>VM: Result<RoutineCompleteModel>
VM->>VM: UiState 업데이트
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt (2)
78-83: onCompletedTodayClick 함수 미완성PR 목표에 "다음 날로 넘어가기" API 연결이 포함되어 있으나, 이 함수는 상태 확인 후 아무 작업도 수행하지 않습니다. 현재 구현은 실질적으로 no-op입니다.
"다음 날로 넘어가기" API 호출 구현을 도와드릴까요? Repository에 해당 메서드가 있다면 연결하는 코드를 생성해 드릴 수 있습니다.
64-76: 루틴 완료 토글 API 호출 누락
onTodoClick함수가 로컬 UI 상태만 업데이트하고 서버에 변경사항을 전송하지 않습니다. 저장소 인터페이스에patchChallengeRoutinesComplete메서드가 준비되어 있으므로 이를 호출하여 데이터 영속성을 보장해야 합니다.🐛 API 호출 추가 제안
fun onTodoClick(id: Long) { + viewModelScope.launch { + challengeMissionProgressRepository.patchChallengeRoutinesComplete(id) + .onSuccess { + _uiState.updateSuccess { state -> + state.copy( + routines = state.routines.map { + if (it.routineId == id) { + it.copy(isCompleted = !it.isCompleted) + } else { + it + } + }.toPersistentList() + ) + } + } + .onLogFailure { } + } - _uiState.updateSuccess { state -> - state.copy( - routines = state.routines.map { - if (it.routineId == id) { - it.copy(isCompleted = !it.isCompleted) - } else { - it - } - }.toPersistentList() - ) - } }
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/cherrish/android/data/repositoryimpl/ChallengeMissionProgressRepositoryImpl.kt`:
- Around line 19-25: patchChallengeRoutinesComplete에서
challengeMissionDataSource.patchChallengeRoutinesComplete(...).data!!.toModel()처럼
강제 null 단언(!!)을 사용하고 있어 NPE 위험이 있으니 안전하게 처리하세요: suspendRunCatching 블록 안에서 응답의
data가 null인지 검사하고 null이면 의미있는 예외(예: IllegalStateException 또는 custom exception)를
발생시키거나 Result.failure로 반환하도록 변경하고, data가 존재할 때만 toModel()을 호출하도록 수정하세요; 관련 심볼:
patchChallengeRoutinesComplete,
challengeMissionDataSource.patchChallengeRoutinesComplete,
ChallengeRoutineCompleteResponseModel, suspendRunCatching, toModel.
- Around line 14-17: Replace the unsafe non-null assertion on
challengeMissionDataSource.getChallengeMissions().data in
ChallengeMissionProgressRepositoryImpl.getChallengeMissions() with an explicit
null check: call challengeMissionDataSource.getChallengeMissions(), inspect its
.data, and if null return/throw a descriptive error (e.g., IllegalStateException
or a domain-specific exception with a message like "Challenge missions response
contained null data") or map to a failed Result; otherwise call .toModel() on
the non-null value. This preserves suspendRunCatching behavior while providing a
clear, debuggable error when data is null.
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt`:
- Around line 45-47: The current assignment of cherryType using
CherryType.entries.first { it.step == response.cherryLevel } can throw
NoSuchElementException if no match exists; change this to use firstOrNull and
handle the null by providing a safe default or explicit error handling. Locate
the cherryType assignment in ChallengeMissionProgressViewModel where
response.cherryLevel is matched against CherryType.entries and replace first {
... } with firstOrNull { ... } ?: <choose a sensible default CherryType or
handle with a graceful fallback/logging/exception>, ensuring the code no longer
crashes when no matching step is found.
- Line 60: The empty onLogFailure {} callback leaves the ViewModel stuck in
UiState.Loading on API errors; update the failure handler inside
ChallengeMissionProgressViewModel (the block where onLogFailure is used) to set
the UI state to an error state (e.g., UiState.Error or a domain-specific error
variant) and surface the error message (or map the exception) so the UI can stop
showing loading and display feedback; ensure you also clear or reset any loading
flags and emit the updated state from the same coroutine/flow that currently
emits UiState.Loading.
♻️ Duplicate comments (2)
app/src/main/java/com/cherrish/android/presentation/home/type/CherrishGaugeType.kt (1)
1-1: (중복) 타입 위치 이동으로 레이어 의존성 역전 가능성디자인시스템에서 이 타입을 참조하는 구조라면, 타입 위치 이동이 의존성 역전을 유발합니다. 상위 댓글의 방향(타입을 core 쪽으로 배치) 확인 부탁드립니다.
app/src/main/java/com/cherrish/android/core/designsystem/component/gaugebar/CherrishGaugeBar.kt (1)
24-24: (중복) 디자인시스템의 presentation 의존성 확인 필요상위 댓글과 동일 이슈입니다. 디자인시스템이 presentation 타입에 의존하지 않도록 레이어 방향을 재확인해 주세요.
🧹 Nitpick comments (4)
app/src/main/java/com/cherrish/android/core/designsystem/component/gaugebar/CherrishGaugeColors.kt (1)
5-5: 디자인시스템 → presentation 의존성 역전 우려core 디자인시스템에서 presentation 타입을 직접 참조하면 레이어 방향이 뒤집혀 재사용성과 모듈 분리가 약해집니다.
CherrishGaugeType을 core/designsystem(또는 core/common)으로 두고 presentation에서 참조하는 구조로 되돌리는 편을 권장합니다.app/src/main/java/com/cherrish/android/data/remote/dto/response/ChallengeMissionProgressResponseDto.kt (1)
6-40: LGTM! kotlinx.serialization을 사용한 DTO 정의가 적절합니다.
@Serializable과@SerialName어노테이션이 올바르게 적용되어 있습니다.API 응답의 안정성을 높이려면 일부 필드에 기본값을 추가하는 것을 고려해볼 수 있습니다. 예를 들어
todayRoutines가 null로 오는 경우를 대비할 수 있습니다:♻️ 선택적 개선안
`@SerialName`("todayRoutines") -val todayRoutines: List<ChallengeRoutineResponseDto>, +val todayRoutines: List<ChallengeRoutineResponseDto> = emptyList(),app/src/main/java/com/cherrish/android/presentation/challenge/component/ChallengeMissionTodoSection.kt (1)
74-90: 리스트 아이템에 key 사용 고려현재
Column+forEach로 구현되어 있어 동작에는 문제가 없습니다. 다만 루틴 목록이 자주 변경되거나 항목 수가 많아질 경우,LazyColumn으로 전환하고key를 지정하면 recomposition 최적화에 도움이 될 수 있습니다.app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressScreen.kt (1)
59-66: 함수명 대소문자 불일치Route 컴포저블은
ChallengeMissionProgressRoute로 올바르게 명명되었으나, private screen 컴포저블은 여전히ChallengeMissionprogressScreen(소문자 'p')입니다. 일관성을 위해ChallengeMissionProgressScreen으로 수정하는 것이 좋습니다.♻️ 제안된 수정
`@Composable` -private fun ChallengeMissionprogressScreen( +private fun ChallengeMissionProgressScreen( paddingValues: PaddingValues, uiState: ChallengeMissionProgressUiState,Line 47과 192에서의 호출부도 함께 수정:
- ChallengeMissionprogressScreen( + ChallengeMissionProgressScreen(
| override suspend fun getChallengeMissions(): Result<ChallengeMissionProgressResponseModel> = | ||
| suspendRunCatching { | ||
| challengeMissionDataSource.getChallengeMissions().data!!.toModel() | ||
| } |
There was a problem hiding this comment.
data!! 사용 시 null 처리 개선 필요
data!!를 사용하면 서버가 null 데이터를 반환할 경우 NullPointerException이 발생합니다. suspendRunCatching이 예외를 잡아주지만, 디버깅 시 원인 파악이 어려운 generic NPE가 됩니다.
명시적인 null 체크와 의미 있는 에러 메시지를 사용하는 것이 좋습니다.
🔧 제안된 수정
override suspend fun getChallengeMissions(): Result<ChallengeMissionProgressResponseModel> =
suspendRunCatching {
- challengeMissionDataSource.getChallengeMissions().data!!.toModel()
+ challengeMissionDataSource.getChallengeMissions().data
+ ?.toModel()
+ ?: throw IllegalStateException("Challenge missions data is null")
}🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/data/repositoryimpl/ChallengeMissionProgressRepositoryImpl.kt`
around lines 14 - 17, Replace the unsafe non-null assertion on
challengeMissionDataSource.getChallengeMissions().data in
ChallengeMissionProgressRepositoryImpl.getChallengeMissions() with an explicit
null check: call challengeMissionDataSource.getChallengeMissions(), inspect its
.data, and if null return/throw a descriptive error (e.g., IllegalStateException
or a domain-specific exception with a message like "Challenge missions response
contained null data") or map to a failed Result; otherwise call .toModel() on
the non-null value. This preserves suspendRunCatching behavior while providing a
clear, debuggable error when data is null.
| override suspend fun patchChallengeRoutinesComplete(routineId: Long): | ||
| Result<ChallengeRoutineCompleteResponseModel> = | ||
| suspendRunCatching { | ||
| challengeMissionDataSource.patchChallengeRoutinesComplete( | ||
| routineId = routineId | ||
| ).data!!.toModel() | ||
| } |
There was a problem hiding this comment.
동일한 data!! 패턴 개선 필요
patchChallengeRoutinesComplete에서도 동일한 문제가 있습니다.
🔧 제안된 수정
override suspend fun patchChallengeRoutinesComplete(routineId: Long):
Result<ChallengeRoutineCompleteResponseModel> =
suspendRunCatching {
- challengeMissionDataSource.patchChallengeRoutinesComplete(
- routineId = routineId
- ).data!!.toModel()
+ challengeMissionDataSource.patchChallengeRoutinesComplete(
+ routineId = routineId
+ ).data
+ ?.toModel()
+ ?: throw IllegalStateException("Routine complete response data is null")
}🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/data/repositoryimpl/ChallengeMissionProgressRepositoryImpl.kt`
around lines 19 - 25, patchChallengeRoutinesComplete에서
challengeMissionDataSource.patchChallengeRoutinesComplete(...).data!!.toModel()처럼
강제 null 단언(!!)을 사용하고 있어 NPE 위험이 있으니 안전하게 처리하세요: suspendRunCatching 블록 안에서 응답의
data가 null인지 검사하고 null이면 의미있는 예외(예: IllegalStateException 또는 custom exception)를
발생시키거나 Result.failure로 반환하도록 변경하고, data가 존재할 때만 toModel()을 호출하도록 수정하세요; 관련 심볼:
patchChallengeRoutinesComplete,
challengeMissionDataSource.patchChallengeRoutinesComplete,
ChallengeRoutineCompleteResponseModel, suspendRunCatching, toModel.
| cherryType = CherryType.entries.first { | ||
| it.step == response.cherryLevel | ||
| }, |
There was a problem hiding this comment.
first { } 사용 시 NoSuchElementException 발생 가능
response.cherryLevel이 CherryType.entries의 어떤 step과도 일치하지 않으면 NoSuchElementException이 발생하여 앱이 크래시됩니다. firstOrNull을 사용하고 기본값을 제공하거나 예외 처리를 추가해야 합니다.
🐛 제안된 수정
- cherryType = CherryType.entries.first {
- it.step == response.cherryLevel
- },
+ cherryType = CherryType.entries.firstOrNull {
+ it.step == response.cherryLevel
+ } ?: CherryType.entries.first(),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| cherryType = CherryType.entries.first { | |
| it.step == response.cherryLevel | |
| }, | |
| cherryType = CherryType.entries.firstOrNull { | |
| it.step == response.cherryLevel | |
| } ?: CherryType.entries.first(), |
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt`
around lines 45 - 47, The current assignment of cherryType using
CherryType.entries.first { it.step == response.cherryLevel } can throw
NoSuchElementException if no match exists; change this to use firstOrNull and
handle the null by providing a safe default or explicit error handling. Locate
the cherryType assignment in ChallengeMissionProgressViewModel where
response.cherryLevel is matched against CherryType.entries and replace first {
... } with firstOrNull { ... } ?: <choose a sensible default CherryType or
handle with a graceful fallback/logging/exception>, ensuring the code no longer
crashes when no matching step is found.
| ) | ||
| ) | ||
| } | ||
| }.onLogFailure {} |
There was a problem hiding this comment.
API 실패 시 UI 상태가 Loading에서 멈춤
onLogFailure {}가 빈 람다로 되어 있어서 API 호출 실패 시 UI 상태가 UiState.Loading 상태로 계속 유지됩니다. 사용자에게 에러 피드백이 전달되지 않으며, 로딩 화면이 무한히 표시될 수 있습니다.
🐛 에러 상태 처리 제안
- }.onLogFailure {}
+ }.onLogFailure { throwable ->
+ _uiState.update { UiState.Error(throwable) }
+ }또는 프로젝트에서 사용하는 에러 처리 패턴에 맞게 UiState.Error 또는 별도의 에러 상태로 업데이트하세요.
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt`
at line 60, The empty onLogFailure {} callback leaves the ViewModel stuck in
UiState.Loading on API errors; update the failure handler inside
ChallengeMissionProgressViewModel (the block where onLogFailure is used) to set
the UI state to an error state (e.g., UiState.Error or a domain-specific error
variant) and surface the error message (or map the exception) so the UI can stop
showing loading and display feedback; ensure you also clear or reset any loading
flags and emit the updated state from the same coroutine/flow that currently
emits UiState.Loading.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/cherrish/android/core/designsystem/component/gaugebar/CherrishGaugeStyle.kt`:
- Line 5: CherrishGaugeType currently lives in presentation/home/type causing
presentation layer dependency from core/designsystem; move the CherrishGaugeType
definition into core/designsystem/type (matching where CherrishButtonStyle and
CherrishSelectionChipStyle live) and update imports in core/designsystem
components (CherrishGaugeStyle, CherrishGaugeColors, CherrishGaugeBar) to
reference the new package; ensure package declaration in the moved file matches
core.designsystem.type and run a quick compile to update any other references.
In
`@app/src/main/java/com/cherrish/android/data/remote/service/ChallengeMissionProgressService.kt`:
- Around line 11-22: The service is using demo paths; update
ChallengeMissionProgressService to use the production path pattern by replacing
all "api/demo/..." routes with "api/challenges/..." (i.e., change
`@GET`("api/demo/challenges") to `@GET`("api/challenges"),
`@PATCH`("api/demo/challenges/routines/{routineId}/toggle") to
`@PATCH`("api/challenges/routines/{routineId}/toggle"), and
`@POST`("api/demo/challenges/advance-day") to
`@POST`("api/challenges/advance-day")); alternatively, if this interface is only
for testing, move it out of the production module into a demo/test module to
keep prod services consistent.
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt`:
- Around line 64-79: The onTodoClick currently applies a local toggle
immediately and then calls
challengeMissionProgressRepository.patchChallengeRoutinesComplete without
reconciling the server result; change onTodoClick to perform an optimistic
update but capture the previous routines state before calling
viewModelScope.launch, then call patchChallengeRoutinesComplete; on success
update the _uiState using the server-provided routine data (or re-fetch
routines) to ensure consistency, and on failure restore the captured previous
state (rollback) and log the error (replace the empty onLogFailure block). Use
the existing symbols: onTodoClick, _uiState.updateSuccess,
viewModelScope.launch,
challengeMissionProgressRepository.patchChallengeRoutinesComplete and
onLogFailure to locate and implement the changes.
♻️ Duplicate comments (3)
app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt (3)
45-47:CherryType.entries.first는 매칭 실패 시 크래시 위험이 있습니다.
Line 45-47과 Line 94-96에서 매칭이 없으면NoSuchElementException이 발생합니다.firstOrNull+ 기본값/에러 처리로 안전하게 처리하세요.🐛 안전 처리 예시 (두 군데 모두 적용)
- cherryType = CherryType.entries.first { - it.step == response.cherryLevel - }, + cherryType = CherryType.entries.firstOrNull { + it.step == response.cherryLevel + } ?: CherryType.entries.first(),Also applies to: 94-96
60-60: API 실패 시 Loading에 고정될 수 있습니다.
Line 60의 빈onLogFailure로 실패 상태가 전달되지 않습니다.🐛 실패 처리 예시
- }.onLogFailure {} + }.onLogFailure { throwable -> + _uiState.update { UiState.Error(throwable) } + }
84-109: 하루 넘기기 실패 시 사용자 피드백이 없습니다.
Line 84-109에서 성공만 처리되어 실패가 묵살됩니다. 실패 시 상태 갱신/피드백을 추가하세요.🐛 실패 처리 예시
viewModelScope.launch { - challengeMissionProgressRepository.postChallengeAdvanceDay() + _uiState.update { UiState.Loading } + challengeMissionProgressRepository.postChallengeAdvanceDay() .onSuccess { response -> _uiState.update { UiState.Success( ChallengeMissionProgressUiState( @@ ) } } + .onLogFailure { throwable -> + _uiState.update { UiState.Error(throwable) } + } }
🧹 Nitpick comments (1)
app/src/main/java/com/cherrish/android/data/remote/datasourceimpl/ChallengeMissionProgressDataSourceImpl.kt (1)
12-19: 코드 스타일 일관성 개선을 권장합니다.세 메서드의 구현 스타일이 일관되지 않습니다:
getChallengeMissions(): expression body 사용patchChallengeRoutinesComplete(): block body + 명시적 반환 타입postChallengeAdvanceDay(): expression body 사용가독성과 유지보수성을 위해 일관된 스타일로 통일하는 것을 권장합니다.
♻️ 일관된 expression body 스타일로 통일
class ChallengeMissionProgressDataSourceImpl `@Inject` constructor( private val challengeMissionService: ChallengeMissionProgressService ) : ChallengeMissionProgressDataSource { override suspend fun getChallengeMissions() = challengeMissionService.getChallengeMissions() - override suspend fun patchChallengeRoutinesComplete(routineId: Long): - BaseResponse<ChallengeRoutineCompleteResponseDto> { - return challengeMissionService.patchChallengeRoutinesComplete(routineId = routineId) - } + override suspend fun patchChallengeRoutinesComplete(routineId: Long) = + challengeMissionService.patchChallengeRoutinesComplete(routineId = routineId) override suspend fun postChallengeAdvanceDay() = challengeMissionService.postChallengeAdvanceDay() }
| import androidx.compose.ui.graphics.Color | ||
| import com.cherrish.android.core.designsystem.component.type.CherrishGaugeType | ||
| import com.cherrish.android.core.designsystem.theme.CherrishColors | ||
| import com.cherrish.android.presentation.home.type.CherrishGaugeType |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, explore the repository structure
find . -type f -name "settings.gradle.kts" -o -name "settings.gradle" | head -5Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 95
🏁 Script executed:
# List the main modules in the project
git ls-files | grep -E "^[^/]+/build\.gradle" | head -20Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 94
🏁 Script executed:
# Find the designsystem module structure
fd -t d "designsystem" | head -10Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 131
🏁 Script executed:
# Look at the file in question
cat -n app/src/main/java/com/cherrish/android/core/designsystem/component/gaugebar/CherrishGaugeStyle.ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 1503
🏁 Script executed:
# Find where CherrishGaugeType is defined
rg -n "class CherrishGaugeType|object CherrishGaugeType|enum class CherrishGaugeType" --type ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 100
🏁 Script executed:
# Check the build.gradle for core/designsystem module
find . -path "*/core/designsystem*" -name "build.gradle*" -exec cat {} \;Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 56
🏁 Script executed:
# Check the build.gradle for presentation module
find . -path "*/presentation*" -name "build.gradle*" | grep -v ".gradle" | head -5 | xargs -I {} sh -c "echo '=== {} ===' && cat {}"Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 56
🏁 Script executed:
# Search for CherrishGaugeType definition without type flag
rg -n "class CherrishGaugeType|object CherrishGaugeType|enum class CherrishGaugeType|enum CherrishGaugeType" --max-count 10Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 188
🏁 Script executed:
# Find all files importing or defining CherrishGaugeType
rg -l "CherrishGaugeType" | head -20Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 794
🏁 Script executed:
# Check the package structure under com.cherrish.android
find app/src/main/java/com/cherrish/android -type d -maxdepth 3 | sortRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 3743
🏁 Script executed:
# Look at the presentation home type file directly
find app/src/main -path "*presentation/home/type*" -type f | xargs cat -nRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 2942
🏁 Script executed:
# Check if there's a core.model or similar shared type location
find app/src/main/java/com/cherrish/android/core -type d | sortRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 1352
🏁 Script executed:
# Check what CherrishGaugeType.kt imports to verify if it can be moved to core/designsystem
cat -n app/src/main/java/com/cherrish/android/presentation/home/type/CherrishGaugeType.ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 600
🏁 Script executed:
# Check what other types in core/designsystem/type contain for pattern consistency
find app/src/main/java/com/cherrish/android/core/designsystem/type -type f -name "*.kt" | xargs cat -nRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 402
🏁 Script executed:
# Verify the full context of how CherrishGaugeType is used in CherrishGaugeColors.kt
cat -n app/src/main/java/com/cherrish/android/core/designsystem/component/gaugebar/CherrishGaugeColors.ktRepository: TEAM-Cherrish/Cherrish-Android
Length of output: 1591
CherrishGaugeType을 core/designsystem/type으로 이동하여 계층 의존성 역전 제거
CherrishGaugeType은 순수한 UI 스타일링 정보(단계 번호, 드로어블 리소스)만 포함하는 디자인시스템 타입입니다. 현재 presentation/home/type에 위치하면서 core/designsystem의 CherrishGaugeStyle, CherrishGaugeColors, CherrishGaugeBar가 presentation 레이어를 의존하게 되어 계층 구조를 위반합니다.
core/designsystem/type 디렉토리에 이미 유사한 패턴(CherrishButtonStyle, CherrishSelectionChipStyle)이 존재하므로, CherrishGaugeType을 동일한 위치로 옮기고 해당 import를 업데이트하세요.
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/core/designsystem/component/gaugebar/CherrishGaugeStyle.kt`
at line 5, CherrishGaugeType currently lives in presentation/home/type causing
presentation layer dependency from core/designsystem; move the CherrishGaugeType
definition into core/designsystem/type (matching where CherrishButtonStyle and
CherrishSelectionChipStyle live) and update imports in core/designsystem
components (CherrishGaugeStyle, CherrishGaugeColors, CherrishGaugeBar) to
reference the new package; ensure package declaration in the moved file matches
core.designsystem.type and run a quick compile to update any other references.
| interface ChallengeMissionProgressService { | ||
| @GET("api/demo/challenges") | ||
| suspend fun getChallengeMissions(): BaseResponse<ChallengeMissionProgressResponseDto> | ||
|
|
||
| @PATCH("api/demo/challenges/routines/{routineId}/toggle") | ||
| suspend fun patchChallengeRoutinesComplete( | ||
| @Path("routineId") routineId: Long | ||
| ): BaseResponse<ChallengeRoutineCompleteResponseDto> | ||
|
|
||
| @POST("api/demo/challenges/advance-day") | ||
| suspend fun postChallengeAdvanceDay(): BaseResponse<ChallengeMissionProgressResponseDto> | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "api/demo" --type kotlin -A 1 -B 1Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 1365
🏁 Script executed:
fd -e kt "Service.kt$" app/src/main/java/com/cherrish/android/data/remote/service/ | head -5Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 481
🏁 Script executed:
cat -n app/src/main/java/com/cherrish/android/data/remote/service/CalendarService.kt | head -20Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 954
🏁 Script executed:
cat -n app/src/main/java/com/cherrish/android/data/remote/service/HomeService.kt | head -20Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 466
🏁 Script executed:
cat -n app/src/main/java/com/cherrish/android/data/remote/service/DummyService.kt | head -20Repository: TEAM-Cherrish/Cherrish-Android
Length of output: 390
API 엔드포인트 경로를 프로덕션 패턴에 맞게 수정해야 합니다.
Retrofit 서비스 인터페이스의 구조와 어노테이션은 올바르게 구현되었으나, 다른 모든 서비스 파일들과 달리 이 서비스만 api/demo/ 경로를 사용하고 있습니다.
다른 프로덕션 서비스들은 다음과 같은 패턴을 따릅니다:
- CalendarService:
api/calendar/... - HomeService:
api/main-dashboard
ChallengeMissionProgressService의 모든 엔드포인트도 일관성 있게 api/challenges/... 패턴으로 수정하거나, 이것이 데모/테스트 코드라면 프로덕션 코드베이스에서 분리해야 합니다.
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/data/remote/service/ChallengeMissionProgressService.kt`
around lines 11 - 22, The service is using demo paths; update
ChallengeMissionProgressService to use the production path pattern by replacing
all "api/demo/..." routes with "api/challenges/..." (i.e., change
`@GET`("api/demo/challenges") to `@GET`("api/challenges"),
`@PATCH`("api/demo/challenges/routines/{routineId}/toggle") to
`@PATCH`("api/challenges/routines/{routineId}/toggle"), and
`@POST`("api/demo/challenges/advance-day") to
`@POST`("api/challenges/advance-day")); alternatively, if this interface is only
for testing, move it out of the production module into a demo/test module to
keep prod services consistent.
| fun onTodoClick(id: Long) { | ||
| _uiState.updateSuccess { state -> | ||
| state.copy( | ||
| routines = state.routines.map { | ||
| if (it.id == id) { | ||
| it.copy(isCompleted = !it.isCompleted) | ||
| routines = state.routines.map { routine -> | ||
| if (routine.routineId == id) { | ||
| routine.copy(isCompleted = !routine.isCompleted) | ||
| } else { | ||
| it | ||
| routine | ||
| } | ||
| }.toPersistentList() | ||
| ) | ||
| } | ||
| viewModelScope.launch { | ||
| challengeMissionProgressRepository | ||
| .patchChallengeRoutinesComplete(routineId = id) | ||
| .onLogFailure { } |
There was a problem hiding this comment.
루틴 토글이 서버 상태와 불일치할 수 있습니다.
Line 64-79에서 로컬 토글을 먼저 적용하고 서버 응답을 반영하지 않아 불일치 위험이 있습니다. 성공 응답 기반 갱신(또는 재조회)으로 동기화하세요. 낙관적 업데이트를 유지하려면 실패 시 롤백도 필요합니다.
🔧 동기화 중심 예시 (성공 응답 기반 갱신)
- _uiState.updateSuccess { state ->
- state.copy(
- routines = state.routines.map { routine ->
- if (routine.routineId == id) {
- routine.copy(isCompleted = !routine.isCompleted)
- } else {
- routine
- }
- }.toPersistentList()
- )
- }
- viewModelScope.launch {
- challengeMissionProgressRepository
- .patchChallengeRoutinesComplete(routineId = id)
- .onLogFailure { }
- }
+ viewModelScope.launch {
+ challengeMissionProgressRepository
+ .patchChallengeRoutinesComplete(routineId = id)
+ .onSuccess {
+ _uiState.updateSuccess { state ->
+ state.copy(
+ routines = state.routines.map { routine ->
+ if (routine.routineId == id) {
+ routine.copy(isCompleted = !routine.isCompleted)
+ } else {
+ routine
+ }
+ }.toPersistentList()
+ )
+ }
+ }
+ }🤖 Prompt for AI Agents
In
`@app/src/main/java/com/cherrish/android/presentation/challenge/missionprogress/ChallengeMissionProgressViewModel.kt`
around lines 64 - 79, The onTodoClick currently applies a local toggle
immediately and then calls
challengeMissionProgressRepository.patchChallengeRoutinesComplete without
reconciling the server result; change onTodoClick to perform an optimistic
update but capture the previous routines state before calling
viewModelScope.launch, then call patchChallengeRoutinesComplete; on success
update the _uiState using the server-provided routine data (or re-fetch
routines) to ensure consistency, and on failure restore the captured previous
state (rollback) and log the error (replace the empty onLogFailure block). Use
the existing symbols: onTodoClick, _uiState.updateSuccess,
viewModelScope.launch,
challengeMissionProgressRepository.patchChallengeRoutinesComplete and
onLogFailure to locate and implement the changes.
Related issue 🛠
Work Description ✏️
챌린지 미션 진행 api 연결
Screenshot 📸
Uncompleted Tasks 😅
To Reviewers 📢
Summary by CodeRabbit
새로운 기능
리팩토링
버그 수정
✏️ Tip: You can customize this high-level summary in your review settings.