Skip to content

Conversation

@s9hn
Copy link
Member

@s9hn s9hn commented May 15, 2025

📌𝘐𝘴𝘴𝘶𝘦𝘴

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

  • 자동 로그인 기능을 구현합니다.
  • SplashViewModel 에서 하나의 이벤트 플로우로 로직을 일원화합니다.
    • 더 이상 라이브데이터를 사용하지 않습니다.

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

스플래시 뷰에서 무조건 1회 `토큰재갱신 API(/reissue)'를 호출합니다.
앱 내에서의 토큰 만료 가능성을 줄여 관련 사이드 이펙트를 최소화합니다.

자동로그인 시나리오

  1. 아예 처음 접속한 경우
  2. 재접속한 경우
  3. 재접속했으나 엑세스토큰이 만료된 경우
  4. 재접속했으나 리프레시토큰이 만료된 경우
  5. 데이터 및 캐시 삭제한 경우
  6. 앱 사용중 캐시 삭제한 경우
  • 현재 `토큰재갱신 API(/reissue)' 는 어센틱케이터를 통과할 수 없도록 구현되어 있습니다.
  • 1, 2, 3, 4, 5번의 경우 필연적으로 앱이 재시작되어 스플래시뷰를 통과합니다.
  • 6번의 경우, 토큰이 없는 상태에서 특정 API를 호출할 경우, 어센틱케이터를 통해 `토큰재갱신 API(/reissue)' 의 리퀘스트로 빈값이 날아가며, 401을 응답받기 때문에 정상적인 플로우로 로그인뷰로 이동하게 됩니다.
  • 1, 5번의 경우, 굳이 `토큰재갱신 API(/reissue)' 을 호출할 필요가 없으므로, 바로 로그인뷰로 이동합니다.
  • 2, 3번의 경우 `토큰재갱신 API(/reissue)' 를 통해 무조건 토큰을 1회 업데이트하고 메인뷰로 이동합니다.
  • 4번의 경우, 토큰이 만료 응답을 받을 것이므로 로그인뷰로 이동합니다.

s9hn added 7 commits May 14, 2025 18:22
1. 라이브데이터 제거
2. UiEffect로 통합 관리
3. 함수 네이밍 변경
4. 자동 로그인 로직 새롭게 구현
1. 불필요한 바인딩 제거
2. 옵저빙 함수 -> collect 함수료 고체
3. 이벤트 통합관리
4. navigator를 통한 뷰 전환, 기존 함수 삭제
@s9hn s9hn self-assigned this May 15, 2025
@s9hn s9hn added ♻️ [REFACTOR] 기존 코드를 리팩토링합니다. ⚖️ 재상 세훈 전지적 세훈 시점 labels May 15, 2025
@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

자동 로그인 로직이 전면적으로 리팩터링되었습니다. LiveData 기반의 분산된 상태 및 네비게이션 처리가 단일 SharedFlow 기반의 UI 효과 처리로 통합되었고, 관련 데이터 소스 및 저장소에서 auto-login 관련 코드가 제거되었습니다. Splash 화면의 네비게이션 흐름과 ViewModel의 토큰 검증 및 갱신 로직이 변경되었습니다.

Changes

파일/경로 그룹 변경 요약
app/build.gradle.kts projects.data.account 종속성 추가
app/src/main/java/com/into/websoso/ui/splash/SplashActivity.kt
app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt
SplashActivity가 BaseActivity에서 AppCompatActivity로 변경, LiveData → SharedFlow 기반 UI 효과 처리, 네비게이션 및 토큰 검증 로직 리팩터링
app/src/main/java/com/into/websoso/ui/splash/dialog/MinimumVersionDialogFragment.kt MINIMUM_VERSION_TAG 상수 companion object로 이동
core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/account/DefaultAccountDataSource.kt
data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt
auto-login 관련 메서드 및 필드 삭제
data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt 토큰 저장 시 auto-login 플래그 갱신 로직 삭제

Sequence Diagram(s)

sequenceDiagram
    participant SplashActivity
    participant SplashViewModel
    participant AccountRepository
    participant VersionRepository
    participant UserRepository

    SplashActivity->>SplashViewModel: onCreate()
    SplashViewModel->>VersionRepository: checkMinimumVersion()
    alt 업데이트 필요
        SplashViewModel-->>SplashActivity: uiEffect(ShowDialog)
    else 업데이트 불필요
        SplashViewModel->>AccountRepository: shouldRefresh()
        alt 토큰 없음/유효하지 않음
            SplashViewModel-->>SplashActivity: uiEffect(NavigateToLogin)
        else 토큰 유효
            SplashViewModel->>AccountRepository: renewToken()
            alt 성공
                SplashViewModel-->>SplashActivity: uiEffect(NavigateToMain)
            else 실패
                SplashViewModel-->>SplashActivity: uiEffect(NavigateToLogin)
            end
        end
    end
Loading

Assessment against linked issues

Objective Addressed Explanation
자동 로그인 로직 리팩터링 및 구현 (#682)

Suggested labels

🍯 [FEAT]

Suggested reviewers

  • m6z1
  • yeonjeen
  • junseo511

Poem

🐰
새로워진 자동 로그인 길,
Splash에서 토큰을 살피고,
SharedFlow로 신호를 실어
로그인, 메인, 어디로든
깔끔해진 흐름 속에
토끼는 춤을 춥니다!
🥕✨


🪧 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.

@github-actions github-actions bot requested review from junseo511, m6z1 and yeonjeen May 15, 2025 05:09
@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.

@s9hn s9hn changed the title Feat/682 refactor: 자동로그인 로직 구현 May 15, 2025
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: 3

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

26-27: 불변 프로퍼티로 의도 명확화 및 재할당 방지

_uiEffect는 객체 생성 이후 재할당되지 않으므로 var 대신 val로 선언하여 의도를 명확히 하고, 실수로 재할당되는 것을 방지하는 편이 좋습니다.

-        private var _uiEffect: MutableSharedFlow<UiEffect> = MutableSharedFlow(replay = 1)
+        private val _uiEffect = MutableSharedFlow<UiEffect>(replay = 1)

54-68: 토큰 갱신 실패 시 재시도·백오프 전략 부재

accountRepository.renewToken() 실패 시 곧바로 로그인 화면으로 이동합니다.
일시적인 네트워크 오류나 서버 오류일 경우 사용자가 불필요하게 로그인 절차를 거치게 될 수 있으므로,
재시도(백오프 포함) 또는 사용자에게 “다시 시도” 옵션을 제공하는 UX 개선을 고려해 보세요.

📜 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 527fdf3.

📒 Files selected for processing (7)
  • app/build.gradle.kts (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 (0 hunks)
  • data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt (0 hunks)
  • data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt (0 hunks)
💤 Files with no reviewable changes (3)
  • data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt
  • data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt
  • core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/account/DefaultAccountDataSource.kt
🧰 Additional context used
🧬 Code Graph Analysis (2)
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 (34-42)
app/build.gradle.kts (1)
build-logic/src/main/kotlin/com/into/websoso/WebsosoDependenciesExtensions.kt (1)
  • implementation (70-76)
🔇 Additional comments (3)
app/build.gradle.kts (1)

85-87:

Details

❓ Verification inconclusive

data.account 모듈 추가 시 의존성 그래프 확인 필요

앱 모듈에서 data-layer 모듈을 직접 참조하면,
• feature → data → core 로 이어지는 기존 아키텍처 계층 구조에 순환 의존성이 생길 수 있습니다.
• DI 그래프가 중복 주입되면서 빌드 시간이 늘어나거나 Duplicate class 컴파일 오류가 발생할 위험도 있습니다.

Gradle dependencies 태스크로 의존성 그래프를 한번 점검해 주세요.

문제가 없다면 그대로 두셔도 무방합니다.


🏁 Script executed:

./gradlew :app:dependencies --configuration releaseRuntimeClasspath | grep -i "data.account"

Length of output: 480


의존성 그래프 확인 필요 (build 오류 발생)

앱 모듈에서 data.account 를 직접 참조할 경우 순환 의존성이나 DI 중복 주입으로 인한 빌드 오류 위험이 있습니다.
하지만 제안된 아래 Gradle 의존성 검사 명령을 실행하는 중 app/build.gradle.kts 27번째 줄에서 value must not be null 오류가 발생해 의존성 트리를 확인할 수 없는 상태입니다.

조치 사항:

  • 먼저 app/build.gradle.kts 27번째 줄의 null 관련 설정 값을 확인·수정하세요.
  • 수정 후, 다음 명령어로 다시 의존성 그래프를 검토해 주세요:
./gradlew :app:dependencies --configuration releaseRuntimeClasspath | grep -i "data.account"

문제가 없다면 그대로 두셔도 무방합니다.

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

37-38: TAG 상수 분리 👍

TAG 상수를 Dialog 내부로 이동하여 책임 범위가 명확해졌습니다. 추가 변경 없이 그대로 사용해도 됩니다.

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

40-46: UI 효과 수집 로직의 lifecycle 안전성 확인

collectWithLifecycle(this) 확장 함수가 Lifecycle.State.STARTED 이상에서 Flow 를 수집하도록 구현돼 있다면 문제없습니다.
확실치 않다면 repeatOnLifecycle(Lifecycle.State.STARTED) 사용 여부를 검토해 주세요.

Comment on lines 33 to 37
@SuppressLint("HardwareIds")
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.

⚠️ Potential issue

ANDROID_ID 널 가능성 미처리로 컴파일 불가

Settings.Secure.getString()의 반환형은 String? 입니다.
아래처럼 Nullable → Non-Null 변환 없이 그대로 넘기면 컴파일 에러가 발생합니다.

val deviceId = getString(contentResolver, ANDROID_ID) // String?
splashViewModel.updateUserDeviceIdentifier(deviceIdentifier = deviceId) // String

다음 중 한 가지로 수정해 주세요.

- val deviceId = getString(contentResolver, ANDROID_ID)
- splashViewModel.updateUserDeviceIdentifier(deviceIdentifier = deviceId)
+ val deviceId = getString(contentResolver, ANDROID_ID) ?: return
+ splashViewModel.updateUserDeviceIdentifier(deviceIdentifier = deviceId)

또는 ViewModel 메서드의 파라미터를 String? 로 변경 후, 내부에서 null 체크를 수행해도 됩니다.

🤖 Prompt for AI Agents
In app/src/main/java/com/into/websoso/ui/splash/SplashActivity.kt around lines
33 to 37, the variable deviceId is assigned a nullable String from
getString(contentResolver, ANDROID_ID) but passed to a method expecting a
non-null String, causing a compile error. Fix this by either safely unwrapping
deviceId with a null check or the Elvis operator to provide a default non-null
value before passing it to updateUserDeviceIdentifier, or alternatively, modify
the ViewModel method parameter to accept a nullable String and handle null
inside that method.

Comment on lines 30 to 32
checkMinimumVersion()
handleAutoLogin()
}
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

동시 UI 이펙트 발행으로 인한 충돌 가능성

checkMinimumVersion()handleAutoLogin()이 각각 별도의 코루틴으로 동시에 실행되기 때문에

  1. 업데이트가 필요한 경우 ShowDialog 발행 후 곧바로 NavigateToLogin/Main 이펙트가 뒤따라
  2. 다이얼로그가 표시되기 전에 화면이 이동하거나, 다이얼로그 뒤에서 화면이 변경되는 현상

이 발생할 수 있습니다. 두 로직 간 선후 관계가 명확하다면 순차 실행(예: 최소 버전 검사 → 통과 시 자동 로그인)을 고려해주세요.

🤖 Prompt for AI Agents
In app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt around lines
30 to 32, the functions checkMinimumVersion() and handleAutoLogin() are
currently launched concurrently, causing UI effect conflicts such as dialogs
showing while navigation occurs. To fix this, refactor the code to execute these
functions sequentially: first complete checkMinimumVersion() and only if it
passes, then call handleAutoLogin(). This ensures the dialog is shown and
handled before any navigation effects are triggered.

Copy link
Member Author

Choose a reason for hiding this comment

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

@coderabbitai 아주 좋은 의견 b
하나의 스코프로 관리해 순서를 보장하도록 수정

Copy link

Choose a reason for hiding this comment

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

@s9hn 네, 하나의 코루틴 스코프로 두 함수의 실행 순서를 관리하는 것이 좋은 접근 방식입니다. 이렇게 하면 UI 효과 간의 충돌을 방지하고 사용자 경험을 향상시킬 수 있습니다. 수정 감사합니다! 👍

Comment on lines 44 to 52
private fun checkMinimumVersion() {
viewModelScope.launch {
runCatching {
userRepository.fetchMyProfile()
}.onSuccess {
autoLogin()
}.onFailure {
authRepository.clearTokens()
_error.value = true
versionRepository.isUpdateRequired()
}.onSuccess { isRequired ->
if (isRequired) _uiEffect.emit(ShowDialog)
}
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

실패 케이스 로깅 및 사용자 피드백 누락

runCatching { versionRepository.isUpdateRequired() } 호출에서 onFailure 처리가 없습니다.
네트워크 오류 등이 발생해도 아무 이펙트도 발행하지 않아 사용자는 무응답 상태를 겪을 수 있습니다.
예시처럼 로깅과 함께 적절한 fallback 네비게이션 또는 재시도 지점을 마련해 주세요.

                 }.onSuccess { isRequired ->
                     if (isRequired) _uiEffect.emit(ShowDialog)
-                }
+                }.onFailure { throwable ->
+                    // TODO: Crashlytics 등의 로깅
+                    throwable.printStackTrace()
+                    // 예: 안전하게 로그인 화면으로 이동
+                    _uiEffect.emit(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
private fun checkMinimumVersion() {
viewModelScope.launch {
runCatching {
userRepository.fetchMyProfile()
}.onSuccess {
autoLogin()
}.onFailure {
authRepository.clearTokens()
_error.value = true
versionRepository.isUpdateRequired()
}.onSuccess { isRequired ->
if (isRequired) _uiEffect.emit(ShowDialog)
}
}
}
private fun checkMinimumVersion() {
viewModelScope.launch {
runCatching {
versionRepository.isUpdateRequired()
}.onSuccess { isRequired ->
if (isRequired) _uiEffect.emit(ShowDialog)
}.onFailure { throwable ->
// TODO: Crashlytics 등의 로깅
throwable.printStackTrace()
// 예: 안전하게 로그인 화면으로 이동
_uiEffect.emit(NavigateToLogin)
}
}
}
🤖 Prompt for AI Agents
In app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt around lines
44 to 52, the runCatching block calling versionRepository.isUpdateRequired()
lacks onFailure handling, so network errors or other failures do not trigger any
user feedback or logging. Add an onFailure block to log the error and emit a
suitable UI effect to inform the user or provide a fallback navigation or retry
option, ensuring the app responds appropriately to failures.

@s9hn s9hn merged commit e3a422e into feat/657 May 15, 2025
1 check passed
@m6z1 m6z1 deleted the feat/682 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