Skip to content

Conversation

@s9hn
Copy link
Member

@s9hn s9hn commented May 15, 2025

📌𝘐𝘴𝘴𝘶𝘦𝘴

📎𝘞𝘰𝘳𝘬 𝘋𝘦𝘴𝘤𝘳𝘪𝘱𝘵𝘪𝘰𝘯

  • 로그아웃 기능을 구현합니다.

💬𝘛𝘰 𝘙𝘦𝘷𝘪𝘦𝘸𝘦𝘳𝘴

  • 카카오 로그아웃은 서버에서 진행하므로, 클라이언트에선 할 필요가 없습니다.
  • 따라서 불필요한 로그아웃 코드는 제거합니다.

@github-actions github-actions bot requested review from junseo511, m6z1 and yeonjeen May 15, 2025 06:50
@s9hn s9hn changed the title Feat/683 refactor: 로그아웃 구현 May 15, 2025
@s9hn
Copy link
Member Author

s9hn commented May 15, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented May 15, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented May 15, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

로그아웃 기능 전반에 대한 리팩터링이 이루어졌습니다. 기존 AuthRepository 및 관련 API, DTO, 데이터소스의 로그아웃 구현이 AccountRepository와 AccountDataSource 계층으로 이동되었으며, UI 레이어에서는 LiveData 기반 상태관리에서 StateFlow 및 Channel 기반의 UI 이펙트 처리로 변경되었습니다. 네비게이션도 NavigatorProvider를 활용하도록 일원화되었습니다.

Changes

파일/경로 그룹 변경 요약
app/build.gradle.kts projects.data.account 의존성 추가
.../data/remote/api/AuthApi.kt
.../data/repository/AuthRepository.kt
AuthApi, AuthRepository에서 로그아웃 관련 메소드 및 DTO import 삭제
.../ui/accountInfo/AccountInfoViewModel.kt
.../ui/accountInfo/LogoutDialogFragment.kt
ViewModel에서 LiveData → StateFlow/Channel로 변경, 로그아웃 → signOut 구조로 변경, DI 및 UI 이펙트 처리 도입
.../ui/splash/SplashActivity.kt
.../ui/splash/SplashViewModel.kt
Splash 화면에서 LiveData 기반 상태관리 → UI 이펙트 Channel로 변경, 네비게이터 DI 적용, 토큰/버전 체크 로직 리팩터링
.../ui/splash/dialog/MinimumVersionDialogFragment.kt MINIMUM_VERSION_TAG 상수 추가
core/datastore/.../DefaultAccountDataSource.kt isAutoLogin, saveIsAutoLogin 제거, clearTokens 메소드 추가
core/network/.../AccountApi.kt
.../DefaultAccountDataSource.kt
.../model/KakaoLogoutRequestDto.kt
카카오 로그아웃 API 및 DTO 추가, DTO명 및 패키지/가시성 변경, postLogout 구현 추가
data/account/.../AccountRepository.kt
.../datasource/AccountLocalDataSource.kt
.../datasource/AccountRemoteDataSource.kt
로그아웃(postLogout) 관련 메소드 AccountRepository/RemoteDataSource/LocalDataSource에 추가 및 autoLogin 관련 코드 제거
feature/signin/.../SignInScreen.kt
.../SignInViewModel.kt
signIn 관련 파라미터명 getToken → signInToPlatform으로 변경

Sequence Diagram(s)

sequenceDiagram
    participant UI as LogoutDialogFragment
    participant VM as AccountInfoViewModel
    participant Repo as AccountRepository
    participant Remote as AccountRemoteDataSource
    participant Local as AccountLocalDataSource

    UI->>VM: signOut(signOutToPlatform)
    activate VM
    VM->>signOutToPlatform: (AuthPlatform.KAKAO)
    VM->>Repo: deleteToken(deviceIdentifier)
    activate Repo
    Repo->>Remote: postLogout(refreshToken, deviceIdentifier)
    Remote-->>Repo: (완료)
    Repo->>Local: clearTokens()
    Local-->>Repo: (완료)
    deactivate Repo
    VM->>UI: emit UiEffect.NavigateToLogin
    deactivate VM
    UI->>Navigator: navigateToLogin()
Loading

Assessment against linked issues

Objective Addressed Explanation
로그아웃 구현 리팩터링 (#683)

Suggested labels

♻️ [REFACTOR]

Suggested reviewers

  • m6z1
  • yeonjeen
  • junseo511

Poem

🐰
로그아웃 토끼가 춤을 춰요,
LiveData는 안녕, StateFlow로 가요!
채널로 이펙트, 네비게이터로 점프,
토큰은 깨끗이, 계정도 산뜻!
리팩터링 한 번에,
깔끔한 로그아웃 완성했어요!
🥕


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 4

🧹 Nitpick comments (2)
app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt (2)

67-72: suspend 키워드가 불필요해 보입니다
shouldRefresh() 내부에서 모든 작업이 즉시 반환되고 I/O 호출이 없다면 suspend 를 제거해 함수 호출 스택을 단순화할 수 있습니다.


36-42: 단순 printStackTrace() 대신 구조화된 로깅 권장
에러를 단순 출력하면 Crashlytics / Sentry 등에서 수집되지 않을 수 있습니다. Log.e 또는 사내 공통 로거를 활용해 오류 원인과 파라미터(예: deviceIdentifier)를 기록해 주세요.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1de6f41 and 618f8c9.

📒 Files selected for processing (17)
  • app/build.gradle.kts (1 hunks)
  • app/src/main/java/com/into/websoso/data/remote/api/AuthApi.kt (0 hunks)
  • app/src/main/java/com/into/websoso/data/repository/AuthRepository.kt (0 hunks)
  • app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoViewModel.kt (3 hunks)
  • app/src/main/java/com/into/websoso/ui/accountInfo/LogoutDialogFragment.kt (1 hunks)
  • app/src/main/java/com/into/websoso/ui/splash/SplashActivity.kt (1 hunks)
  • app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt (1 hunks)
  • app/src/main/java/com/into/websoso/ui/splash/dialog/MinimumVersionDialogFragment.kt (1 hunks)
  • core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/account/DefaultAccountDataSource.kt (1 hunks)
  • core/network/src/main/java/com/into/websoso/core/network/datasource/account/AccountApi.kt (2 hunks)
  • core/network/src/main/java/com/into/websoso/core/network/datasource/account/DefaultAccountDataSource.kt (2 hunks)
  • core/network/src/main/java/com/into/websoso/core/network/datasource/account/model/KakaoLogoutRequestDto.kt (1 hunks)
  • data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt (2 hunks)
  • data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt (1 hunks)
  • data/account/src/main/java/com/into/websoso/data/account/datasource/AccountRemoteDataSource.kt (1 hunks)
  • feature/signin/src/main/java/com/into/websoso/feature/signin/SignInScreen.kt (1 hunks)
  • feature/signin/src/main/java/com/into/websoso/feature/signin/SignInViewModel.kt (1 hunks)
💤 Files with no reviewable changes (2)
  • app/src/main/java/com/into/websoso/data/remote/api/AuthApi.kt
  • app/src/main/java/com/into/websoso/data/repository/AuthRepository.kt
🧰 Additional context used
🧬 Code Graph Analysis (3)
app/build.gradle.kts (1)
build-logic/src/main/kotlin/com/into/websoso/WebsosoDependenciesExtensions.kt (1)
  • implementation (70-76)
data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt (3)
data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt (1)
  • refreshToken (6-6)
core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/account/DefaultAccountDataSource.kt (1)
  • refreshToken (29-33)
core/network/src/main/java/com/into/websoso/core/network/datasource/account/model/TokenReissueRequestDto.kt (1)
  • refreshToken (6-10)
app/src/main/java/com/into/websoso/ui/splash/SplashActivity.kt (1)
app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt (1)
  • updateUserDeviceIdentifier (36-44)
🔇 Additional comments (15)
app/build.gradle.kts (1)

86-86: 로그아웃 기능을 위한 의존성 추가

로그아웃 기능 리팩토링의 일환으로 AccountRepository를 사용하기 위해 projects.data.account 의존성이 추가되었습니다. 이는 기존의 AuthRepository에서 AccountRepository로 로그아웃 관련 기능이 이전되었음을 나타냅니다.

feature/signin/src/main/java/com/into/websoso/feature/signin/SignInScreen.kt (1)

65-65: 매개변수 이름 개선: getToken에서 signInToPlatform으로 변경

매개변수 이름을 변경한 것은 함수의 목적을 더 명확하게 표현합니다. 단순히 토큰을 가져오는 것보다 플랫폼에 로그인하는 의미가 더 정확합니다.

app/src/main/java/com/into/websoso/ui/splash/dialog/MinimumVersionDialogFragment.kt (1)

37-38: 다이얼로그 태그 상수 추가

최소 버전 업데이트 다이얼로그 표시를 위한 태그 상수를 추가했습니다. 이 태그는 SplashActivitySplashViewModel에서 다이얼로그 표시를 위해 사용됩니다. UI 이펙트 흐름에 따라 다이얼로그를 표시하는 새로운 방식에 맞게 통합되었습니다.

data/account/src/main/java/com/into/websoso/data/account/datasource/AccountRemoteDataSource.kt (1)

14-18: 로그아웃 함수 추가

AccountRemoteDataSource 인터페이스에 로그아웃 기능을 위한 postLogout 함수가 추가되었습니다. 이 함수는 refreshToken과 deviceIdentifier를 매개변수로 받아 서버에 로그아웃 요청을 보냅니다. 이는 기존 AuthRepository와 AuthApi에서 제거된 logout 기능을 대체하는 부분으로, 로그아웃 기능 리팩토링의 핵심입니다.

인터페이스 설계가 명확하며 필요한 매개변수들이 잘 정의되어 있습니다.

core/network/src/main/java/com/into/websoso/core/network/datasource/account/DefaultAccountDataSource.kt (1)

34-44: 로그아웃 메서드가 잘 구현되었습니다.

postLogout 메서드가 적절하게 구현되었습니다. refreshTokendeviceIdentifier를 파라미터로 받아 KakaoLogoutRequestDto를 생성하고 API 호출을 수행하는 흐름이 깔끔합니다. 로그아웃 기능을 AuthRepository에서 AccountRepository 계층으로 옮겨 책임 분리가 잘 이루어졌습니다.

core/network/src/main/java/com/into/websoso/core/network/datasource/account/AccountApi.kt (1)

23-26: 로그아웃 API 엔드포인트가 잘 정의되었습니다.

postLogoutWithKakao 메서드가 적절하게 정의되었습니다. @POST("auth/logout")으로 올바른 엔드포인트를 지정하고, 요청 본문으로 KakaoLogoutRequestDto를 사용하는 구조가 명확합니다. 기존 API 메서드들과 일관성 있게 구현되었습니다.

feature/signin/src/main/java/com/into/websoso/feature/signin/SignInViewModel.kt (1)

30-30: 파라미터 이름이 더 명확하게 개선되었습니다.

getToken에서 signInToPlatform으로 파라미터 이름을 변경한 것은 해당 함수의 역할을 더 정확히 표현합니다. 이 변경은 코드 가독성을 향상시키고 인증 흐름에 대한 이해를 돕습니다. 기존 로그아웃 로직을 리팩토링하는 전체적인 변경 사항과도 일관성이 있습니다.

Also applies to: 34-34

data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt (1)

12-12: 토큰 초기화 기능이 적절하게 추가되었습니다.

clearTokens() 메서드 추가는 로그아웃 흐름에서 필요한 기능으로 잘 구현되었습니다. 기존의 자동 로그인 상태 관리 메서드들을 대체하고 토큰 초기화에 집중하는 방식으로 개선된 점이 좋습니다. 코드가 간결해지고 책임이 명확해졌습니다.

data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt (2)

10-10: TODO 잔존: 개발 완료 전에 반드시 처리 필요

// TODO:가 그대로 남아 있습니다. 실제 배포 전에 싱글톤 패턴‧네이밍‧Result 객체 적용 여부를 검토하고 주석을 제거해 주세요.
[ suggest_nitpick ]


37-43: 예외 발생 시 토큰이 삭제되지 않는 문제

현재 구현은 postLogout() 호출이 예외를 던지면 clearTokens()가 실행되지 않아, 로컬에 남은 토큰으로 인해 재로그인 흐름이 꼬일 수 있습니다. finally 블록(혹은 runCatching)으로 토큰 삭제를 보장해 주세요.

-    suspend fun deleteToken(deviceIdentifier: String) {
-        accountRemoteDataSource
-            .postLogout(
-                refreshToken = refreshToken(),
-                deviceIdentifier = deviceIdentifier,
-            ).also { accountLocalDataSource.clearTokens() }
-    }
+    suspend fun deleteToken(deviceIdentifier: String) {
+        try {
+            accountRemoteDataSource.postLogout(
+                refreshToken = refreshToken(),
+                deviceIdentifier = deviceIdentifier,
+            )
+        } catch (e: Exception) {
+            // TODO: 필요하다면 로그 기록
+        } finally {
+            accountLocalDataSource.clearTokens()
+        }
+    }

[ raise_critical_issue ]

core/network/src/main/java/com/into/websoso/core/network/datasource/account/model/KakaoLogoutRequestDto.kt (1)

6-12: DTO 명칭 범용성 제고 제안

향후 카카오 외 플랫폼에서도 동일 DTO를 사용할 가능성이 있다면, Kakao 접두어를 제거해 LogoutRequestDto 등 범용 이름으로 변경하는 편이 유지보수에 유리합니다.
[ suggest_optional_refactor ]

core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/account/DefaultAccountDataSource.kt (1)

47-51: 로컬 토큰 삭제 구현 확인 완료

DataStore.edit { remove(...) } 방식으로 토큰을 안전하게 삭제하고 있어 문제없습니다.
[ approve_code_changes ]

app/src/main/java/com/into/websoso/ui/accountInfo/LogoutDialogFragment.kt (2)

38-44: 로그아웃 후 Fragment 미종료 가능성

NavigateToLogin으로 이동한 뒤 LogoutDialogFragmentdismiss()되지 않으면 백스택에 남을 수 있습니다. 내비게이션 직후에 dismiss() 혹은 findNavController().popBackStack() 호출을 고려해 주세요.
[ suggest_nitpick ]


51-56: UI 스레드에서 블로킹 호출 가능성

authClient[platform]?.signOut()이 네트워크 I/O를 포함한 블로킹 연산이라면 UI 스레드에서 호출되어 ANR이 발생할 수 있습니다. ViewModel 쪽에서 withContext(Dispatchers.IO)로 감싸거나, 여기서 CoroutineScope.launch로 offload하는 방안을 검토해 주세요.
[ request_verification ]

app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt (1)

46-51: 버전 확인 실패 시 ‘업데이트 필요 없음’으로 처리하면 잠재적 보안 리스크
네트워크 오류 등으로 isUpdateRequired() 호출이 실패하면, 현재 로직은 false 로 간주해 바로 다음 단계로 진행합니다. 실제로는 구(舊) 버전이 차단돼야 하는 상황에서 사용자가 우회 진입할 가능성이 있습니다.

예외 시에는 보수적으로 true 로 간주하거나, 별도의 오류 다이얼로그를 띄워 재시도하도록 하는 쪽이 안전합니다.

Comment on lines 26 to 28
private var _uiEffect = Channel<UiEffect>(Channel.BUFFERED)
val uiEffect: Flow<UiEffect> get() = _uiEffect.receiveAsFlow()

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Channel → SharedFlow로 전환 및 var 삭제를 고려해 주세요
Channel을 노출할 때마다 receiveAsFlow() 로 래핑해야 하고, var 로 선언되어 재할당 가능성이 열려 있습니다. 단방향 이벤트 스트림이면 MutableSharedFlow(+ extraBufferCapacity)가 보다 간결‧안정적이며, val 로 선언하면 재할당 우려도 사라집니다.

- private var _uiEffect = Channel<UiEffect>(Channel.BUFFERED)
- val uiEffect: Flow<UiEffect> get() = _uiEffect.receiveAsFlow()
+ private val _uiEffect = MutableSharedFlow<UiEffect>(extraBufferCapacity = 1)
+ val uiEffect: SharedFlow<UiEffect> get() = _uiEffect.asSharedFlow()
📝 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.

Suggested change
private var _uiEffect = Channel<UiEffect>(Channel.BUFFERED)
val uiEffect: Flow<UiEffect> get() = _uiEffect.receiveAsFlow()
private val _uiEffect = MutableSharedFlow<UiEffect>(extraBufferCapacity = 1)
val uiEffect: SharedFlow<UiEffect> get() = _uiEffect.asSharedFlow()
🤖 Prompt for AI Agents
In app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt around lines
26 to 28, replace the private Channel<UiEffect> _uiEffect and its public
Flow<UiEffect> uiEffect with a private val MutableSharedFlow<UiEffect>
initialized with an appropriate extraBufferCapacity, and expose it as a public
val SharedFlow<UiEffect>. Change the declaration from var to val to prevent
reassignment and simplify usage by removing the need to call receiveAsFlow()
each time.

Comment on lines 34 to 37
private fun updateUserDeviceIdentifier() {
val ssaid = Settings.Secure.getString(
this.contentResolver,
Settings.Secure.ANDROID_ID,
)
splashViewModel.updateUserDeviceIdentifier(deviceIdentifier = ssaid)
val deviceId = getString(contentResolver, ANDROID_ID)
splashViewModel.updateUserDeviceIdentifier(deviceIdentifier = deviceId)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

ANDROID_ID 는 nullable → NPE 예방 필요
Settings.Secure.getString()String? 을 반환합니다. 바로 전달하면 뷰모델에서 String non-null 로 기대하기 때문에 기기 일부에서 NPE 가 발생할 수 있습니다.

- val deviceId = getString(contentResolver, ANDROID_ID)
+ val deviceId = getString(contentResolver, ANDROID_ID).orEmpty()
🤖 Prompt for AI Agents
In app/src/main/java/com/into/websoso/ui/splash/SplashActivity.kt around lines
34 to 37, the ANDROID_ID retrieved using getString(contentResolver, ANDROID_ID)
is nullable and passing it directly to the view model expecting a non-null
String can cause a NullPointerException. To fix this, add a null check or
provide a default non-null value before passing deviceId to
splashViewModel.updateUserDeviceIdentifier, ensuring the argument is always a
non-null String.

Comment on lines 32 to 34
private var _uiEffect = Channel<UiEffect>(Channel.BUFFERED)
val uiEffect: Flow<UiEffect> get() = _uiEffect.receiveAsFlow()

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

ChannelSharedFlow + val 로 일관성 확보
SplashViewModel 과 동일한 패턴입니다. 이벤트 스트림이면 MutableSharedFlow 사용이 더 직관적이며 var 제거로 재할당 위험을 없앨 수 있습니다.

🤖 Prompt for AI Agents
In app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoViewModel.kt
around lines 32 to 34, replace the Channel-based event stream with a
MutableSharedFlow to align with the SplashViewModel pattern. Change the private
mutable property to a val MutableSharedFlow and expose it as a SharedFlow to
prevent reassignment risks and improve clarity for event streams.

Comment on lines 49 to 60
fun signOut(signOutToPlatform: suspend (platform: AuthPlatform) -> Unit) {
viewModelScope.launch {
runCatching {
signOutToPlatform(AuthPlatform.KAKAO)
val userDeviceIdentifier = userRepository.fetchUserDeviceIdentifier()
authRepository.logout(userDeviceIdentifier)
accountRepository.deleteToken(userDeviceIdentifier)
}.onSuccess {
_isLogoutSuccess.value = true
authRepository.updateIsAutoLogin(false)
pushMessageRepository.clearFCMToken()
_uiEffect.send(NavigateToLogin)
}.onFailure {
_isLogoutSuccess.value = false
_uiEffect.send(NavigateToLogin)
}
Copy link

@coderabbitai coderabbitai bot May 15, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

FCM 토큰 제거가 실패 경로에서 누락될 수 있습니다
pushMessageRepository.clearFCMToken()onSuccess 에만 위치해 있어, 서버 로그아웃 실패 시 FCM 토큰이 남아버립니다. 성공‧실패와 무관하게 실행하도록 리팩터링해 주세요.

- }.onSuccess {
-     pushMessageRepository.clearFCMToken()
-     _uiEffect.send(NavigateToLogin)
- }.onFailure {
-     _uiEffect.send(NavigateToLogin)
- }
+ }.onSuccess {
+     /* no-op */
+ }.onFailure {
+     /* 로그 등 추가 */
+ }.also {
+     // 무조건 실행
+     pushMessageRepository.clearFCMToken()
+     _uiEffect.send(NavigateToLogin)
+ }
📝 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.

Suggested change
fun signOut(signOutToPlatform: suspend (platform: AuthPlatform) -> Unit) {
viewModelScope.launch {
runCatching {
signOutToPlatform(AuthPlatform.KAKAO)
val userDeviceIdentifier = userRepository.fetchUserDeviceIdentifier()
authRepository.logout(userDeviceIdentifier)
accountRepository.deleteToken(userDeviceIdentifier)
}.onSuccess {
_isLogoutSuccess.value = true
authRepository.updateIsAutoLogin(false)
pushMessageRepository.clearFCMToken()
_uiEffect.send(NavigateToLogin)
}.onFailure {
_isLogoutSuccess.value = false
_uiEffect.send(NavigateToLogin)
}
fun signOut(signOutToPlatform: suspend (platform: AuthPlatform) -> Unit) {
viewModelScope.launch {
runCatching {
signOutToPlatform(AuthPlatform.KAKAO)
val userDeviceIdentifier = userRepository.fetchUserDeviceIdentifier()
accountRepository.deleteToken(userDeviceIdentifier)
}.onSuccess {
/* no-op */
}.onFailure {
/* 로그 등 추가 */
}.also {
// 무조건 실행
pushMessageRepository.clearFCMToken()
_uiEffect.send(NavigateToLogin)
}
}
}
🤖 Prompt for AI Agents
In app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoViewModel.kt
around lines 49 to 60, the call to pushMessageRepository.clearFCMToken() is only
inside the onSuccess block, so it is not executed if signOutToPlatform or token
deletion fails. Move pushMessageRepository.clearFCMToken() outside of the
onSuccess and onFailure blocks so it runs regardless of success or failure,
ensuring the FCM token is always cleared.

Copy link
Member Author

@s9hn s9hn May 15, 2025

Choose a reason for hiding this comment

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

@coderabbitai 로그아웃이 실패했는데 왜 토큰을 지워?

Copy link

Choose a reason for hiding this comment

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

@s9hn 말씀하신 내용이 맞습니다. 로그아웃이 실패한 경우에는 사용자가 여전히 로그인 상태로 남아있어야 하므로 FCM 토큰을 지우는 것이 적절하지 않습니다. 원래 구현대로 성공 경로에서만 FCM 토큰을 지우는 것이 맞습니다. 제안 내용을 철회합니다.


✏️ Learnings added
Learnt from: s9hn
PR: Team-WSS/WSS-Android#687
File: app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoViewModel.kt:0-0
Timestamp: 2025-05-15T17:11:19.809Z
Learning: 로그아웃 성공 케이스에서만 FCM 토큰을 제거해야 합니다. 로그아웃 실패 시에는 사용자가 여전히 로그인 상태이므로 FCM 토큰을 유지해야 합니다.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@s9hn s9hn merged commit 7f28f8c into feat/657 May 15, 2025
1 check passed
@s9hn s9hn added ♻️ [REFACTOR] 기존 코드를 리팩토링합니다. ⚖️ 재상 세훈 전지적 세훈 시점 labels May 19, 2025
@m6z1 m6z1 deleted the feat/683 branch August 11, 2025 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

♻️ [REFACTOR] 기존 코드를 리팩토링합니다. ⚖️ 재상 세훈 전지적 세훈 시점

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants