Skip to content

Conversation

@wjdrjs00
Copy link
Collaborator

@wjdrjs00 wjdrjs00 commented Nov 27, 2025

Related issue 🛠

Work Description ✏️

  • 프로필 조회 api 연동
  • 로그아웃/회원탈퇴 api 연동
  • 문의/ 정책 페이지 웹 연결을 위한 androidx.browser 라이브러리 추가
    • 네비게이션 이벤트 openUri 메소드 추가

Screenshot 📸

  • N/A

Uncompleted Tasks 😅

  • 없음

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 시니어 설정 화면 추가 — 프로필, 버전 정보, 설정 항목 표시
    • 로그아웃 및 계정 탈퇴 흐름 추가(확인 다이얼로그 포함)
    • 외부 링크(정책·고객센터) 열기 지원
    • 재사용 가능한 알림 대화상자 컴포넌트 추가
  • 향상된 기능

    • 네비게이션 확장: 외부 URL 열기 및 새로운 라우트(SeniorSetting) 추가
    • 사용자 프로필 조회 API 및 저장소/유스케이스 도입

✏️ Tip: You can customize this high-level summary in your review settings.

@wjdrjs00 wjdrjs00 self-assigned this Nov 27, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 27, 2025

Walkthrough

사용자 프로필 조회, 로그아웃·회원탈퇴 API와 SeniorSetting 화면을 추가하고 네비게이션에 OpenUrl 이벤트/브라우저 열기 구현을 도입했으며, 관련 DI·서비스·리포지토리 바인딩과 UI 컴포넌트 변경을 포함합니다. (약 50단어 이내)

Changes

코호트 / 파일(s) 변경 요약
네비게이션 계약 확장
core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt, core/navigation/src/main/java/com/moa/app/navigation/NavigationEvent.kt, core/navigation/src/main/java/com/moa/app/navigation/Navigator.kt
AppRoute.SeniorSetting 추가, NavigationEvent.OpenUrl(url) 추가, Navigator.openUrl(url: String) 인터페이스 메서드 추가
네비게이션 구현 및 브라우저 처리
app/src/main/kotlin/com/moa/app/navigation/NavigatorImpl.kt, app/src/main/kotlin/com/moa/app/navigation/ObserveNavigationEvents.kt, app/src/main/kotlin/com/moa/app/navigation/OpenUrlInBrowser.kt
NavigatorImpl.openUrl 추가(단순 URL 검증 + OpenUrl 이벤트), 이벤트 관찰부에 OpenUrl 처리 추가, CustomTabs + ACTION_VIEW 폴백으로 URL 열기 구현
앱 라우팅 등록
app/src/main/kotlin/com/moa/app/main/MainActivity.kt
NavHost에 AppRoute.SeniorSetting 경로 등록(새 스크린 라우트 추가)
프로젝트 종속성
app/build.gradle.kts, gradle/libs.versions.toml
androidx.browser:browser:1.9.0 의존성 추가
인증 로그아웃 API
data/src/main/kotlin/com/moa/app/data/auth/service/AuthService.kt, data/src/main/kotlin/com/moa/app/data/auth/datasource/AuthDataSource.kt, data/src/main/kotlin/com/moa/app/data/auth/datasourceImpl/AuthDataSourceImpl.kt, data/src/main/kotlin/com/moa/app/data/auth/repositoryImpl/AuthRepositoryImpl.kt, domain/src/main/kotlin/com/moa/app/domain/auth/repository/AuthRepository.kt, domain/src/main/kotlin/com/moa/app/domain/auth/usecase/LogOutUseCase.kt
로그아웃 엔드포인트(POST /api/v1/auth/logout)와 AuthTokenRequest 모델 추가, 각 계층에 logOut 메서드 도입 및 리포지토리/유스케이스 구현
유저 API·도메인 추가
data/src/main/kotlin/com/moa/app/data/user/service/UserService.kt, data/src/main/kotlin/com/moa/app/data/user/model/response/UserProfileResponse.kt, data/src/main/kotlin/com/moa/app/data/user/datasource/UserDataSource.kt, data/src/main/kotlin/com/moa/app/data/user/datasourceImpl/UserDataSourceImpl.kt, data/src/main/kotlin/com/moa/app/data/user/repositoryImpl/UserRepositoryImpl.kt, domain/src/main/kotlin/com/moa/app/domain/user/repository/UserRepository.kt, domain/src/main/kotlin/com/moa/app/domain/user/usecase/FetchUserProfileUseCase.kt, domain/src/main/kotlin/com/moa/app/domain/auth/usecase/WithdrawalUseCase.kt
사용자 프로필 조회·회원탈퇴 API·모델 추가, 데이터소스·리포지토리·유스케이스 계층 구현 및 매핑(성별 변환 포함)
DI 바인딩(데이터 계층)
data/src/main/kotlin/com/moa/app/data/di/DataSourceModule.kt, data/src/main/kotlin/com/moa/app/data/di/RepositoryModule.kt, data/src/main/kotlin/com/moa/app/data/di/ServiceModule.kt
UserService 제공자 추가, UserDataSource / UserRepository 바인딩 추가
Senior 설정 화면 추가/교체
feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingScreen.kt, feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SeniorSettingViewModel.kt, feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/model/SeniorSettingUiState.kt, feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/SettingScreen.kt (삭제)
SeniorSettingScreen + ViewModel/UiState 추가, 기존 SettingScreen 파일 전체 삭제(대체)
설정 UI 컴포넌트 업데이트
feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/component/OtherSection.kt, feature/senior/src/main/kotlin/com/moa/app/feature/senior/setting/component/OptionItem.kt
OtherSection에 클릭 콜백(고객센터/정책/로그아웃/탈퇴) 추가, OptionItem에 start padding 적용
홈 화면 연동
feature/senior/src/main/kotlin/com/moa/app/feature/senior/home/SeniorHomeScreen.kt, feature/senior/src/main/kotlin/com/moa/app/feature/senior/home/SeniorHomeViewModel.kt
설정 버튼 클릭 콜백 추가, navigateToReport()navigateToSetting()로 명칭 및 라우팅 변경
디자인 시스템 - 다이얼로그
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/dialog/MaAlertDialog.kt
커스텀 AlertDialog 컴포저블 MaAlertDialog 추가
도메인 유틸
domain/src/main/kotlin/com/moa/app/domain/auth/model/Gender.kt
Gender.fromString() 매핑 함수 추가

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45–60 minutes

  • 주의 집중 필요 항목:
    • SeniorSettingViewModel 전체 흐름(프로필 조회, 로그아웃·탈퇴, 백스택 초기화)
    • 계층 간 에러 전달 및 toResult/Result 매핑 일관성
    • OpenUrl 검증/로깅 및 CustomTabs 폴백 안전성
    • DI 바인딩 추가(UserService, UserDataSource, UserRepository)와 모듈 임포트

Possibly related PRs

Poem

🐰 토끼가 말하네, 새 화면이 활짝 열리고
프로필 불러오고, 로그아웃도 척척 해냈지
정책은 클릭하면 탭으로 훌쩍, 실패해도 폴백은 준비돼
코드 한 줄씩 뽀송뽀송, 기능은 한 뼘 더 자라났네
뛰어봄직한 변화, 당근 한 조각 축하해요 ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 설정 화면 로직 구현 및 API 연동이라는 주요 변경사항을 명확하게 요약하고 있습니다.
Description check ✅ Passed PR 설명이 저장소의 템플릿 구조를 따르고 있으며, 관련 이슈, 작업 내용, 스크린샷, 미완료 작업을 포함하고 있습니다.
Linked Issues check ✅ Passed 프로필 조회, 로그아웃/회원탈퇴 API 연동, 웹 URL 연결 등 이슈 #40의 모든 주요 목표가 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 설정 화면 로직 및 API 연동과 관련된 범위 내의 변경입니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/40-setting-api

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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.

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: 클릭 가능 영역 확인 권장

현재 paddingclickable 수정자 뒤에 적용되어 있어, 패딩 영역은 클릭할 수 없습니다. 만약 더 넓은 클릭 영역을 제공하려면 paddingclickable 앞으로 이동하는 것을 고려하세요.

현재 구조를 유지하려면:

.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 콜백들을 그대로 넘겨주어 고객센터/정책/로그아웃/탈퇴 플로우가 한 눈에 들어옵니다.

다만 두 가지는 추후 개선을 고려해볼 수 있습니다.

  1. 회원코드 복사 버튼 (onCopyClick = {})
    현재 ProfileSection"복사" 버튼이 동작하지 않으므로, 실제로 사용자가 복사 기능을 기대할 수 있는 UI라면 뷰모델 메서드(or 헬퍼)를 넘겨주거나, 추후 구현 계획이 아니라면 TODO 코멘트라도 남겨 두는 편이 좋겠습니다.

  2. 앱 버전 정보 하드코딩 ("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

📥 Commits

Reviewing files that changed from the base of the PR and between eaff0b4 and a9c94cb.

📒 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 returns Result<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.browser library 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 behavior

The codebase shows parentCode as consistently non-nullable across all response models (UserProfileResponse and ParentRoleResponse). 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 (parentUserId is nullable Long? while parentCode is non-nullable String) appears intentional, but lacks documentation. With strict kotlinx.serialization, a null parentCode from 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/bash

Search 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/bash

Find the ObserveNavigationEvents.kt file and read its content

fd "ObserveNavigationEvents.kt" --type=f -x cat -n {}


</function_calls>

#!/bin/bash

Search for openUrlInBrowser function implementation

rg -n "fun openUrlInBrowser|openUrlInBrowser\s*(" --type=kt -A 10 -B 2


</function_calls>

#!/bin/bash

Search 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, 두 개의 다이얼로그 플래그로만 구성된 SeniorSettingUiStateINIT 값 정의가 설정 화면에서 필요한 최소 상태를 잘 캡처하고 있습니다. 프리뷰/초기 상태에서 재사용하기에도 좋아 보입니다.

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 구현입니다.

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.

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() 함수 모두 비동기 작업 중 로딩 상태를 표시하지 않습니다. 네트워크 요청이 처리되는 동안 사용자에게 시각적 피드백을 제공하면 사용자 경험이 향상됩니다.

SeniorSettingUiStateisLoading 또는 개별 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

📥 Commits

Reviewing files that changed from the base of the PR and between a9c94cb and f1eeb37.

📒 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()를 호출하여 회원탈퇴 실패 시 올바른 다이얼로그를 닫습니다.

@wjdrjs00 wjdrjs00 merged commit 65bc428 into develop Nov 27, 2025
4 checks passed
@wjdrjs00 wjdrjs00 deleted the feature/40-setting-api branch November 27, 2025 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 설정 로직 구현 및 API를 연동합니다.

2 participants