-
Notifications
You must be signed in to change notification settings - Fork 0
[Feature/#40] setting 화면 로직 구현 및 api를 연동합니다. #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough사용자 프로필 조회, 로그아웃·회원탈퇴 API와 SeniorSetting 화면을 추가하고 네비게이션에 OpenUrl 이벤트/브라우저 열기 구현을 도입했으며, 관련 DI·서비스·리포지토리 바인딩과 UI 컴포넌트 변경을 포함합니다. (약 50단어 이내) Changes
Sequence Diagram(s)sequenceDiagram
participant User as 사용자
participant UI as SeniorSettingScreen
participant VM as SeniorSettingViewModel
participant Nav as NavigatorImpl
participant Ev as ObserveNavigationEvents
participant Browser as 브라우저
User->>UI: 정책 버튼 클릭
UI->>VM: openPolicyUrl()
VM->>Nav: openUrl(POLICY_URL)
Nav->>Ev: emit OpenUrl(url)
Ev->>Browser: openUrlInBrowser(context, url)
Browser->>Browser: CustomTabsIntent 시도
alt 실패
Browser->>Browser: ACTION_VIEW 폴백
end
sequenceDiagram
participant User as 사용자
participant UI as SeniorSettingScreen
participant VM as SeniorSettingViewModel
participant LO as LogOutUseCase
participant Repo as AuthRepositoryImpl
participant Svc as AuthService
participant Nav as Navigator
User->>UI: 로그아웃 확인
UI->>VM: logOut()
VM->>LO: invoke()
LO->>Repo: logOut()
Repo->>Svc: logOut(AuthTokenRequest)
alt 성공
Svc-->>Repo: success
Repo-->>LO: success
LO-->>VM: success
VM->>Nav: navigate(AuthLanding, clearBackStack)
else 실패
Svc-->>Repo: failure
Repo-->>LO: failure
LO-->>VM: failure
VM->>UI: 다이얼로그 숨김 및 로깅
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45–60 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (7)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/dialog/MaAlertDialog.kt (1)
80-98: Dismiss 버튼 색상을 재사용 가능하도록 추출하는 것을 고려해 보세요.인라인으로 정의된
MaButtonColors를 companion object나 기본값 객체로 추출하면 다른 다이얼로그에서도 재사용할 수 있고 유지보수가 용이해집니다.companion object { @Composable fun dismissButtonColors() = MaButtonColors( defaultBackground = MoaTheme.colors.coolGray98, pressedBackground = MoaTheme.colors.coolGray96, disabledBackground = MoaTheme.colors.coolGray98, defaultContentColor = MoaTheme.colors.coolGray50, pressedContentColor = MoaTheme.colors.coolGray50, disabledContentColor = MoaTheme.colors.coolGray50 ) }또는
MaButtonDefaults에 secondary 스타일 색상으로 추가하는 것도 좋은 방법입니다.feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/component/OptionItem.kt (1)
32-40: 클릭 가능 영역 확인 권장현재
padding이clickable수정자 뒤에 적용되어 있어, 패딩 영역은 클릭할 수 없습니다. 만약 더 넓은 클릭 영역을 제공하려면padding을clickable앞으로 이동하는 것을 고려하세요.현재 구조를 유지하려면:
.fillMaxWidth() .clickable(...) .padding(start = 20.dp)더 넓은 클릭 영역을 원하면:
.fillMaxWidth() .padding(start = 20.dp) .clickable(...)app/src/main/kotlin/com/moa/app/navigation/OpenUrlInBrowser.kt (1)
9-22: LGTM! CustomTabs 우선 사용과 폴백 전략이 적절합니다.CustomTabs를 먼저 시도하고 실패 시 표준 브라우저 인텐트로 폴백하는 방식이 좋습니다.
선택적 개선사항: 잘못된 URL 형식이 전달될 경우를 대비해 URL 유효성 검증을 고려해볼 수 있습니다 (예:
url.isBlank()체크 또는 URL 스킴 검증).app/src/main/kotlin/com/moa/app/navigation/NavigatorImpl.kt (1)
12-42:openUrl에서도 send 실패 시 로깅을 맞춰두는 게 좋습니다
navigate,navigateBack에서는trySend(...).onFailure { ... }로 실패 로그를 남기는데,openUrl은 실패 시 로그가 없어 디버깅 시 원인 추적이 어렵습니다. 아래처럼 동일하게onFailure를 붙여 두면 일관성이 좋아집니다.override fun openUrl(url: String) { if (url.startsWith(HTTP_PREFIX) || url.startsWith(HTTPS_PREFIX)) { _events.trySend(NavigationEvent.OpenUrl(url)) .onFailure { Timber.tag(TAG).e(it, "Failed to send navigation event") } } else { Timber.tag(TAG).w("Invalid URL format: $url") } }feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/component/OtherSection.kt (1)
28-103: 섹션별 클릭 콜백 분리 좋습니다 (약간의 padding 정리 제안)
onCustomerCenterClick,onPolicyClick,onLogOutClick,onWithdrawalClick각각을OptionItem/Row에 직접 물려준 구조가 명확해서SeniorSettingScreen쪽에서 의도가 잘 드러납니다."기타"타이틀의modifier는 현재padding(vertical = 10.dp).padding(start = 20.dp)인데, 아래처럼 한 번에 적어 주면 조금 더 읽기 편할 것 같습니다.modifier = Modifier.padding(start = 20.dp, top = 10.dp, bottom = 10.dp)기능 영향은 없으니 선택 사항입니다.
feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingScreen.kt (1)
27-127: 다이얼로그/섹션 콜백 연동은 적절하며, 버전/복사 동작은 후속 개선 여지가 있습니다
showLogoutDialog/showWithdrawalDialog플래그로MaAlertDialog를 제어하고, 확인/취소 콜백을SeniorSettingViewModel메서드에 직접 연결한 구조가 명확하고 유지보수하기 좋아 보입니다.OtherSection에도viewModel콜백들을 그대로 넘겨주어 고객센터/정책/로그아웃/탈퇴 플로우가 한 눈에 들어옵니다.다만 두 가지는 추후 개선을 고려해볼 수 있습니다.
회원코드 복사 버튼 (
onCopyClick = {})
현재ProfileSection의"복사"버튼이 동작하지 않으므로, 실제로 사용자가 복사 기능을 기대할 수 있는 UI라면 뷰모델 메서드(or 헬퍼)를 넘겨주거나, 추후 구현 계획이 아니라면 TODO 코멘트라도 남겨 두는 편이 좋겠습니다.앱 버전 정보 하드코딩 (
"v.1.0.0")
버전 문자열을 직접 하드코딩하면 배포 버전이 올라갈 때마다 수동 수정이 필요합니다.BuildConfig.VERSION_NAME등의 값으로부터 가져오도록 변경하면 유지보수 비용을 줄일 수 있습니다.feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingViewModel.kt (1)
52-65: 에러 상태를 UI에 노출하는 것을 고려해보세요.현재 API 호출 실패 시 로그만 남기고 있어 사용자에게 피드백이 제공되지 않습니다. 향후 개선 시
SeniorSettingUiState에 에러 상태를 추가하여 사용자에게 실패 알림(예: 스낵바, 토스트)을 제공하는 것을 고려해보세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (37)
app/build.gradle.kts(1 hunks)app/src/main/kotlin/com/moa/app/main/MainActivity.kt(2 hunks)app/src/main/kotlin/com/moa/app/navigation/NavigatorImpl.kt(1 hunks)app/src/main/kotlin/com/moa/app/navigation/ObserveNavigationEvents.kt(3 hunks)app/src/main/kotlin/com/moa/app/navigation/OpenUrlInBrowser.kt(1 hunks)core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/dialog/MaAlertDialog.kt(1 hunks)core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt(1 hunks)core/navigation/src/main/java/com/moa/app/navigation/NavigationEvent.kt(1 hunks)core/navigation/src/main/java/com/moa/app/navigation/Navigator.kt(1 hunks)data/src/main/kotlin/com/moa/app/data/auth/datasource/AuthDataSource.kt(1 hunks)data/src/main/kotlin/com/moa/app/data/auth/datasourceImpl/AuthDataSourceImpl.kt(2 hunks)data/src/main/kotlin/com/moa/app/data/auth/model/request/AuthTokenRequest.kt(1 hunks)data/src/main/kotlin/com/moa/app/data/auth/repositoryImpl/AuthRepositoryImpl.kt(3 hunks)data/src/main/kotlin/com/moa/app/data/auth/service/AuthService.kt(2 hunks)data/src/main/kotlin/com/moa/app/data/di/DataSourceModule.kt(2 hunks)data/src/main/kotlin/com/moa/app/data/di/RepositoryModule.kt(2 hunks)data/src/main/kotlin/com/moa/app/data/di/ServiceModule.kt(2 hunks)data/src/main/kotlin/com/moa/app/data/user/datasource/UserDataSource.kt(1 hunks)data/src/main/kotlin/com/moa/app/data/user/datasourceImpl/UserDataSourceImpl.kt(1 hunks)data/src/main/kotlin/com/moa/app/data/user/model/response/UserProfileResponse.kt(1 hunks)data/src/main/kotlin/com/moa/app/data/user/repositoryImpl/UserRepositoryImpl.kt(1 hunks)data/src/main/kotlin/com/moa/app/data/user/service/UserService.kt(1 hunks)domain/src/main/kotlin/com/moa/app/domain/auth/model/Gender.kt(1 hunks)domain/src/main/kotlin/com/moa/app/domain/auth/repository/AuthRepository.kt(1 hunks)domain/src/main/kotlin/com/moa/app/domain/auth/usecase/LogOutUseCase.kt(1 hunks)domain/src/main/kotlin/com/moa/app/domain/auth/usecase/WithdrawalUseCase.kt(1 hunks)domain/src/main/kotlin/com/moa/app/domain/user/repository/UserRepository.kt(1 hunks)domain/src/main/kotlin/com/moa/app/domain/user/usecase/FetchUserProfileUseCase.kt(1 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/home/SeniorHomeScreen.kt(3 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/home/SeniorHomeViewModel.kt(1 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingScreen.kt(1 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingViewModel.kt(1 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SettingScreen.kt(0 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/component/OptionItem.kt(1 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/component/OtherSection.kt(3 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/model/SeniorSettingUiState.kt(1 hunks)gradle/libs.versions.toml(2 hunks)
💤 Files with no reviewable changes (1)
- feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SettingScreen.kt
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-21T09:07:31.486Z
Learnt from: wjdrjs00
Repo: team-memory-care/MoA-Android PR: 31
File: core/network/src/main/kotlin/com/moa/app/network/adapter/NetworkResultCall.kt:36-37
Timestamp: 2025-11-21T09:07:31.486Z
Learning: The MoA-Android project exclusively uses Retrofit suspend functions for network calls in the core/network module. The NetworkResultCall.execute() method intentionally throws UnsupportedOperationException because synchronous execution is not needed.
Applied to files:
data/src/main/kotlin/com/moa/app/data/user/service/UserService.kt
🧬 Code graph analysis (4)
app/src/main/kotlin/com/moa/app/navigation/ObserveNavigationEvents.kt (1)
app/src/main/kotlin/com/moa/app/navigation/OpenUrlInBrowser.kt (1)
openUrlInBrowser(9-22)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/component/OtherSection.kt (1)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/component/OptionItem.kt (1)
OptionItem(25-57)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingViewModel.kt (1)
data/src/main/kotlin/com/moa/app/data/user/service/UserService.kt (2)
fetchUserProfile(8-15)fetchUserProfile(10-11)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/dialog/MaAlertDialog.kt (1)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/core/button/MaButton.kt (1)
MaButton(30-68)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Run ktlint
- GitHub Check: Run Unit Tests
🔇 Additional comments (32)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/dialog/MaAlertDialog.kt (2)
26-37: 함수 시그니처가 잘 설계되었습니다.Compose 컨벤션을 잘 따르고 있으며,
modifier를 두 번째 파라미터로 배치하고 선택적 파라미터들에 적절한 기본값을 제공하고 있습니다.ExperimentalMaterial3Api옵트인도BasicAlertDialog사용에 적합합니다.
116-147: Preview 구성이 적절합니다.
content유무에 따른 두 가지 케이스를 모두 커버하고 있어 다이얼로그의 다양한 사용 상황을 확인할 수 있습니다.app/build.gradle.kts (1)
28-28: LGTM!외부 URL을 Chrome Custom Tabs로 열기 위한
androidx.browser의존성이 올바르게 추가되었습니다.core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt (1)
43-44: LGTM!새로운
SeniorSetting라우트가 기존 패턴을 따라 올바르게 추가되었습니다.core/navigation/src/main/java/com/moa/app/navigation/Navigator.kt (1)
14-14: LGTM!외부 URL을 열기 위한
openUrl메서드가 올바르게 추가되었습니다. AI 요약에 따르면 NavigatorImpl에서 http/https URL 검증이 구현되어 있어 보안이 고려되었습니다.core/navigation/src/main/java/com/moa/app/navigation/NavigationEvent.kt (1)
10-10: LGTM!
OpenUrl네비게이션 이벤트가 기존 이벤트 패턴을 따라 올바르게 추가되었습니다.domain/src/main/kotlin/com/moa/app/domain/auth/repository/AuthRepository.kt (1)
12-12: LGTM! All verification checks passed.The
logOut()method has been correctly implemented with consistent signatures across all layers:
- Interface defines:
suspend fun logOut(): Result<Unit>- Implementation properly retrieves tokens and delegates to AuthDataSource
- Usage in LogOutUseCase correctly calls
authRepository.logOut()and returnsResult<Unit>- Return type and suspend modifier are consistent throughout the call chain
gradle/libs.versions.toml (1)
22-22: Version 1.9.0 is the latest stable release and contains no known security vulnerabilities.The
androidx.browserlibrary version 1.9.0 is current as of November 2025 (released July 30, 2025) and is the latest stable version available. No CVEs or security advisories have been published for this version. No action is required.data/src/main/kotlin/com/moa/app/data/user/model/response/UserProfileResponse.kt (1)
6-17: Review comment appears to be based on unverified assumptions about API behaviorThe codebase shows
parentCodeas consistently non-nullable across all response models (UserProfileResponseandParentRoleResponse). No evidence was found of:
- API documentation specifying null handling for Senior role users
- Custom deserializers allowing null values
- Role-based conditional logic
- Test data showing API responses for different roles
The asymmetric nullable design (
parentUserIdis nullableLong?whileparentCodeis non-nullableString) appears intentional, but lacks documentation. With strict kotlinx.serialization, a nullparentCodefrom the API would cause deserialization failure—suggesting either the API always sends a value, or there's an undetected production issue.The concern about role-based nullable handling is reasonable from a domain perspective (Senior users may have no parents), but cannot be confirmed from the codebase alone.
app/src/main/kotlin/com/moa/app/main/MainActivity.kt (2)
34-34: 설정 화면 import가 올바르게 추가되었습니다.새로운 SeniorSettingScreen을 위한 import가 적절하게 추가되었습니다.
80-80: 설정 화면 라우트가 올바르게 등록되었습니다.AppRoute.SeniorSetting 라우트가 NavHost에 적절하게 추가되어 SeniorSettingScreen과 연결됩니다.
data/src/main/kotlin/com/moa/app/data/di/ServiceModule.kt (1)
27-30: UserService DI 제공자가 올바르게 구현되었습니다.UserService를 위한 DI 제공 메서드가 기존 패턴을 따라 적절하게 추가되었습니다. Singleton 스코프도 Retrofit 서비스에 적합합니다.
domain/src/main/kotlin/com/moa/app/domain/auth/model/Gender.kt (1)
9-17: API 응답의 Gender 값 검증을 확인하세요.
fromString메서드가 알 수 없는 값에 대해IllegalArgumentException을 throw합니다. API가 예상치 못한 값을 반환하거나 향후 새로운 성별 옵션(예: "OTHER", "UNKNOWN")이 추가될 경우 앱이 크래시될 수 있습니다. API 계약이 "MALE"과 "FEMALE"만 보장하는지 확인하고, 필요시 더 안전한 폴백 처리를 고려하세요.feature/senior/src/main/kotlin/com/moa/app/feature/senior/home/SeniorHomeViewModel.kt (1)
23-25: 설정 화면 네비게이션이 올바르게 업데이트되었습니다.메서드명이
navigateToSetting()으로 적절하게 변경되었고, 새로운AppRoute.SeniorSetting라우트로 정확하게 네비게이션됩니다.data/src/main/kotlin/com/moa/app/data/di/RepositoryModule.kt (1)
21-23: UserRepository DI 바인딩이 올바르게 추가되었습니다.UserRepository 인터페이스를 UserRepositoryImpl에 바인딩하는 설정이 기존 패턴을 따라 적절하게 구현되었습니다.
data/src/main/kotlin/com/moa/app/data/auth/datasourceImpl/AuthDataSourceImpl.kt (1)
44-47: 로그아웃 메서드가 올바르게 구현되었습니다.제공된 토큰으로
AuthTokenRequest를 생성하고authService.logOut에 위임하는 구현이 적절합니다. 기존 패턴을 잘 따르고 있습니다.data/src/main/kotlin/com/moa/app/data/auth/datasource/AuthDataSource.kt (1)
17-17: 로그아웃 메서드가 인터페이스에 올바르게 추가되었습니다.
logOut메서드 시그니처가AuthDataSource인터페이스에 적절하게 추가되어 구현체와 일치합니다.app/src/main/kotlin/com/moa/app/navigation/ObserveNavigationEvents.kt (2)
19-19: Context 가져오기가 적절하게 추가되었습니다.URL을 브라우저에서 열기 위해
LocalContext.current를 사용하는 것이 적절합니다.
28-28: I'll verify the URL validation concerns mentioned in the review comment. Let me start by searching for the relevant code.
<function_calls>
#!/bin/bashSearch for NavigationEvent definition and OpenUrl event structure
rg -n "sealed class NavigationEvent|data class.*OpenUrl|object.*OpenUrl" --type=kt -A 5 -B 2
</function_calls>
#!/bin/bashFind the ObserveNavigationEvents.kt file and read its content
fd "ObserveNavigationEvents.kt" --type=f -x cat -n {}
</function_calls>
#!/bin/bashSearch for openUrlInBrowser function implementation
rg -n "fun openUrlInBrowser|openUrlInBrowser\s*(" --type=kt -A 10 -B 2
</function_calls>
#!/bin/bashSearch for all places where NavigationEvent.OpenUrl is created/emitted
rg -n "NavigationEvent.OpenUrl|OpenUrl(" --type=kt -B 3 -A 2
</function_calls>data/src/main/kotlin/com/moa/app/data/di/DataSourceModule.kt (1)
21-24: LGTM! DI 바인딩이 기존 패턴과 일관성 있게 추가되었습니다.
@Binds와@Singleton어노테이션 사용이 기존AuthDataSource바인딩과 동일한 패턴을 따르고 있어 코드 일관성이 유지됩니다.data/src/main/kotlin/com/moa/app/data/auth/model/request/AuthTokenRequest.kt (1)
6-12: LGTM! 데이터 클래스 구조가 적절합니다.
@Serializable및@SerialName사용이 올바릅니다.참고: 필드명과 JSON 키가 동일한 경우
@SerialName은 선택사항입니다. 프로젝트의 일관성을 위해 명시적으로 사용하는 것도 좋은 접근입니다.domain/src/main/kotlin/com/moa/app/domain/auth/usecase/WithdrawalUseCase.kt (1)
1-12: LGTM! Use case 구현이 클린 아키텍처 패턴을 잘 따르고 있습니다.단일 책임 원칙을 준수하며
UserRepository에 대한 위임이 깔끔합니다.참고: 이 use case가
auth.usecase패키지에 있지만UserRepository를 사용합니다. 회원탈퇴가 인증과 관련된 작업이라 의도적인 배치일 수 있으나, 패키지 구조의 일관성 측면에서user.usecase패키지도 고려해볼 수 있습니다.domain/src/main/kotlin/com/moa/app/domain/auth/usecase/LogOutUseCase.kt (1)
6-12: LGTM! 로그아웃 use case가 적절하게 구현되었습니다.
AuthRepository를 주입받아logOut()을 위임하는 패턴이 클린 아키텍처 원칙에 부합하며, 패키지 구조도 적절합니다.feature/senior/src/main/kotlin/com/moa/app/feature/senior/home/SeniorHomeScreen.kt (1)
41-266: 설정 진입 콜백 연동 잘 되어 있습니다
SeniorHomeScreen에서viewModel::navigateToSetting을 내려주고, 상단 설정 아이콘과 프리뷰까지 모두onSettingClick으로 일관되게 연결되어 있어 추후 리팩터링 시에도 추적이 쉽겠습니다. 추가로 고려할 사항은 없어 보입니다.data/src/main/kotlin/com/moa/app/data/auth/service/AuthService.kt (1)
3-45: 로그아웃 API 시그니처가 기존 패턴과 잘 맞습니다
AuthTokenRequest를 바디로 받는logOut메서드를NetworkResult<Unit>으로 선언한 부분이 다른 메서드들과 동일한 패턴을 따르고 있어,AuthDataSource/레포지토리 계층에서 사용하기에도 자연스러워 보입니다. 서버 스펙만 맞다면 그대로 사용해도 무방해 보입니다.feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/model/SeniorSettingUiState.kt (1)
1-17: UI 상태 모델이 현재 요구사항에 잘 맞습니다
userName,userCode, 두 개의 다이얼로그 플래그로만 구성된SeniorSettingUiState와INIT값 정의가 설정 화면에서 필요한 최소 상태를 잘 캡처하고 있습니다. 프리뷰/초기 상태에서 재사용하기에도 좋아 보입니다.data/src/main/kotlin/com/moa/app/data/user/datasource/UserDataSource.kt (1)
1-8: UserDataSource 추상화가 간결하고 역할이 명확합니다
getUserProfile,withdrawal두 메서드로 사용자 관련 기능만 노출하는 인터페이스 구조가 직관적이고, 상위 레이어에서 테스트/모킹하기도 좋겠습니다. 현재 요구사항 범위에서는 추가 수정 없이도 충분해 보입니다.data/src/main/kotlin/com/moa/app/data/user/service/UserService.kt (1)
1-15: UserService 엔드포인트 설계가 직관적입니다
GET /api/v1/users/me로 프로필을 가져오고,DELETE /api/v1/users/withdraw로 회원탈퇴를 처리하는 구조가 REST 관점에서도 의미가 잘 맞습니다.
NetworkResult를 사용한 반환 타입도 기존 네트워크 계층 패턴과 일관되어 있어, 데이터소스/레포지토리 단 연계에 문제 없어 보입니다.data/src/main/kotlin/com/moa/app/data/user/datasourceImpl/UserDataSourceImpl.kt (1)
9-21: LGTM!DataSource 패턴을 잘 따르고 있으며,
toResult확장 함수를 사용하여 NetworkResult를 Result로 변환하는 구현이 깔끔합니다.domain/src/main/kotlin/com/moa/app/domain/user/repository/UserRepository.kt (1)
5-8: LGTM!도메인 레이어에 적절하게 정의된 인터페이스입니다. 데이터 모델 대신 도메인 모델(
UserProfile)을 사용하여 관심사 분리가 잘 되어 있습니다.data/src/main/kotlin/com/moa/app/data/user/repositoryImpl/UserRepositoryImpl.kt (1)
13-24: LGTM!
mapCatching을 사용하여 매핑 중 발생할 수 있는 예외를 적절히 처리하고 있습니다. 데이터 모델에서 도메인 모델로의 변환 로직이 명확합니다.domain/src/main/kotlin/com/moa/app/domain/user/usecase/FetchUserProfileUseCase.kt (1)
7-13: LGTM!단일 책임 원칙을 잘 따르는 간결한 Use Case 구현입니다.
data/src/main/kotlin/com/moa/app/data/auth/repositoryImpl/AuthRepositoryImpl.kt
Show resolved
Hide resolved
feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingViewModel.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingViewModel.kt (2)
67-93: 로딩 상태 추가를 권장합니다.
logOut()과withdrawal()함수 모두 비동기 작업 중 로딩 상태를 표시하지 않습니다. 네트워크 요청이 처리되는 동안 사용자에게 시각적 피드백을 제공하면 사용자 경험이 향상됩니다.
SeniorSettingUiState에isLoading또는 개별isLoggingOut/isWithdrawing플래그를 추가하여 UI에서 로딩 인디케이터를 표시할 수 있도록 하는 것을 고려해보세요.fun logOut() { viewModelScope.launch { + _uiState.update { it.copy(isLoggingOut = true) } logOutUseCase().fold( onSuccess = { navigateToClear() }, onFailure = { Log.e("logOut", "logOut: $it") + _uiState.update { it.copy(isLoggingOut = false) } hideLogoutDialog() }, ) } }
112-115: URL을 설정 파일로 관리하는 것을 고려해보세요.정책 및 고객센터 URL이 하드코딩되어 있습니다. 앱 재배포 없이 URL을 업데이트해야 하는 경우를 대비하여 다음을 고려해보세요:
- Firebase Remote Config와 같은 원격 설정 시스템 사용
- BuildConfig나 별도의 상수 파일로 중앙화
현재 구현도 동작하지만, 향후 유지보수성을 위한 선택적 개선사항입니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
data/src/main/kotlin/com/moa/app/data/auth/repositoryImpl/AuthRepositoryImpl.kt(3 hunks)data/src/main/kotlin/com/moa/app/data/user/repositoryImpl/UserRepositoryImpl.kt(1 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingViewModel.kt(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- data/src/main/kotlin/com/moa/app/data/user/repositoryImpl/UserRepositoryImpl.kt
🧰 Additional context used
🧬 Code graph analysis (1)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingViewModel.kt (1)
data/src/main/kotlin/com/moa/app/data/user/service/UserService.kt (2)
fetchUserProfile(8-15)fetchUserProfile(10-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Run Unit Tests
🔇 Additional comments (2)
data/src/main/kotlin/com/moa/app/data/auth/repositoryImpl/AuthRepositoryImpl.kt (1)
68-76: 로그아웃 구현이 올바르게 작성되었습니다.이전 리뷰에서 지적된 토큰 삭제 누락 문제가 해결되었습니다.
authDataSource.logOut()성공 후tokenManager.clearTokens()를 호출하여 로컬 토큰을 안전하게 제거하고 있습니다. 서버 로그아웃이 실패할 경우 토큰을 유지하여 재시도가 가능하도록 한 설계도 합리적입니다.feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingViewModel.kt (1)
81-93: 이전 리뷰 이슈가 수정되었습니다.이전 리뷰에서 지적된
onFailure블록의 다이얼로그 처리 오류가 올바르게 수정되었습니다. 89번 라인에서hideWithdrawalDialog()를 호출하여 회원탈퇴 실패 시 올바른 다이얼로그를 닫습니다.
Related issue 🛠
Work Description ✏️
androidx.browser라이브러리 추가openUri메소드 추가Screenshot 📸
Uncompleted Tasks 😅
Summary by CodeRabbit
릴리스 노트
새로운 기능
향상된 기능
✏️ Tip: You can customize this high-level summary in your review settings.