-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 구글 로그인 구현 #234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
feat: 구글 로그인 구현 #234
Conversation
구글로 부터 idToken을 받아와 서버에 전달하는 로직
회원가입 없이 둘러보기 텍스트 버튼 contentColor 변경 및 padding 변경사항 반영
client 패키지내에서 google/kakao LoginClient 관리
WalkthroughGoogle 로그인 기능이 추가되어 UI(버튼), 상태/프레젠터, 사이드이펙트, CredentialManager 기반 GoogleLoginClient, AuthRepository 시그니처 변경 및 Gradle 의존성/빌드 설정이 함께 도입되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as LoginUi
participant Presenter as LoginPresenter
participant SideEffect as HandleLoginSideEffects
participant GoogleClient as GoogleLoginClient
participant CredentialMgr as CredentialManager
participant AuthRepo as AuthRepository
UI->>Presenter: OnGoogleLoginButtonClick
activate Presenter
Presenter->>Presenter: isLoading = true
Presenter->>SideEffect: emit GoogleLogin
deactivate Presenter
activate SideEffect
SideEffect->>GoogleClient: loginWithGoogle(context, BuildConfig.GOOGLE_WEB_CLIENT_ID, onSuccess, onFailure)
deactivate SideEffect
activate GoogleClient
GoogleClient->>CredentialMgr: request Google ID token credential
activate CredentialMgr
CredentialMgr-->>GoogleClient: credential response / error
deactivate CredentialMgr
GoogleClient->>GoogleClient: validate & extract idToken
alt success
GoogleClient-->>SideEffect: onSuccess(idToken)
else failure
GoogleClient-->>SideEffect: onFailure(errorMessage)
end
deactivate GoogleClient
activate SideEffect
SideEffect->>Presenter: emit Login(PROVIDER_TYPE_GOOGLE, idToken)
deactivate SideEffect
activate Presenter
Presenter->>AuthRepo: login("GOOGLE", idToken)
activate AuthRepo
AuthRepo-->>Presenter: Result<Unit>
deactivate AuthRepo
Presenter->>Presenter: isLoading = false
deactivate Presenter
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45분
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (5)
feature/login/build.gradle.kts (1)
39-41:getApiKey함수가 여러 빌드 파일에서 중복되고 있습니다.
app/build.gradle.kts와core/ocr/build.gradle.kts에도 동일한 함수가 정의되어 있습니다. 또한getProperty()가 키를 찾지 못하면 null을 반환하여 빌드 실패를 유발할 수 있습니다.중복 제거와 null 처리를 위해 다음과 같이 개선할 수 있습니다:
fun getApiKey(propertyKey: String): String { - return gradleLocalProperties(rootDir, providers).getProperty(propertyKey) + return gradleLocalProperties(rootDir, providers).getProperty(propertyKey) + ?: throw GradleException("Missing property: $propertyKey in local.properties") }장기적으로는
buildSrc또는 convention plugin으로 추출하여 모든 모듈에서 재사용하는 것을 권장합니다.feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/client/KakaoLoginClient.kt (1)
26-29:.Companion.호출이 불필요합니다.Kotlin에서 companion object의 멤버는 직접 접근할 수 있으므로
UserApiClient.Companion.instance대신UserApiClient.instance로 충분합니다.- if (UserApiClient.Companion.instance.isKakaoTalkLoginAvailable(context)) { - UserApiClient.Companion.instance.loginWithKakaoTalk(context, callback = kakaoCallback) + if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) { + UserApiClient.instance.loginWithKakaoTalk(context, callback = kakaoCallback) } else { - UserApiClient.Companion.instance.loginWithKakaoAccount(context, callback = kakaoCallback) + UserApiClient.instance.loginWithKakaoAccount(context, callback = kakaoCallback) }- UserApiClient.Companion.instance.me { user, _ -> + UserApiClient.instance.me { user, _ ->Also applies to: 57-57
feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/client/GoogleLoginClient.kt (2)
25-25:.Companion.호출이 불필요합니다.
KakaoLoginClient와 마찬가지로 Companion object 멤버는 직접 접근할 수 있습니다.- val credentialManager = CredentialManager.Companion.create(context) + val credentialManager = CredentialManager.create(context)- if (credential is CustomCredential && - credential.type == GoogleIdTokenCredential.Companion.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) { + if (credential is CustomCredential && + credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) { try { - val googleIdTokenCredential = GoogleIdTokenCredential.Companion.createFrom(credential.data) + val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)Also applies to: 67-67, 69-69
43-55: 취소와 오류를 구분하는 사용자 메시지 제공을 고려해 주세요.현재 모든 예외에서 동일한
unknown_error_message를 표시합니다. 사용자가 로그인을 취소한 경우(GetCredentialCancellationException)에는 오류 메시지를 표시하지 않거나, 더 명확한 메시지를 제공하는 것이 UX에 좋습니다.} catch (e: GetCredentialCancellationException) { Logger.e("Google 로그인 취소됨, ${e.message}") - onFailure(context.getString(R.string.unknown_error_message)) + // 사용자가 취소한 경우 에러 메시지 표시 생략 또는 별도 처리 } catch (e: NoCredentialException) { Logger.e("Google 계정을 찾을 수 없음, ${e.message}") - onFailure(context.getString(R.string.unknown_error_message)) + onFailure(context.getString(R.string.no_google_account_message)) // 별도 문자열 리소스 추가 권장feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUiState.kt (1)
37-40: 상수를 사용한 좋은 접근 방식입니다.제공자 타입을 companion object의 상수로 정의하여 문자열 오타를 방지하고 일관성을 보장합니다.
선택적 개선 사항: 더 강력한 타입 안전성을 위해 enum을 고려할 수 있습니다:
enum class ProviderType(val value: String) { KAKAO("KAKAO"), GOOGLE("GOOGLE") }하지만 백엔드 API가 문자열을 기대한다면 현재의 접근 방식이 더 간단하고 실용적입니다.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
app/build.gradle.kts(2 hunks)core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/AuthRepository.kt(1 hunks)core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultAuthRepository.kt(1 hunks)core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ButtonColorStyle.kt(3 hunks)core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt(1 hunks)feature/login/build.gradle.kts(2 hunks)feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/HandleLoginSideEffects.kt(1 hunks)feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginPresenter.kt(2 hunks)feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt(1 hunks)feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUiState.kt(2 hunks)feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/client/GoogleLoginClient.kt(1 hunks)feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/client/KakaoLoginClient.kt(4 hunks)feature/login/src/main/res/drawable/ic_google.xml(1 hunks)feature/login/src/main/res/values/strings.xml(1 hunks)gradle/libs.versions.toml(2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-07-08T12:33:01.863Z
Learnt from: seoyoon513
Repo: YAPP-Github/Reed-Android PR: 32
File: core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ButtonColorStyle.kt:10-16
Timestamp: 2025-07-08T12:33:01.863Z
Learning: Reed Android 프로젝트에서 KAKAO 버튼 스타일은 디자이너가 pressed 상태 색상을 별도로 정의하지 않았기 때문에 pressed 상태에서도 동일한 Kakao 색상을 사용한다.
Applied to files:
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.ktcore/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ButtonColorStyle.kt
📚 Learning: 2025-07-20T12:34:23.786Z
Learnt from: easyhooon
Repo: YAPP-Github/Reed-Android PR: 61
File: feature/webview/build.gradle.kts:17-21
Timestamp: 2025-07-20T12:34:23.786Z
Learning: Reed-Android 프로젝트에서는 `booket.android.feature` convention plugin을 사용하여 feature 모듈들의 공통 의존성을 관리한다. 이 plugin은 Circuit, Compose, 그리고 core 모듈들의 의존성을 자동으로 포함하므로, 각 feature 모듈의 build.gradle.kts에서는 특별한 의존성(예: libs.logger, libs.kakao.auth)만 별도로 선언하면 된다.
Applied to files:
feature/login/build.gradle.ktsgradle/libs.versions.toml
📚 Learning: 2025-08-28T12:25:54.058Z
Learnt from: easyhooon
Repo: YAPP-Github/Reed-Android PR: 174
File: feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt:128-133
Timestamp: 2025-08-28T12:25:54.058Z
Learning: In BookSearchPresenter.kt, when a guest user tries to register a book and is redirected to login, the bottom sheet (isBookRegisterBottomSheetVisible) and selection state (selectedBookIsbn, selectedBookStatus) are intentionally kept open/preserved so that when the user returns from login, they can continue from where they left off without losing context.
Applied to files:
feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.ktfeature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginPresenter.ktfeature/login/src/main/kotlin/com/ninecraft/booket/feature/login/client/KakaoLoginClient.kt
📚 Learning: 2025-07-17T23:41:33.929Z
Learnt from: easyhooon
Repo: YAPP-Github/Reed-Android PR: 55
File: core/designsystem/src/main/res/drawable/ic_x_circle.xml:6-11
Timestamp: 2025-07-17T23:41:33.929Z
Learning: Reed Android 프로젝트에서는 SVG에서 vector drawable로 변환시 색상 매핑 대신 모드별 별도 아이콘 파일을 사용하는 방식을 선호한다. Figma에서 SVG export한 형태를 그대로 사용하며, 다크모드 대응이 필요할 경우 drawable-night 폴더에 별도 아이콘을 배치하는 방식을 사용한다.
Applied to files:
feature/login/src/main/res/drawable/ic_google.xml
🧬 Code graph analysis (4)
feature/login/build.gradle.kts (2)
app/build.gradle.kts (1)
getApiKey(115-117)core/ocr/build.gradle.kts (1)
getApiKey(34-36)
feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt (1)
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ReedButton.kt (1)
ReedButton(34-114)
core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultAuthRepository.kt (1)
core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/RunSuspendCatching.kt (1)
runSuspendCatching(16-30)
app/build.gradle.kts (2)
feature/login/build.gradle.kts (1)
getApiKey(39-41)core/ocr/build.gradle.kts (1)
getApiKey(34-36)
⏰ 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: Compose Stability Check
- GitHub Check: ci-build
🔇 Additional comments (15)
core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/AuthRepository.kt (1)
8-11: LGTM! 다중 제공자 지원을 위한 API 변경이 적절합니다.
providerType과token을 분리하여 KAKAO와 GOOGLE 로그인을 모두 지원할 수 있게 되었습니다. 타입 안전성을 높이려면providerType을 enum이나 sealed class로 변경하는 것도 고려해 볼 수 있지만, 현재 String 타입도 백엔드 통합 시 유연성을 제공합니다.core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ButtonColorStyle.kt (2)
11-11: LGTM! GOOGLE 버튼 스타일이 적절하게 추가되었습니다.흰색 배경(
basePrimary), 검정 텍스트(contentPrimary), 회색 테두리(borderPrimary) 조합이 Google 로그인 버튼 브랜드 가이드라인에 부합합니다.Also applies to: 21-21, 32-32, 47-47
30-30: TEXT 스타일 변경이 Google 로그인과 관련이 있는지 확인 필요.
TEXT버튼의contentColor가borderBrand에서contentTertiary로 변경되었습니다. 의도된 디자인 변경인지 확인해 주세요.core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultAuthRepository.kt (1)
21-32: LGTM! 구현이 올바르게 업데이트되었습니다.
providerType과token을LoginRequest에 적절히 전달하고 있으며,runSuspendCatching을 통한 에러 처리가 잘 적용되어 있습니다.app/build.gradle.kts (1)
35-35:GOOGLE_WEB_CLIENT_ID가 app 모듈과 feature/login 모듈 모두에 정의되어 있습니다.두 모듈에서 동일한 BuildConfig 필드를 정의하고 있습니다.
GoogleLoginClient가 feature/login 모듈에 있으므로, feature/login의 BuildConfig만 사용하고 app 모듈에서는 제거하는 것이 좋을 수 있습니다.app 모듈에서도 이 값이 필요한지 확인해 주세요. 필요하지 않다면 중복을 제거하는 것이 유지보수에 유리합니다.
Also applies to: 46-46
feature/login/src/main/res/values/strings.xml (1)
5-5: LGTM!기존
kakao_login문자열 패턴("XXX로 시작하기")과 일관성 있게 잘 추가되었습니다.feature/login/src/main/res/drawable/ic_google.xml (1)
1-26: LGTM!Google 브랜드 색상(빨강, 노랑, 파랑, 초록)이 올바르게 적용된 벡터 드로어블입니다. 24x24 뷰포트와 evenOdd 채우기 규칙이 적절히 사용되었습니다.
feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUi.kt (1)
116-137: LGTM!Google 로그인 버튼이 Kakao 버튼과 동일한 패턴(leadingIcon, fullWidth, 수평 패딩)으로 일관성 있게 구현되었습니다.
Color.Unspecified를 사용하여 다중 색상 아이콘이 올바르게 렌더링됩니다.feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginPresenter.kt (2)
88-91: LGTM!Kakao 로그인 핸들러(lines 83-86)와 동일한 패턴으로 Google 로그인 이벤트 핸들링이 구현되었습니다.
isLoading상태 관리와 사이드 이펙트 트리거가 일관성 있게 적용되었습니다.
99-119: LGTM!
authRepository.login(providerType, token)호출이 provider 기반 인증 흐름에 맞게 업데이트되었습니다.finally블록에서isLoading상태가 올바르게 리셋됩니다.feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/HandleLoginSideEffects.kt (2)
42-60: idToken vs accessToken 확인 필요Google Credential Manager에서 반환하는
idToken이 서버 API 요구사항과 일치하는지 확인이 필요합니다. PR 설명에서 "현재 서버 API가 idToken 대신 accessToken을 기대할 수 있다"고 언급되어 있습니다.Google ID Token은 사용자 인증 정보를 포함하는 JWT이고, Access Token은 Google API 호출용 토큰입니다. 서버 측에서 어떤 토큰을 기대하는지 API 명세를 확인해 주세요.
29-34: LGTM!Kakao 로그인 콜백이
providerType과token을 포함하는 새로운Login이벤트 형식으로 올바르게 업데이트되었습니다.feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/LoginUiState.kt (3)
19-19: LGTM: GoogleLogin 사이드 이펙트가 기존 패턴을 잘 따르고 있습니다.
GoogleLogin이KakaoLogin과 동일한 패턴을 사용하여 일관성이 유지됩니다. UUID를 사용한 private key는 각 사이드 이펙트 인스턴스의 고유성을 보장하여 올바른 접근입니다.
28-28: LGTM: 구글 로그인 버튼 클릭 이벤트가 올바르게 정의되었습니다.기존
OnKakaoLoginButtonClick과 동일한 패턴을 사용하여 일관성이 유지됩니다.
29-32:Login이벤트 시그니처 변경 완료 확인됨
Login이벤트가accessToken: String에서providerType: String과token: String으로 변경되어 여러 소셜 로그인 제공자를 지원할 수 있게 되었습니다. 코드베이스 전체를 검색한 결과, HandleLoginSideEffects.kt의 모든 Login 이벤트 인스턴스화가 새로운 시그니처로 올바르게 업데이트되었습니다. Kakao 로그인(providerType = PROVIDER_TYPE_KAKAO)과 Google 로그인(providerType = PROVIDER_TYPE_GOOGLE) 모두 새로운 구조를 올바르게 사용하고 있으며, 기존 시그니처는 더 이상 코드베이스에 없습니다.
| val Blue900 = Color(0xFF1F47CD) | ||
|
|
||
| val Kakao = Color(0xFFFBD300) | ||
| val Kakao = Color(0xFFFFEB00) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
카카오 색상이 공식 브랜드 가이드라인과 맞지 않음
업데이트된 색상 0xFFFFEB00이 공식 카카오 브랜드 색상과 일치하지 않습니다. 공식 카카오 브랜드 색상은 #FEE102이며, 카카오톡 로고 색상은 #ffe812입니다. 이 값들을 기반으로 올바른 색상값을 확인하고 적용해 주세요.
🤖 Prompt for AI Agents
In
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt
around line 66, the Kakao color is set to 0xFFFFEB00 which does not match the
official brand values; update the value to the official Kakao brand hex
0xFFFEE102 (or use 0xFFFFE812 where the KakaoTalk logo color is required) by
replacing the current literal with the correct 0xFFFEE102 constant for the
primary Kakao color.
feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/client/GoogleLoginClient.kt
Show resolved
Hide resolved
| ## Google Credential Manager | ||
| androidx-credentials = "1.6.0-beta03" | ||
| googleid = "1.1.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안정적인 버전 1.5.0 사용을 권고합니다.
1.6.0-beta03은 최신 버전이지만, 안정적인 1.5.0 버전이 이미 출시되었습니다. 프로덕션 환경에서는 안정적인 버전 사용을 권장합니다. 새로운 기능이 필요한 경우가 아니라면 androidx-credentials = "1.5.0"으로 변경해 주세요.
🤖 Prompt for AI Agents
In gradle/libs.versions.toml around lines 54-56, the androidx-credentials entry
uses the beta version "1.6.0-beta03"; update that entry to the stable version
"1.5.0" by replacing androidx-credentials = "1.6.0-beta03" with
androidx-credentials = "1.5.0" and leave the surrounding lines unchanged.
🔗 관련 이슈
📙 작업 설명
🧪 테스트 내역 (선택)
📸 스크린샷 또는 시연 영상 (선택)
💬 추가 설명 or 리뷰 포인트 (선택)
reference)
Credential Manager로 로그인이 안돼요. 이유는 몰라요
Summary by CodeRabbit
새 기능
구성/종속성
✏️ Tip: You can customize this high-level summary in your review settings.