Skip to content

[Feat] 카카오 인증 연결#122

Merged
nahy-512 merged 4 commits into
developfrom
feat/#115-kakao-login-api
Jan 17, 2026
Merged

[Feat] 카카오 인증 연결#122
nahy-512 merged 4 commits into
developfrom
feat/#115-kakao-login-api

Conversation

@kimjw2003

@kimjw2003 kimjw2003 commented Jan 16, 2026

Copy link
Copy Markdown
Contributor

📮 관련 이슈

📌 작업 내용

  • 로그인 화면에서 카카오 인증 후 온보딩까지 화면 전환

Summary by CodeRabbit

릴리스 노트

  • 새 기능

    • Kakao 소셜 로그인 연동 및 로그인 흐름 추가
    • 소셜 인증 기반 회원가입 및 프로필 온보딩 흐름 추가(임시 토큰 전달)
    • 인증 API와 관련 모델/매핑·상태·뷰모델 도입
    • 스플래시에서 지연 후 자동 이동 동작 추가
  • Chores

    • Kakao SDK 및 빌드/매니페스트 설정, 저장소/버전 업데이트 추가

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

@kimjw2003 kimjw2003 self-assigned this Jan 16, 2026
@kimjw2003 kimjw2003 requested a review from a team as a code owner January 16, 2026 15:31
@kimjw2003 kimjw2003 added 🔖 API feat - API 연동 Feat ✨ 신규 기능을 추가하거나 기존 기능의 동작, 정책을 변경 labels Jan 16, 2026
@coderabbitai

coderabbitai Bot commented Jan 16, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

카카오 소셜 로그인 통합을 위해 SDK 의존성·매니페스트·빌드 설정을 추가하고, 인증 API/DTO, 도메인 모델, 리포지토리 구현, 매퍼, 뷰모델, 로그인 UI/매니저 및 내비게이션 흐름을 추가·수정합니다.

Changes

Cohort / File(s) 변경 사항
빌드 및 SDK 설정
app/build.gradle.kts, gradle/libs.versions.toml, settings.gradle.kts
Kakao v2-user 라이브러리 추가, KAKAO_NATIVE_APP_KEY를 BuildConfig 및 manifestPlaceholders로 노출, Kakao maven repo 추가
AndroidManifest
app/src/main/AndroidManifest.xml
com.kakao.sdk.auth.AuthCodeHandlerActivity 액티비티 등록(Exported, OAuth intent-filter)
앱 초기화
app/src/main/java/com/flint/FlintApplication.kt
KakaoSdk 초기화 호출 추가
인증 API 및 DTO
app/src/main/java/com/flint/data/api/AuthApi.kt, app/src/main/java/com/flint/data/dto/.../SignupRequestDto.kt, .../SocialVerifyRequestDto.kt, .../SignupResponseDto.kt, .../SocialVerifyResponseDto.kt
AuthApi 인터페이스 추가(회원가입·소셜검증 엔드포인트) 및 요청/응답 DTO 추가
도메인 모델·타입·리포지토리 인터페이스
app/src/main/java/com/flint/domain/model/auth/*, app/src/main/java/com/flint/domain/type/ProviderType.kt, app/src/main/java/com/flint/domain/repository/AuthRepository.kt
Signup/SocialVerify 도메인 모델, ProviderType enum, AuthRepository 인터페이스 추가
매퍼 및 리포지토리 구현
app/src/main/java/com/flint/data/mapper/auth/*, app/src/main/java/com/flint/data/repositoryImpl/DefaultAuthRepository.kt
DTO↔도메인 매퍼 추가 및 AuthApi 사용하는 DefaultAuthRepository 구현 추가 (runCatching으로 에러 래핑)
DI 모듈 변경
app/src/main/java/com/flint/core/common/di/RepositoryModule.kt, app/src/main/java/com/flint/core/common/di/ServiceModule.kt
FlintRepository/FlintApi 바인딩을 AuthRepository/AuthApi로 변경 (바인딩 대상과 제공 함수명/타입 변경)
로그인 UI·뷰모델·매니저
app/src/main/java/com/flint/presentation/login/LoginScreen.kt, .../LoginViewModel.kt, .../manager/KakaoLoginManager.kt, .../data/VerifyStatusData.kt
KakaoLoginManager 추가(카카오톡/계정 로그인 분기), LoginViewModel 추가(소셜검증 처리·토큰 저장), LoginScreen에 카카오 로그인 클릭 핸들러 및 상태 기반 네비게이션 연결
내비게이션·라우트 변경
app/src/main/java/com/flint/core/navigation/Route.kt, .../login/navigation/LoginNavigation.kt, .../onboarding/navigation/OnboardingNavigation.kt, .../main/MainNavigator.kt
OnboardingProfile을 tempToken을 받는 data class로 변경하고 온보딩 네비게이션에 tempToken 전달하도록 시그니처 및 호출부 수정, 시작 목적지 변경
스플래시 변경
app/src/main/java/com/flint/presentation/splash/SplashScreen.kt
LaunchedEffect로 2000ms 지연 후 로그인 화면 네비게이션 추가
공통 유틸
app/src/main/java/com/flint/core/common/util/Constants.kt
DataStore 키 상수(ACCESS_TOKEN, REFRESH_TOKEN, USER_ID) 추가

Sequence Diagram(s)

sequenceDiagram
    participant 사용자 as User
    participant UI as LoginScreen
    participant Manager as KakaoLoginManager
    participant KakaoSDK as Kakao SDK
    participant VM as LoginViewModel
    participant Repo as DefaultAuthRepository
    participant API as AuthApi
    participant Prefs as PreferencesManager
    participant Nav as Navigator

    User->>UI: 카카오 로그인 클릭
    UI->>Manager: login(context, callback)
    Manager->>KakaoSDK: loginWithKakaoTalk() / loginWithKakaoAccount()
    KakaoSDK-->>Manager: OAuthToken / Error
    Manager-->>UI: Result(OAuthToken)
    UI->>VM: socialVerifyWithKakao(provider=KAKAO, accessToken)
    VM->>Repo: socialVerify(requestModel)
    Repo->>API: socialVerify(SocialVerifyRequestDto)
    API-->>Repo: SocialVerifyResponseDto
    Repo-->>VM: Result<SocialVerifyResponseModel>
    alt isRegistered == false
        VM-->>UI: UiState.Success(tempToken)
        UI->>Nav: navigateToOnBoarding(tempToken)
    else isRegistered == true
        VM->>Prefs: save accessToken/refreshToken/userId
        VM-->>UI: UiState.Success(null)
        UI->>Nav: navigateToHome()
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

⚙️ Setting

Suggested reviewers

  • nahy-512

Poem

🐰 카카오 햇살 반짝, 토큰을 물고 왔네
작은 발로 로그인 길을 열고
tempToken 들고 온보딩 문으로 뛰어가요
토끼도 함께 춤추며 저장소에 넣었네
훌쩍, 새로운 시작! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 주요 변경사항인 카카오 인증 연결을 명확하게 요약하고 있습니다.
Description check ✅ Passed PR 설명에서 관련 이슈(#115)와 작업 내용이 포함되어 있으나, 템플릿의 스크린샷, 미구현 사항, 리뷰어 노트 등 선택적 섹션이 미작성되어 있습니다.
Linked Issues check ✅ Passed PR이 이슈 #115의 카카오 로그인 API 연동 요구사항을 충족합니다. AuthApi, KakaoLoginManager, LoginViewModel을 통해 카카오 인증 흐름이 구현되었고, 온보딩 네비게이션과 연결되었습니다.
Out of Scope Changes check ✅ Passed 카카오 SDK 추가, 인증 저장소 및 매퍼, 도메인 모델, UI 화면 및 네비게이션 수정 등 모든 변경사항이 카카오 인증 흐름 구현이라는 범위 내에 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt (1)

29-34: 라우트 파라미터 tempToken이 추출되지 않고 있습니다.

Route.OnboardingProfile(tempToken)으로 네비게이션할 때 tempToken을 전달하지만, composable<Route.OnboardingProfile> 블록에서 이를 추출하여 사용하고 있지 않습니다. navBackStackEntry.arguments를 통해 tempToken을 추출한 후 OnboardingProfileRoute에 전달하거나 화면 로직에서 직접 사용해야 합니다.

🤖 Fix all issues with AI agents
In `@app/src/main/AndroidManifest.xml`:
- Line 16: Remove the global android:usesCleartextTraffic="true" setting from
the application manifest and instead either set
android:usesCleartextTraffic="false" or remove it entirely; if you need
cleartext for a dev backend, create a network-security-config XML
(res/xml/network_security_config.xml) and reference it via the application
attribute android:networkSecurityConfig, or apply the cleartext allowance only
to debug builds via manifest placeholders/manifestMerger so production does not
permit cleartext traffic; update AndroidManifest.xml to use the
networkSecurityConfig attribute and add the domain-specific config file to limit
cleartext to specific dev domains.

In `@app/src/main/java/com/flint/presentation/login/data/VerifyStatusData.kt`:
- Around line 3-6: VerifyStatusData currently mixes registration state and
tempToken allowing tempToken to be null when isRegistered is false; change the
model to make states explicit by replacing VerifyStatusData with a sealed class
(e.g., sealed class VerifyStatus { data class Registered(val accessToken:
String, val refreshToken: String, val userId: String): VerifyStatus(); data
class NotRegistered(val tempToken: String): VerifyStatus() }) or, if you prefer
keeping the data class, add validation where SocialVerifyResponseDto is mapped
(the converter/mapping function that builds VerifyStatusData) to throw/log and
reject/handle responses where isRegistered == false but tempToken == null so
onboarding never receives an empty token; update call sites that read
VerifyStatusData (login UI code using data.tempToken ?: "") to consume the new
sealed variants or rely on the validated non-null contract.

In `@app/src/main/java/com/flint/presentation/login/LoginScreen.kt`:
- Around line 49-62: LaunchedEffect keyed on socialVerifyStatus can retrigger
navigation on recomposition; after handling UiState.Success in LoginScreen's
LaunchedEffect (the branch that reads (socialVerifyStatus as
UiState.Success<VerifyStatusData>).data and calls navigateToHome() or
navigateToOnBoarding(...)), call a ViewModel method to clear the status (e.g.,
viewModel.resetVerifyStatus()) so the UiState is set back to UiState.Empty and
navigation won't fire again; implement resetVerifyStatus() in the LoginViewModel
to set _verifyStatus = UiState.Empty and invoke it immediately after each
navigateToHome() / navigateToOnBoarding(...) call.

In `@app/src/main/java/com/flint/presentation/login/LoginViewModel.kt`:
- Around line 43-45: The onFailure block currently only logs the exception with
Timber.e(it) and never updates the UI; modify the onFailure lambda in
LoginViewModel to emit an error state to _verifyStatus (e.g.,
_verifyStatus.emit(UiState.Error(...))) including the exception message or a
user-facing message, verify that UiState.Error exists (create it if missing),
and ensure LoginScreen consumes verifyStatus to show appropriate feedback
(toast/snackbar) for error states; keep the Timber.e call for logging but add
the state emission in the onFailure path.

In `@app/src/main/java/com/flint/presentation/login/manager/KakaoLoginManager.kt`:
- Around line 16-27: 로그인 취소 시 호출자가 무한 대기에 빠지지 않도록
UserApiClient.instance.loginWithKakaoTalk의 취소 분기에서 단순 return 대신 onResult를 호출해
취소를 알리는 실패 결과를 전달하고, when 블록 안에서도 token과 error가 둘 다 null인 경우를 방어적으로 처리해
onResult(Result.failure(...))를 호출하도록 수정하세요; 참고로 수정 위치는
UserApiClient.instance.loginWithKakaoTalk(...) 콜백의
ClientError/ClientErrorCause.Cancelled 처리와 내부 fallback인
UserApiClient.instance.loginWithKakaoAccount(...) 콜백(토큰2/에러2 처리)입니다.

In `@app/src/main/java/com/flint/presentation/splash/SplashScreen.kt`:
- Around line 16-20: 현재 SplashScreen의 LaunchedEffect(…) 블록은 FIXME 테스트 코드로
delay(2000) 후 항상 navigateToLogin()만 호출하여 viewModel과 navigateToHome 파라미터를 무시하고
있습니다; 이를 고치려면 LaunchedEffect 또는 viewModel의 상태(flow/state)를 구독하여 ViewModel의 인증
상태(예: viewModel.isAuthenticated / authState)를 확인한 뒤 인증되어 있으면 navigateToHome()을
호출하고 아니면 navigateToLogin()을 호출하도록 분기 처리하고, 필요한 경우 인증 확인이 끝날 때까지 짧은 스플래시 지연을 유지하되
하드코딩된 테스트 주석(FIXME)과 불필요한 고정 호출을 제거하세요 (참조 심볼: LaunchedEffect, viewModel,
navigateToLogin, navigateToHome).
🧹 Nitpick comments (8)
app/src/main/java/com/flint/presentation/splash/SplashScreen.kt (1)

25-27: 빈 스플래시 화면 구현.

SplashScreen() 컴포저블이 비어있어 2초 딜레이 동안 사용자에게 빈 화면이 표시됩니다. 일반적으로 스플래시 화면에서는 앱 로고나 브랜딩 요소를 보여주는 것이 좋습니다.

app/build.gradle.kts (1)

46-48: 누락된 속성에 대한 방어적 처리 권장.

kakao.native.app.keylocal.properties에 없을 경우, properties["kakao.native.app.key"].toString()은 문자열 "null"을 반환하여 런타임에 인증 실패를 유발할 수 있습니다. 빌드 시점에 명확한 오류 메시지로 실패하도록 하는 것이 좋습니다.

♻️ 제안된 수정
-        val kakaoNativeAppKey = properties["kakao.native.app.key"].toString()
+        val kakaoNativeAppKey = properties["kakao.native.app.key"]?.toString()
+            ?: error("kakao.native.app.key is missing in local.properties")
         buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"$kakaoNativeAppKey\"")
         manifestPlaceholders["KAKAO_NATIVE_APP_KEY"] = kakaoNativeAppKey
gradle/libs.versions.toml (1)

53-54: 카카오 SDK 버전 업데이트 권장.

버전 2.21.0은 유효하지만 최신 버전이 아닙니다. 현재 최신 안정 버전은 2.23.2입니다. 더 최신의 안정적인 버전으로 업데이트를 권장합니다. (가용한 최신 버전: 2.23.2, 2.23.1, 2.23.0, 2.22.0 등)

app/src/main/java/com/flint/core/navigation/Route.kt (1)

12-15: 네비게이션 라우트에 민감한 토큰 전달 회피 필요

tempToken은 인증 관련 민감한 데이터이므로 네비게이션 라우트 매개변수로 전달하지 않는 것이 좋습니다. 완료 후 토큰을 사용할 때는 ViewModelSavedStateHandle이나 보안 저장소를 통해 전달하는 방식을 고려해 주세요.

app/src/main/java/com/flint/core/common/di/RepositoryModule.kt (1)

16-16: 메서드 이름이 바인딩 대상과 일치하지 않습니다.

메서드 이름이 bindFlintRepository이지만 실제로는 AuthRepository를 바인딩하고 있습니다. 일관성을 위해 메서드 이름을 변경하는 것이 좋습니다.

♻️ 제안된 수정
-    abstract fun bindFlintRepository(defaultFlintRepository: DefaultAuthRepository): AuthRepository
+    abstract fun bindAuthRepository(defaultAuthRepository: DefaultAuthRepository): AuthRepository
app/src/main/java/com/flint/presentation/login/LoginViewModel.kt (1)

13-19: 사용되지 않는 import 존재

OAuthToken (line 13)과 Locale (line 19)는 이 파일에서 사용되지 않습니다. 제거를 권장합니다.

-import com.kakao.sdk.auth.model.OAuthToken
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.launch
 import timber.log.Timber
-import java.util.Locale
 import javax.inject.Inject
app/src/main/java/com/flint/presentation/login/LoginScreen.kt (2)

3-3: 사용되지 않는 import

android.util.Log가 import되어 있지만 실제로는 Timber를 사용하고 있습니다. 제거해 주세요.


43-44: KakaoLoginManager 기본 인스턴스 생성

KakaoLoginManager()를 Composable 파라미터의 기본값으로 생성하면 테스트 시 모킹이 어려울 수 있습니다. Hilt를 통한 주입을 고려해 보세요.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c1ef569 and 6b8beda.

📒 Files selected for processing (32)
  • app/build.gradle.kts
  • app/src/main/AndroidManifest.xml
  • app/src/main/java/com/flint/FlintApplication.kt
  • app/src/main/java/com/flint/core/common/di/RepositoryModule.kt
  • app/src/main/java/com/flint/core/common/di/ServiceModule.kt
  • app/src/main/java/com/flint/core/common/util/Constants.kt
  • app/src/main/java/com/flint/core/navigation/Route.kt
  • app/src/main/java/com/flint/data/api/AuthApi.kt
  • app/src/main/java/com/flint/data/api/FlintApi.kt
  • app/src/main/java/com/flint/data/dto/request/auth/SignupRequestDto.kt
  • app/src/main/java/com/flint/data/dto/request/auth/SocialVerifyRequestDto.kt
  • app/src/main/java/com/flint/data/dto/response/auth/SignupResponseDto.kt
  • app/src/main/java/com/flint/data/dto/response/auth/SocialVerifyResponseDto.kt
  • app/src/main/java/com/flint/data/mapper/auth/SignupMapper.kt
  • app/src/main/java/com/flint/data/mapper/auth/SocialVerifyMapper.kt
  • app/src/main/java/com/flint/data/repositoryImpl/DefaultAuthRepository.kt
  • app/src/main/java/com/flint/data/repositoryImpl/DefaultFlintRepository.kt
  • app/src/main/java/com/flint/domain/model/auth/SignupModel.kt
  • app/src/main/java/com/flint/domain/model/auth/SocialVerifyModel.kt
  • app/src/main/java/com/flint/domain/repository/AuthRepository.kt
  • app/src/main/java/com/flint/domain/repository/FlintRepository.kt
  • app/src/main/java/com/flint/domain/type/ProviderType.kt
  • app/src/main/java/com/flint/presentation/login/LoginScreen.kt
  • app/src/main/java/com/flint/presentation/login/LoginViewModel.kt
  • app/src/main/java/com/flint/presentation/login/data/VerifyStatusData.kt
  • app/src/main/java/com/flint/presentation/login/manager/KakaoLoginManager.kt
  • app/src/main/java/com/flint/presentation/login/navigation/LoginNavigation.kt
  • app/src/main/java/com/flint/presentation/main/MainNavigator.kt
  • app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt
  • app/src/main/java/com/flint/presentation/splash/SplashScreen.kt
  • gradle/libs.versions.toml
  • settings.gradle.kts
💤 Files with no reviewable changes (3)
  • app/src/main/java/com/flint/data/api/FlintApi.kt
  • app/src/main/java/com/flint/data/repositoryImpl/DefaultFlintRepository.kt
  • app/src/main/java/com/flint/domain/repository/FlintRepository.kt
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-16T08:47:13.979Z
Learnt from: ckals413
Repo: imflint/Flint-Android PR: 116
File: app/src/main/java/com/flint/presentation/onboarding/OnboardingDoneScreen.kt:97-105
Timestamp: 2026-01-16T08:47:13.979Z
Learning: In OnboardingDoneScreen.kt, the "시작하기" button is intentionally set to FlintButtonState.Disable as a placeholder state until ViewModel implementation is completed.

Applied to files:

  • app/src/main/java/com/flint/presentation/login/LoginViewModel.kt
  • app/src/main/java/com/flint/presentation/splash/SplashScreen.kt
  • app/src/main/java/com/flint/presentation/main/MainNavigator.kt
  • app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt
  • app/src/main/java/com/flint/presentation/login/LoginScreen.kt
🧬 Code graph analysis (2)
app/src/main/java/com/flint/presentation/splash/SplashScreen.kt (2)
app/src/main/java/com/flint/presentation/main/MainNavigator.kt (1)
  • navigateToLogin (90-99)
app/src/main/java/com/flint/presentation/login/navigation/LoginNavigation.kt (1)
  • navigateToLogin (11-13)
app/src/main/java/com/flint/presentation/login/LoginScreen.kt (2)
app/src/main/java/com/flint/presentation/main/MainNavigator.kt (2)
  • navigateToHome (105-114)
  • navigateToOnBoarding (101-103)
app/src/main/java/com/flint/presentation/home/navigation/HomeNavigation.kt (1)
  • navigateToHome (11-13)
🔇 Additional comments (28)
settings.gradle.kts (1)

19-19: LGTM!

카카오 SDK 공식 Maven 저장소가 올바르게 추가되었습니다. 이는 카카오 SDK 의존성 해결에 필요합니다.

gradle/libs.versions.toml (1)

102-103: LGTM!

카카오 사용자 SDK 라이브러리가 버전 카탈로그에 올바르게 정의되었습니다.

app/build.gradle.kts (1)

100-101: LGTM!

카카오 사용자 SDK 의존성이 올바르게 추가되었습니다.

app/src/main/AndroidManifest.xml (1)

29-40: LGTM!

카카오 SDK의 AuthCodeHandlerActivity 설정이 올바르게 구성되었습니다. OAuth 콜백을 위한 intent-filter와 scheme 설정이 카카오 SDK 문서에 맞게 작성되었습니다.

app/src/main/java/com/flint/FlintApplication.kt (1)

27-29: LGTM! Kakao SDK 초기화 구현이 올바릅니다.

Application.onCreate()에서 Kakao SDK를 초기화하는 것은 표준 패턴이며, BuildConfig를 통해 네이티브 앱 키를 관리하는 것은 권장되는 방식입니다.

build.gradle에서 kakao.native.app.key를 local.properties에서 읽어 buildConfigField로 설정하고, manifestPlaceholder로도 주입하는 구성이 정확합니다. 민감한 정보를 local.properties에 저장하고 VCS에서 제외하는 것은 보안 모범 사례입니다.

app/src/main/java/com/flint/data/dto/request/auth/SocialVerifyRequestDto.kt (1)

6-12: LGTM!

DTO 구조가 적절하며 @Serializable@SerialName 어노테이션이 올바르게 적용되었습니다.

app/src/main/java/com/flint/domain/type/ProviderType.kt (1)

3-5: LGTM!

향후 다른 소셜 로그인 제공자(GOOGLE, APPLE 등)를 추가할 수 있도록 확장 가능한 enum 구조입니다.

app/src/main/java/com/flint/core/common/util/Constants.kt (1)

3-7: LGTM!

DataStore 키를 상수로 중앙 관리하는 것은 좋은 패턴입니다. 인증 관련 토큰 및 사용자 정보 저장에 적합한 구조입니다.

app/src/main/java/com/flint/data/dto/response/auth/SignupResponseDto.kt (1)

6-14: LGTM!

회원가입 응답 DTO가 적절하게 구성되었습니다. 모든 필드가 non-null로 선언되어 있으므로, 서버 API 응답이 항상 이 필드들을 반환하는지 확인해 주세요.

app/src/main/java/com/flint/data/dto/request/auth/SignupRequestDto.kt (1)

6-16: LGTM!

DTO 구조가 명확하고 kotlinx.serialization 컨벤션을 잘 따르고 있습니다. @SerialName 어노테이션이 프로퍼티명과 동일하지만 명시적으로 선언하여 API 계약을 명확히 한 점이 좋습니다.

app/src/main/java/com/flint/presentation/login/manager/KakaoLoginManager.kt (1)

29-37: KakaoAccount 폴백 로직 정상 구현됨

KakaoTalk이 사용 불가능한 경우 KakaoAccount로 로그인을 시도하는 폴백 로직이 올바르게 구현되어 있습니다.

app/src/main/java/com/flint/domain/model/auth/SignupModel.kt (1)

3-14: LGTM!

도메인 모델이 깔끔하게 정의되어 있습니다. DTO와 분리하여 레이어 간 경계를 명확히 유지하고 있습니다.

app/src/main/java/com/flint/data/mapper/auth/SignupMapper.kt (1)

8-23: LGTM!

매퍼 함수들이 확장 함수 패턴을 사용하여 깔끔하게 구현되어 있습니다. 필드 매핑이 정확하고 도메인 ↔ DTO 변환 로직이 명확합니다.

app/src/main/java/com/flint/presentation/login/navigation/LoginNavigation.kt (1)

15-24: 온보딩 네비게이션 계약을 토큰 기반으로 맞춘 점 좋습니다.
LoginRoutetempToken을 그대로 전달해 흐름이 일관됩니다.

app/src/main/java/com/flint/data/api/AuthApi.kt (1)

11-16: AuthApi 엔드포인트 정의가 명확합니다.
signup / socialVerify 분리가 직관적입니다.

app/src/main/java/com/flint/domain/repository/AuthRepository.kt (1)

8-10: AuthRepository 계약이 명확합니다.
Result 기반으로 에러 처리를 일관되게 구성하기 좋습니다.

app/src/main/java/com/flint/data/mapper/auth/SocialVerifyMapper.kt (2)

8-12: provider 문자열 규격을 백엔드 계약과 재확인하세요.
provider.name이 API에서 요구하는 값(대/소문자, 별칭 등)과 다르면 인증이 실패할 수 있습니다. 필요 시 명시 매핑을 고려해 주세요.


15-22: 응답 매핑이 단순하고 명확합니다.
필드가 1:1로 연결되어 있어 추적이 쉽습니다.

app/src/main/java/com/flint/presentation/main/MainNavigator.kt (2)

13-36: 시작 목적지를 Splash로 둔 변경이 로그인 플로우와 자연스럽습니다.
Route.SplashstartDestination으로 명시해 초기 진입이 명확해졌습니다.


101-102: 온보딩 이동 시 tempToken 전달이 일관적입니다.
토큰을 그대로 전달해 이후 온보딩 화면에서 활용하기 좋습니다.

app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt (1)

12-14: 네비게이션 함수 변경이 적절합니다.

tempToken을 매개변수로 받아 Route.OnboardingProfile에 전달하는 방식이 잘 구현되어 있습니다.

app/src/main/java/com/flint/domain/model/auth/SocialVerifyModel.kt (1)

5-16: 도메인 모델이 적절하게 설계되었습니다.

SocialVerifyRequestModelSocialVerifyResponseModel이 카카오 인증 플로우에 맞게 잘 정의되어 있습니다. accessToken, refreshToken, tempToken과 같은 민감한 데이터가 포함되어 있으므로, 로깅 시 마스킹 처리가 필요합니다.

app/src/main/java/com/flint/data/dto/response/auth/SocialVerifyResponseDto.kt (1)

6-18: DTO가 적절하게 구현되었습니다.

@Serializable@SerialName 어노테이션을 사용하여 API 응답 매핑이 명시적이고 안정적입니다. nullable 필드에 기본값 null을 설정하여 누락된 필드도 안전하게 처리됩니다.

app/src/main/java/com/flint/core/common/di/ServiceModule.kt (1)

14-16: DI 모듈이 올바르게 업데이트되었습니다.

FlintApi에서 AuthApi로의 전환이 적절하게 이루어졌으며, 메서드 이름(provideAuthApi)과 반환 타입이 일치합니다.

app/src/main/java/com/flint/presentation/login/LoginViewModel.kt (1)

32-47: 전체적인 인증 로직 구현 확인

인증 성공 시 토큰 저장 및 상태 emit 로직이 적절하게 구현되어 있습니다. isRegistered 여부에 따라 분기 처리하는 방식이 명확합니다.

app/src/main/java/com/flint/data/repositoryImpl/DefaultAuthRepository.kt (1)

17-25: Repository 구현 LGTM

runCatching을 사용한 에러 처리와 DTO-Model 매핑이 적절하게 구현되어 있습니다. runCatching 내부에서 발생하는 예외(예: .data가 null인 경우)도 Result.failure로 전파되어 호출부에서 적절히 처리할 수 있습니다.

app/src/main/java/com/flint/presentation/login/LoginScreen.kt (2)

56-58: tempToken이 null일 경우 빈 문자열 처리

data.tempToken ?: ""로 빈 문자열을 전달하면 온보딩 화면에서 유효하지 않은 토큰으로 인한 문제가 발생할 수 있습니다. tempToken이 필수값인지 확인이 필요합니다.

온보딩 플로우에서 빈 tempToken을 어떻게 처리하는지 확인해 주세요. 만약 필수값이라면 null 체크 후 에러 처리가 필요합니다:

if (data.tempToken.isNullOrEmpty()) {
    // 에러 처리 또는 사용자 피드백
    return@LaunchedEffect
}
navigateToOnBoarding(data.tempToken)

64-80: Kakao 로그인 플로우 통합 구현 확인

Kakao 로그인 버튼 클릭 시 KakaoLoginManager.login → 성공 시 socialVerifyWithKakao 호출 흐름이 적절하게 구현되어 있습니다.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread app/src/main/AndroidManifest.xml Outdated
Comment on lines +3 to +6
data class VerifyStatusData(
val isRegistered: Boolean,
val tempToken: String?
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "*.kt" | head -20

Repository: imflint/Flint-Android

Length of output: 1539


🏁 Script executed:

rg -n "VerifyStatusData" --type=kt

Repository: imflint/Flint-Android

Length of output: 91


🏁 Script executed:

rg -n -B 5 -A 10 "isRegistered" --type=kt | head -100

Repository: imflint/Flint-Android

Length of output: 91


🏁 Script executed:

rg "VerifyStatusData" -A 5 -B 5

Repository: imflint/Flint-Android

Length of output: 6616


🏁 Script executed:

rg "isRegistered.*false" -A 10 -B 5

Repository: imflint/Flint-Android

Length of output: 47


🏁 Script executed:

find . -path "*/login/*" -name "*.kt" | grep -E "(LoginScreen|LoginViewModel|Navigation)"

Repository: imflint/Flint-Android

Length of output: 274


🏁 Script executed:

rg "navigateToOnBoarding" -A 10 -B 5

Repository: imflint/Flint-Android

Length of output: 7093


🏁 Script executed:

rg "tempToken" -A 3 -B 3

Repository: imflint/Flint-Android

Length of output: 9994


🏁 Script executed:

find . -path "*/onboarding/*" -name "*.kt" | grep -i "route\|screen\|navigation" | head -10

Repository: imflint/Flint-Android

Length of output: 463


🏁 Script executed:

rg "OnboardingProfileRoute\|OnboardingProfileScreen" -A 15 -B 5

Repository: imflint/Flint-Android

Length of output: 47


🏁 Script executed:

cat app/src/main/java/com/flint/presentation/onboarding/OnboardingProfileScreen.kt | head -80

Repository: imflint/Flint-Android

Length of output: 376


🏁 Script executed:

cat app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt

Repository: imflint/Flint-Android

Length of output: 1549


🏁 Script executed:

rg "OnboardingProfile" -A 20 -B 5

Repository: imflint/Flint-Android

Length of output: 8553


isRegisteredfalse일 때 tempToken이 null인 상태 검토 필수.

로그인 화면에서 data.tempToken ?: ""를 사용해 null을 빈 문자열로 처리하고 있지만, 이는 문제를 감싸는 것이지 해결하는 것이 아닙니다. API 응답(SocialVerifyResponseDto)에서 isRegistered=false일 때 tempToken이 null로 반환될 수 있으며, 이 빈 문자열은 온보딩 진행 중 회원가입 API 호출 시 유효하지 않은 토큰이 됩니다.

다음 중 하나를 권장합니다:

  1. Sealed class 사용: Registered(accessToken, refreshToken, userId)NotRegistered(tempToken)로 상태를 명확히 분리
  2. 또는 null 체크 강화: isRegistered=false일 때 tempToken이 반드시 non-null임을 보장하는 검증 로직 추가
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/presentation/login/data/VerifyStatusData.kt`
around lines 3 - 6, VerifyStatusData currently mixes registration state and
tempToken allowing tempToken to be null when isRegistered is false; change the
model to make states explicit by replacing VerifyStatusData with a sealed class
(e.g., sealed class VerifyStatus { data class Registered(val accessToken:
String, val refreshToken: String, val userId: String): VerifyStatus(); data
class NotRegistered(val tempToken: String): VerifyStatus() }) or, if you prefer
keeping the data class, add validation where SocialVerifyResponseDto is mapped
(the converter/mapping function that builds VerifyStatusData) to throw/log and
reject/handle responses where isRegistered == false but tempToken == null so
onboarding never receives an empty token; update call sites that read
VerifyStatusData (login UI code using data.tempToken ?: "") to consume the new
sealed variants or rely on the validated non-null contract.

Comment on lines +49 to +62
LaunchedEffect(socialVerifyStatus) {
when(socialVerifyStatus) {
is UiState.Success -> {
val data = (socialVerifyStatus as UiState.Success<VerifyStatusData>).data

if (data.isRegistered) {
navigateToHome()
} else {
navigateToOnBoarding(data.tempToken ?: "")
}
}
else -> {}
}
}

@coderabbitai coderabbitai Bot Jan 16, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

중복 네비게이션 발생 가능성

LaunchedEffect의 key로 socialVerifyStatus를 사용하고 있어, Composable이 recomposition될 때 UiState.Success 상태가 유지된 채로 네비게이션이 다시 트리거될 수 있습니다.

🛠️ 상태 소비 후 리셋 처리 제안

ViewModel에서 네비게이션 후 상태를 리셋하는 방식을 고려해 주세요:

// LoginViewModel.kt에 추가
fun resetVerifyStatus() {
    _verifyStatus.value = UiState.Empty
}
 LaunchedEffect(socialVerifyStatus) {
     when(socialVerifyStatus) {
         is UiState.Success -> {
             val data = (socialVerifyStatus as UiState.Success<VerifyStatusData>).data

             if (data.isRegistered) {
                 navigateToHome()
             } else {
                 navigateToOnBoarding(data.tempToken ?: "")
             }
+            viewModel.resetVerifyStatus()
         }
         else -> {}
     }
 }
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/presentation/login/LoginScreen.kt` around lines
49 - 62, LaunchedEffect keyed on socialVerifyStatus can retrigger navigation on
recomposition; after handling UiState.Success in LoginScreen's LaunchedEffect
(the branch that reads (socialVerifyStatus as
UiState.Success<VerifyStatusData>).data and calls navigateToHome() or
navigateToOnBoarding(...)), call a ViewModel method to clear the status (e.g.,
viewModel.resetVerifyStatus()) so the UiState is set back to UiState.Empty and
navigation won't fire again; implement resetVerifyStatus() in the LoginViewModel
to set _verifyStatus = UiState.Empty and invoke it immediately after each
navigateToHome() / navigateToOnBoarding(...) call.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

말같지도 않은 소리하지마라

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@kimjw2003, 죄송합니다. 제 분석이 잘못되었네요. LaunchedEffect는 키 값이 변경될 때만 재실행되고, 네비게이션 후에는 화면이 컴포지션에서 벗어나기 때문에 제가 우려한 중복 네비게이션 문제는 실제로 발생하지 않을 것 같습니다. 불필요한 지적으로 번거롭게 해드려 죄송합니다.


🧠 Learnings used
Learnt from: ckals413
Repo: imflint/Flint-Android PR: 116
File: app/src/main/java/com/flint/presentation/onboarding/OnboardingDoneScreen.kt:97-105
Timestamp: 2026-01-16T08:47:13.979Z
Learning: In OnboardingDoneScreen.kt, the "시작하기" button is intentionally set to FlintButtonState.Disable as a placeholder state until ViewModel implementation is completed.

Comment on lines +43 to +45
onFailure = {
Timber.e(it)
}

@coderabbitai coderabbitai Bot Jan 16, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

실패 시 UI 상태가 업데이트되지 않음

onFailure 블록에서 로그만 남기고 _verifyStatus에 에러 상태를 emit하지 않습니다. 이로 인해 사용자는 인증 실패 시 아무런 피드백을 받지 못하고 무한 대기 상태에 빠질 수 있습니다.

🛠️ 에러 상태 emit 추가 제안
             onFailure = {
                 Timber.e(it)
+                _verifyStatus.emit(UiState.Error(it))
             }

UiState.Error 타입이 존재하는지 확인 후 적용해 주세요. 또한 LoginScreen에서 에러 상태를 처리하여 사용자에게 적절한 피드백(예: 토스트 메시지)을 제공하는 것을 권장합니다.

🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/presentation/login/LoginViewModel.kt` around
lines 43 - 45, The onFailure block currently only logs the exception with
Timber.e(it) and never updates the UI; modify the onFailure lambda in
LoginViewModel to emit an error state to _verifyStatus (e.g.,
_verifyStatus.emit(UiState.Error(...))) including the exception message or a
user-facing message, verify that UiState.Error exists (create it if missing),
and ensure LoginScreen consumes verifyStatus to show appropriate feedback
(toast/snackbar) for error states; keep the Timber.e call for logging but add
the state emission in the onFailure path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

그럼 니가 하던가

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

땡큐

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@kimjw2003, 천만에요! 에러 상태 처리를 추가하시면 사용자 경험이 더 좋아질 거예요. 궁금한 점 있으시면 언제든지 말씀해 주세요. 😊


🧠 Learnings used
Learnt from: ckals413
Repo: imflint/Flint-Android PR: 116
File: app/src/main/java/com/flint/presentation/onboarding/OnboardingDoneScreen.kt:97-105
Timestamp: 2026-01-16T08:47:13.979Z
Learning: In OnboardingDoneScreen.kt, the "시작하기" button is intentionally set to FlintButtonState.Disable as a placeholder state until ViewModel implementation is completed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the UiState implementation to see what states are available
fd -e kt UiState.kt --exec cat {}

Length of output: 268


🏁 Script executed:

#!/bin/bash
# Check LoginScreen to see how it currently handles verifyStatus states
rg -A 10 -B 2 "verifyStatus" app/src/main/java/com/flint/presentation/login/LoginScreen.kt

Length of output: 495


태스크: 로그인 실패 시 UI 상태 업데이트 구현

  • LoginViewModel의 onFailure 블록에서 UiState.Failure 상태 emit 추가
  • LoginScreen에서 Failure 상태 처리 및 Toast 메시지 표시

🧠 Learnings used
Learnt from: ckals413
Repo: imflint/Flint-Android PR: 116
File: app/src/main/java/com/flint/presentation/onboarding/OnboardingDoneScreen.kt:97-105
Timestamp: 2026-01-16T08:47:13.979Z
Learning: In OnboardingDoneScreen.kt, the "시작하기" button is intentionally set to FlintButtonState.Disable as a placeholder state until ViewModel implementation is completed.

💡 For code changes across multiple files, use @coderabbitai plan in an issue comment

Comment on lines +16 to +27
UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) return@loginWithKakaoTalk
when {
token != null -> onResult(Result.success(token))
error != null -> UserApiClient.instance.loginWithKakaoAccount(context) { token2, error2 ->
if (token2 != null) {
onResult(Result.success(token2))
} else {
onResult(Result.failure(error2 ?: Exception("Unknown error")))
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

취소 시 콜백 누락 - 호출자가 무한 대기 상태에 빠질 수 있음

Line 17에서 사용자가 로그인을 취소했을 때 onResult 콜백 없이 return하면 호출자가 결과를 받지 못해 무한 대기 상태에 빠질 수 있습니다.

또한, when 블록에서 tokenerror가 모두 null인 경우를 처리하지 않습니다.

🐛 취소 처리 및 방어적 코딩 수정 제안
 UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
-    if (error is ClientError && error.reason == ClientErrorCause.Cancelled) return@loginWithKakaoTalk
+    if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
+        onResult(Result.failure(error))
+        return@loginWithKakaoTalk
+    }
     when {
         token != null -> onResult(Result.success(token))
         error != null -> UserApiClient.instance.loginWithKakaoAccount(context) { token2, error2 ->
             if (token2 != null) {
                 onResult(Result.success(token2))
             } else {
                 onResult(Result.failure(error2 ?: Exception("Unknown error")))
             }
         }
+        else -> onResult(Result.failure(Exception("Unknown error: token and error are both null")))
     }
 }
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/presentation/login/manager/KakaoLoginManager.kt`
around lines 16 - 27, 로그인 취소 시 호출자가 무한 대기에 빠지지 않도록
UserApiClient.instance.loginWithKakaoTalk의 취소 분기에서 단순 return 대신 onResult를 호출해
취소를 알리는 실패 결과를 전달하고, when 블록 안에서도 token과 error가 둘 다 null인 경우를 방어적으로 처리해
onResult(Result.failure(...))를 호출하도록 수정하세요; 참고로 수정 위치는
UserApiClient.instance.loginWithKakaoTalk(...) 콜백의
ClientError/ClientErrorCause.Cancelled 처리와 내부 fallback인
UserApiClient.instance.loginWithKakaoAccount(...) 콜백(토큰2/에러2 처리)입니다.

Comment on lines 16 to 20
LaunchedEffect(Unit) {
viewModel.sampleSaveData()
// FIXME navigation test @ckals413
delay(2000)
navigateToLogin()
}

@coderabbitai coderabbitai Bot Jan 16, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

FIXME 주석이 있는 테스트/플레이스홀더 코드가 머지 대상에 포함되어 있습니다.

FIXME 주석이 이 코드가 테스트 목적임을 나타내고 있습니다. 현재 구현은 인증 상태와 관계없이 항상 로그인 화면으로 이동하며, viewModelnavigateToHome 파라미터가 전혀 사용되지 않고 있습니다.

프로덕션 코드에서는 ViewModel을 통해 인증 상태(토큰 유무 등)를 확인한 후 navigateToLogin() 또는 navigateToHome()으로 분기해야 합니다.

🛠️ 제안하는 구현 방향
 LaunchedEffect(Unit) {
-    // FIXME navigation test `@ckals413`
-    delay(2000)
-    navigateToLogin()
+    delay(2000)
+    val isLoggedIn = viewModel.checkAuthState()
+    if (isLoggedIn) {
+        navigateToHome()
+    } else {
+        navigateToLogin()
+    }
 }
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/presentation/splash/SplashScreen.kt` around lines
16 - 20, 현재 SplashScreen의 LaunchedEffect(…) 블록은 FIXME 테스트 코드로 delay(2000) 후 항상
navigateToLogin()만 호출하여 viewModel과 navigateToHome 파라미터를 무시하고 있습니다; 이를 고치려면
LaunchedEffect 또는 viewModel의 상태(flow/state)를 구독하여 ViewModel의 인증 상태(예:
viewModel.isAuthenticated / authState)를 확인한 뒤 인증되어 있으면 navigateToHome()을 호출하고
아니면 navigateToLogin()을 호출하도록 분기 처리하고, 필요한 경우 인증 확인이 끝날 때까지 짧은 스플래시 지연을 유지하되
하드코딩된 테스트 주석(FIXME)과 불필요한 고정 호출을 제거하세요 (참조 심볼: LaunchedEffect, viewModel,
navigateToLogin, navigateToHome).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

이런거는 달지마라 알아서 한다

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@kimjw2003, 알겠습니다. 의도적으로 작성하신 플레이스홀더 코드에 대해서는 리뷰 코멘트를 남기지 않도록 하겠습니다.


✏️ Learnings added
Learnt from: kimjw2003
Repo: imflint/Flint-Android PR: 122
File: app/src/main/java/com/flint/presentation/splash/SplashScreen.kt:16-20
Timestamp: 2026-01-16T15:56:53.763Z
Learning: In the imflint/Flint-Android repository, do not flag or comment on FIXME comments, placeholder code, or test code with TODO/FIXME markers. The team prefers to handle these intentional placeholders on their own timeline without review comments.

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.


🧠 Learnings used
Learnt from: ckals413
Repo: imflint/Flint-Android PR: 116
File: app/src/main/java/com/flint/presentation/onboarding/OnboardingDoneScreen.kt:97-105
Timestamp: 2026-01-16T08:47:13.979Z
Learning: In OnboardingDoneScreen.kt, the "시작하기" button is intentionally set to FlintButtonState.Disable as a placeholder state until ViewModel implementation is completed.

…gin-api

# Conflicts:
#	app/src/main/java/com/flint/presentation/splash/SplashScreen.kt

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app/src/main/java/com/flint/presentation/login/LoginScreen.kt`:
- Around line 73-75: The onFailure { error -> Timber.e(error) } block in
LoginScreen.kt only logs Kakao SDK login errors and does not surface feedback to
the user; update that failure handler to map SDK errors into the UI failure flow
(e.g., call into the ViewModel to emit a UiState.Failure or a dedicated
viewModel.onKakaoLoginFailure(error) method) so the UI can display a
Toast/Snackbar/error state; ensure you pass a user-friendly message
(error.message ?: "Login failed or cancelled") and reuse the existing
UiState.Failure handling used by socialVerifyWithKakao for consistent UX.
🧹 Nitpick comments (1)
app/src/main/java/com/flint/presentation/login/LoginViewModel.kt (1)

13-19: 사용되지 않는 import 존재

OAuthTokenLocale import가 코드에서 사용되지 않습니다.

♻️ 미사용 import 제거 제안
-import com.kakao.sdk.auth.model.OAuthToken
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.launch
 import timber.log.Timber
-import java.util.Locale
 import javax.inject.Inject

Comment on lines +73 to +75
}.onFailure { error ->
Timber.e(error)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

카카오 SDK 로그인 실패 시 사용자 피드백 누락

카카오 SDK 자체의 로그인 실패(예: 사용자 취소, 네트워크 오류 등)는 로그만 남기고 사용자에게 피드백을 제공하지 않습니다. ViewModel의 socialVerifyWithKakao 실패(서버 인증 실패)는 UiState.Failure로 처리되지만, SDK 레벨 실패는 별도로 처리가 필요합니다.

🛠️ SDK 실패 시 피드백 추가 제안
                 }.onFailure { error ->
                     Timber.e(error)
+                    // 사용자에게 로그인 실패 피드백 제공 (예: Toast 또는 Snackbar)
                 }
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/presentation/login/LoginScreen.kt` around lines
73 - 75, The onFailure { error -> Timber.e(error) } block in LoginScreen.kt only
logs Kakao SDK login errors and does not surface feedback to the user; update
that failure handler to map SDK errors into the UI failure flow (e.g., call into
the ViewModel to emit a UiState.Failure or a dedicated
viewModel.onKakaoLoginFailure(error) method) so the UI can display a
Toast/Snackbar/error state; ensure you pass a user-friendly message
(error.message ?: "Login failed or cancelled") and reuse the existing
UiState.Failure handling used by socialVerifyWithKakao for consistent UX.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app/src/main/java/com/flint/core/navigation/Route.kt`:
- Around line 12-15: OnboardingProfile data class currently carries tempToken
but screens/routes (OnboardingProfileRoute, OnboardingProfileScreen) do not
extract or use it and the `@Serializable` token can leak; change flow so Nav host
reads the token via
navBackStackEntry.toRoute<Route.OnboardingProfile>().tempToken and passes it
into OnboardingViewModel (or have the ViewModel read it on init), remove
tempToken from any serializable navigation state to avoid serialization leakage,
store token in OnboardingViewModel state, and ensure the ViewModel supplies the
token when building SignupRequestModel for the final signup call.

Comment on lines 12 to +15
@Serializable
data object OnboardingProfile : Route
data class OnboardingProfile(
val tempToken: String
) : Route

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for tempToken usage and any logging that might expose it
rg -n 'tempToken' -A 3 -B 3 --type=kotlin --type=java

Repository: imflint/Flint-Android

Length of output: 10309


🏁 Script executed:

#!/bin/bash
# Check for logging statements that might expose sensitive tokens
rg -n -i '(log\.|timber\.|println|print)' --type=kotlin --type=java | rg -i 'token' | head -20

Repository: imflint/Flint-Android

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Look for OnboardingProfile usage in navigation
rg -n 'OnboardingProfile' --type=kotlin --type=java -A 2 -B 2

Repository: imflint/Flint-Android

Length of output: 4631


🏁 Script executed:

#!/bin/bash
# Check for token expiration or validity checks
rg -n -i '(expir|ttl|timeout|valid.*token)' --type=kotlin --type=java | head -20

Repository: imflint/Flint-Android

Length of output: 2469


🏁 Script executed:

#!/bin/bash
# Find the Route.kt file and review its full content
find . -name "Route.kt" -type f | head -5

Repository: imflint/Flint-Android

Length of output: 119


🏁 Script executed:

#!/bin/bash
# Check OnboardingProfileScreen.kt to see how tempToken is used
cat app/src/main/java/com/flint/presentation/onboarding/OnboardingProfileScreen.kt | head -80

Repository: imflint/Flint-Android

Length of output: 3044


🏁 Script executed:

#!/bin/bash
# Check the full OnboardingNavigation to see composable parameters
cat app/src/main/java/com/flint/presentation/onboarding/navigation/OnboardingNavigation.kt

Repository: imflint/Flint-Android

Length of output: 2101


🏁 Script executed:

#!/bin/bash
# Search for any data class/parameter that receives tempToken
rg -n 'class.*tempToken|fun.*tempToken' --type=kotlin -A 3

Repository: imflint/Flint-Android

Length of output: 918


🏁 Script executed:

#!/bin/bash
# Check if tempToken is stored locally or cached
rg -n '(SharedPreferences|DataStore|saveString|save.*token)' --type=kotlin | grep -i 'temp\|token' | head -15

Repository: imflint/Flint-Android

Length of output: 647


🏁 Script executed:

#!/bin/bash
# Check how OnboardingProfileRoute extracts tempToken from the route
rg -n 'navBackStackEntry|savedStateHandle' app/src/main/java/com/flint/presentation/onboarding/ --type=kotlin -A 3

Repository: imflint/Flint-Android

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Check if tempToken is used in signup/onboarding completion
rg -n 'SignupRequestModel|SignupRequestDto' --type=kotlin -A 5 | grep -C 3 'tempToken'

Repository: imflint/Flint-Android

Length of output: 1893


🏁 Script executed:

#!/bin/bash
# Look for ViewModel in onboarding that might use tempToken
find app/src/main/java/com/flint/presentation/onboarding -name "*ViewModel*" -type f

Repository: imflint/Flint-Android

Length of output: 139


🏁 Script executed:

#!/bin/bash
# Check OnboardingDoneRoute to see if that's where signup happens
cat app/src/main/java/com/flint/presentation/onboarding/OnboardingDoneScreen.kt | head -100

Repository: imflint/Flint-Android

Length of output: 3294


🏁 Script executed:

#!/bin/bash
# Check OnboardingViewModel for tempToken usage
cat app/src/main/java/com/flint/presentation/onboarding/OnboardingViewModel.kt | head -150

Repository: imflint/Flint-Android

Length of output: 343


🏁 Script executed:

#!/bin/bash
# Check if tempToken is extracted using navBackStackEntry
rg -n 'toRoute\|getArgumentOrNull\|getArgument' app/src/main/java/com/flint/presentation/onboarding/ --type=kotlin

Repository: imflint/Flint-Android

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Look for any usage of OnboardingProfile or where tempToken might be passed
rg -n 'OnboardingProfile\|toRoute' app/src/main/java/com/flint/presentation/onboarding/ --type=kotlin -A 2

Repository: imflint/Flint-Android

Length of output: 47


네비게이션 인자로 전달된 tempToken을 화면에서 추출하지 않음

data object에서 data class로 변경하여 tempToken을 전달하는 구조는 적절하나, 다음 문제점이 있습니다:

  1. 토큰이 추출되지 않음: OnboardingProfileRouteOnboardingProfileScreentempToken 파라미터를 받지 않습니다. 네비게이션 경로에 포함된 토큰을 navBackStackEntry.toRoute<Route.OnboardingProfile>().tempToken으로 추출하여 ViewModel이나 상태로 관리해야 합니다.

  2. 보안 노출: @Serializable 애노테이션으로 인해 토큰이 네비게이션 상태에 직렬화되므로 디버그 로그, 크래시 리포트, 백스택 히스토리에 노출될 수 있습니다.

tempTokenOnboardingViewModel에서 관리하고, 최종 회원가입 요청 시 SignupRequestModel에 전달되도록 수정하세요.

🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/core/navigation/Route.kt` around lines 12 - 15,
OnboardingProfile data class currently carries tempToken but screens/routes
(OnboardingProfileRoute, OnboardingProfileScreen) do not extract or use it and
the `@Serializable` token can leak; change flow so Nav host reads the token via
navBackStackEntry.toRoute<Route.OnboardingProfile>().tempToken and passes it
into OnboardingViewModel (or have the ViewModel read it on init), remove
tempToken from any serializable navigation state to avoid serialization leakage,
store token in OnboardingViewModel state, and ensure the ViewModel supplies the
token when building SignupRequestModel for the final signup call.

@nahy-512 nahy-512 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

고생하셨습니다 굿~~

Comment on lines +65 to +75
kakaoLoginManager.login(context) { result ->
result.onSuccess { token ->
viewModel.socialVerifyWithKakao(
requestModel = SocialVerifyRequestModel(
provider = ProviderType.KAKAO,
accessToken = token.accessToken
),
)
}.onFailure { error ->
Timber.e(error)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

p2
이런 처리도 뷰모델에서 해보면 좋을까요?? context가 필요해서 조금 애매할지도

@nahy-512 nahy-512 merged commit 0e14167 into develop Jan 17, 2026
2 of 3 checks passed
@nahy-512 nahy-512 deleted the feat/#115-kakao-login-api branch January 17, 2026 10:57
@88guri

88guri commented Jan 20, 2026

Copy link
Copy Markdown

코드레빗보다 김종우

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔖 API feat - API 연동 Feat ✨ 신규 기능을 추가하거나 기존 기능의 동작, 정책을 변경

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 카카오 로그인 구현

3 participants