Conversation
WalkthroughThis update introduces a comprehensive authentication infrastructure using social login (Kakao, Naver, Google) with secure token management and dependency injection. It adds new modules and classes for domain, data, and network layers, implements encrypted token storage, integrates the Kakao SDK, and refactors the login UI to use state-driven ViewModel logic and navigation. Gradle scripts and dependencies are updated to support these features. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant MainActivity
participant LogInViewModel
participant AuthRepository
participant SocialAuthDataSource
participant AuthRemoteDataSource
participant TokenManager
User->>MainActivity: Launch app
MainActivity->>MainActivity: Check isLoggedIn
alt Not logged in
MainActivity->>LogInViewModel: Show login screen
User->>LogInViewModel: Click social login (Kakao/Naver/Google)
LogInViewModel->>AuthRepository: login(context, socialType)
AuthRepository->>SocialAuthDataSource: login(context)
SocialAuthDataSource-->>AuthRepository: Result<AuthTokens, DataError>
alt AuthTokens success
AuthRepository->>AuthRemoteDataSource: loginWithSocial(socialType, accessToken)
AuthRemoteDataSource-->>AuthRepository: Result<LoginResult, DataError>
alt LoginResult success
AuthRepository->>TokenManager: saveTokens(accessToken, refreshToken)
AuthRepository-->>LogInViewModel: Result<LoginResult, DataError>
LogInViewModel-->>MainActivity: Update UI state (Success)
MainActivity->>MainActivity: Navigate to Home
else LoginResult error
AuthRepository-->>LogInViewModel: Error
end
else AuthTokens error
AuthRepository-->>LogInViewModel: Error
end
else Already logged in
MainActivity->>MainActivity: Navigate to Home
end
Suggested labels
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 19
🧹 Nitpick comments (29)
core/presentation/ui/src/main/java/com/hyunjung/core/presentation/ui/DataErrorToText.kt (1)
35-37: Remove theelseto keep thewhenexhaustive
BecauseDataErroris a sealed hierarchy, the compiler can warn you when a new subtype is added—but only if there is no catch-all branch.- else -> UiText.StringResource( - R.string.error_unknown - ) + // No else: compiler forces exhaustive match and reveals missing casesfeature/auth/build.gradle.kts (1)
9-11: Scope Timber to debug builds
Shipping Timber in release APKs adds a useless dependency and potential log-leaks. UsedebugImplementation.- implementation(libs.timber) + debugImplementation(libs.timber)core/model/src/main/java/com/hyunjung/core/model/SocialType.kt (1)
3-5: Consider adding a fall-back enum value (e.g.UNKNOWN)Defensive parsing of server payloads or deep-link parameters is easier when an unmapped value can be routed to
UNKNOWNrather than crashing withIllegalArgumentException.
If you decide to add it later, it will be a binary-breaking change; adding it now avoids that risk.core/model/src/main/java/com/hyunjung/core/model/LoginResult.kt (1)
3-6: Mark the data class as@Immutablefor Compose stability
LoginResultis likely exposed viaStateFlow/LiveDatato a Compose UI.
Annotating withandroidx.compose.runtime.Immutablelets the Compose runtime skip deep object comparison during recomposition, improving performance.-import package ... +import androidx.compose.runtime.Immutable + +@Immutable data class LoginResult( val user: User, val tokens: AuthTokens )core/model/src/main/java/com/hyunjung/core/model/AuthTokens.kt (1)
3-6: Potential value-class optimisationIf you foresee extra token metadata, keep as-is.
Otherwise consider an@JvmInline value class AccessToken(val value: String)&RefreshTokenfor stronger type-safety and zero-cost wrappers.core/model/src/main/java/com/hyunjung/core/model/User.kt (1)
3-8: Provide sane defaults for nullable stringsDown-stream UI often does
text = user.nickname ?: ""repeatedly.
Supplying default""here centralises that logic and removes null-checks across the codebase.data class User( val userId: Long, - val email: String?, - val nickname: String?, - val profileImage: String? + val email: String? = null, + val nickname: String? = null, + val profileImage: String? = null )settings.gradle.kts (1)
20-21: Pin repository to HTTPS & restrict groupGood: HTTPS is already used.
Safer: restrict to only Kakao groups to reduce supply-chain risk.maven { url = uri("https://devrepo.kakao.com/nexus/content/groups/public/") content { includeGroupByRegex("com\\.kakao.*") } }core/network/src/main/java/com/hyunjung/core/network/model/TokenResponse.kt (1)
1-12: LGTM! Consider security best practices for token handling.The data class implementation is clean and follows Kotlin serialization best practices. The JSON mapping with
@SerialNameis appropriate for API integration.Consider implementing the following security enhancements at the usage level:
- Ensure tokens are never logged or exposed in debug outputs
- Implement secure storage mechanisms for these tokens
- Consider token expiration validation
core/network/src/main/java/com/hyunjung/core/network/datasource/SocialAuthDataSource.kt (1)
8-10: Well-designed interface with good error handling.The interface follows clean architecture principles with proper async handling using suspend functions and Result types for error management.
Consider adding:
- KDoc documentation explaining the contract
- Generic type parameter bounds for better type safety
- Alternative without Context dependency for improved testability
+/** + * Interface for social authentication data sources. + * Provides login functionality for various social platforms. + */ interface SocialAuthDataSource { + /** + * Performs social login authentication. + * @param context Android context required for social SDK operations + * @return Result containing AuthTokens on success or DataError on failure + */ suspend fun login(context: Context): Result<AuthTokens, DataError> }feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInState.kt (1)
5-10: Well-designed state class with good default values.The state class follows UI state management best practices with clear, descriptive properties and sensible defaults.
Consider adding state validation to ensure mutual exclusivity:
isLoadingshould typically be false whenisLoggedInis trueerrorMessageshould be null whenisLoggedInis truedata class LogInState( val isLoading: Boolean = false, val isLoggedIn: Boolean = false, val user: User? = null, val errorMessage: String? = null +) { + init { + require(!(isLoggedIn && isLoading)) { "Cannot be both logged in and loading" } + require(!(isLoggedIn && errorMessage != null)) { "Cannot be logged in with error message" } + }core/network/src/main/java/com/hyunjung/core/network/model/SocialLoginRequestResponse.kt (1)
6-10: Consider renaming the class for clarity.The class name
SocialLoginRequestResponsesuggests it handles both request and response data, but it appears to be used only for request payloads. Consider renaming toSocialLoginRequestfor better clarity.@Serializable -data class SocialLoginRequestResponse( +data class SocialLoginRequest( val accessToken: String, val fcmToken: String? = null, val deviceType: String = "android" )core/network/src/main/java/com/hyunjung/core/network/token/TokenManager.kt (1)
3-8: Consider making token operations async for better performance.Token operations typically involve I/O (SharedPreferences, encryption) and should be async to avoid blocking the main thread.
interface TokenManager { - fun getAccessToken(): String? - fun getRefreshToken(): String? - fun saveTokens(accessToken: String, refreshToken: String) - fun clearTokens() + suspend fun getAccessToken(): String? + suspend fun getRefreshToken(): String? + suspend fun saveTokens(accessToken: String, refreshToken: String) + suspend fun clearTokens() }app/src/main/java/com/hyunjung/cherrydan/CherrydanApplication.kt (1)
22-28: Consider removing sensitive key logging in production.While the logging helps with debugging, consider removing or masking the Kakao app key in logs to prevent potential security issues.
// 카카오 앱키 확인 val kakaoAppKey = BuildConfig.KAKAO_NATIVE_APP_KEY -Timber.d("Kakao App Key: $kakaoAppKey") +Timber.d("Kakao App Key: ${if (kakaoAppKey.isNotEmpty()) "***configured***" else "missing"}") if (kakaoAppKey.isEmpty()) { Timber.e("Kakao App Key가 설정되지 않았습니다!") }core/network/src/main/java/com/hyunjung/core/network/token/AuthTokenManager.kt (3)
26-31: Simplify the chained edit syntax.The chained
putString()calls can be simplified for better readability.- sharedPreferences.edit { - putString(ACCESS_TOKEN_KEY, accessToken) - .putString(REFRESH_TOKEN_KEY, refreshToken) - } + sharedPreferences.edit { + putString(ACCESS_TOKEN_KEY, accessToken) + putString(REFRESH_TOKEN_KEY, refreshToken) + }
42-46: Simplify the chained edit syntax.The chained
remove()calls can be simplified for better readability.- sharedPreferences.edit { - remove(ACCESS_TOKEN_KEY) - .remove(REFRESH_TOKEN_KEY) - } + sharedPreferences.edit { + remove(ACCESS_TOKEN_KEY) + remove(REFRESH_TOKEN_KEY) + }
48-51: Consider adding hasValidTokens() to TokenManager interface.The
hasValidTokens()method is useful but not declared in theTokenManagerinterface. Consider adding it to the interface for consistency and better abstraction.Alternatively, document why this method is implementation-specific if it's intentionally not part of the interface contract.
app/src/main/java/com/hyunjung/cherrydan/navigation/AppNavigation.kt (2)
18-18: Consider using sealed classes for navigation routes.String-based navigation routes are prone to typos and hard to maintain. Consider defining a sealed class for routes to improve type safety.
sealed class AppRoute(val route: String) { object Splash : AppRoute("splash") object Login : AppRoute("login") object Home : AppRoute("home") }Then use
startDestination = AppRoute.Splash.routeandAppRoute.Login.routeinstead of string literals.
56-61: Remove commented-out code.The commented-out code should be removed to keep the codebase clean. If these are placeholders for future implementation, consider using TODO comments instead.
-// authGraph(navController) -// -// mainGraph(navController) -// -// profileGraph(navController)build-logic/convention/src/main/kotlin/com/hyunjung/cherrydan/BuildTypes.kt (1)
54-54: Clarify BASE_URL handling for multiple environments
- File:
build-logic/convention/src/main/kotlin/com/hyunjung/cherrydan/BuildTypes.kt
Lines: 54 & 62Current code:
buildConfigField("String", "BASE_URL", "\"https://cherrydan.com\"")This hardcodes the same endpoint for both debug and release. Consider introducing environment-specific values:
• Per build type:
buildTypes { debug { buildConfigField("String", "BASE_URL", "\"https://dev.cherrydan.com\"") } release { buildConfigField("String", "BASE_URL", "\"https://cherrydan.com\"") } }• Or via product flavors:
flavorDimensions("environment") productFlavors { dev { dimension "environment" buildConfigField("String", "BASE_URL", "\"https://dev.cherrydan.com\"") } staging { dimension "environment" buildConfigField("String", "BASE_URL", "\"https://staging.cherrydan.com\"") } prod { dimension "environment" buildConfigField("String", "BASE_URL", "\"https://cherrydan.com\"") } }Then reference
BuildConfig.BASE_URLin your networking layer. If you only need one endpoint today, the current setup is fine; otherwise please update to support your required environments.core/network/src/main/java/com/hyunjung/core/network/datasource/AuthRemoteDataSourceImpl.kt (1)
38-38: Consider making device type configurable.The device type is hardcoded as "android". Consider making this configurable or obtaining it from the build configuration to support different platforms or testing scenarios.
Also applies to: 50-50, 62-62
core/network/src/main/java/com/hyunjung/core/network/datasource/KakaoAuthDataSource.kt (2)
22-22: Consider internationalization for log messages.The Korean log messages might need to be internationalized if the app supports multiple languages, or consider using English for consistency with other modules.
Also applies to: 27-27, 30-30, 40-40, 61-61, 64-64, 71-71, 77-77
60-62: Review error mapping for cancelled login.Mapping cancelled login to
DataError.Network.UNAUTHORIZEDmight be confusing. Consider using a more specific error type likeDataError.Network.CANCELLEDorDataError.User.CANCELLEDif available.feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInViewModel.kt (1)
28-28: Consider Flow collection approach.Using
first()on the repository Flow might not be the best approach if the repository is designed to emit multiple values. Consider usingcollectorcollectLatestfor better Flow handling.- when (val result = authRepository.login(context, socialType).first()) { + authRepository.login(context, socialType).collect { result -> when (result) { is Result.Success -> _uiState.update { LoginUiState.Success(result.data) } is Result.Error -> _uiState.update { LoginUiState.Error(result.error) } } + }core/network/src/main/java/com/hyunjung/core/network/di/NetworkModule.kt (1)
50-58: Remove commented code or document future implementation plans.The commented code for Naver and Google auth sources should either be removed or have a clear implementation timeline documented. Keeping commented code with
NotImplementedErrorcan cause confusion.Consider removing the commented code:
- // single<SocialAuthDataSource>(named(SocialType.NAVER.name)) { - // // NaverAuthDataSource는 아직 구현되지 않았습니다. - // throw NotImplementedError("NaverAuthDataSource is not implemented yet.") - // } single<AuthRemoteDataSource> { AuthRemoteDataSourceImpl(get()) } - // single<SocialAuthDataSource>(named(SocialType.GOOGLE.name)) { - // // GoogleAuthDataSource는 아직 구현되지 않았습니다. - // throw NotImplementedError("GoogleAuthDataSource is not implemented yet.") - // }app/src/main/java/com/hyunjung/cherrydan/MainActivity.kt (1)
65-66: Implement token validation and wire up login handlers.Two issues need attention:
- The TODO indicates missing token validation logic
- Empty click handlers for social login buttons
The token validation should check for existing valid tokens to skip the login screen. The empty click handlers need to be connected to the actual login logic.
Would you like me to help implement the token validation logic or create an issue to track this?
Also applies to: 75-77
feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInScreen.kt (2)
43-43: Complete UI implementation for all LoginUiState variants.The TODO indicates that UI needs to be implemented for different states. Currently, only the loading state affects the UI.
Would you like me to help implement UI handling for all
LoginUiStatevariants (Initial, Loading, Success, Error) or create an issue to track this?
55-68: Combine LaunchedEffect blocks for better efficiency.Having two
LaunchedEffectblocks with the same key (uiState) is inefficient. Combine them into a single effect.- // 로그인 성공 시 네비게이션 - LaunchedEffect(uiState) { - if (uiState is LoginUiState.Success) { - onLoginSuccess() - } - } - - // 에러 메시지 표시 - LaunchedEffect(uiState) { - val error = (uiState as? LoginUiState.Error)?.error - error?.toString()?.let { - snackbarHostState.showSnackbar(it) - } - } + LaunchedEffect(uiState) { + when (uiState) { + is LoginUiState.Success -> onLoginSuccess() + is LoginUiState.Error -> { + uiState.error.toString().let { + snackbarHostState.showSnackbar(it) + } + } + else -> { /* Handle other states if needed */ } + } + }app/build.gradle.kts (2)
9-12: Secrets-plugin duplication – drop the manual filename override unless you really need it
secrets { defaultPropertiesFileName = "secrets.properties" }is the default behaviour of the Google Secrets-Gradle-plugin already, so the block is a no-op. Unless you plan to change the filename later, you can safely delete the wholesecrets {}stanza and trim a few lines.
25-33: Let the secrets-plugin injectKAKAO_NATIVE_APP_KEYinstead of DIY file I/OThe secrets plugin already places all keys into
project.properties. You can fetch it withproject.property("KAKAO_NATIVE_APP_KEY")and drop the manualProperties.load(..)boilerplate (plus one I/O hit).- val secretsFile = file("${rootProject.projectDir}/secrets.properties") - val kakaoKey = if (secretsFile.exists()) { - val properties = Properties() - properties.load(secretsFile.inputStream()) - properties.getProperty("KAKAO_NATIVE_APP_KEY", "") - } else { - "" - } + val kakaoKey: String = project.findProperty("KAKAO_NATIVE_APP_KEY") as? String ?: ""This keeps behaviour identical while relying on the library built for the purpose.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (49)
app/build.gradle.kts(2 hunks)app/src/main/AndroidManifest.xml(2 hunks)app/src/main/java/com/hyunjung/cherrydan/CherrydanApplication.kt(1 hunks)app/src/main/java/com/hyunjung/cherrydan/MainActivity.kt(1 hunks)app/src/main/java/com/hyunjung/cherrydan/navigation/AppNavigation.kt(1 hunks)build-logic/convention/src/main/kotlin/com/hyunjung/cherrydan/BuildTypes.kt(2 hunks)build-logic/convention/src/main/kotlin/com/hyunjung/cherrydan/ComposeDependencies.kt(1 hunks)core/common/.gitignore(1 hunks)core/common/build.gradle.kts(1 hunks)core/common/src/main/java/com/hyunjung/core/common/util/DataError.kt(1 hunks)core/common/src/main/java/com/hyunjung/core/common/util/Error.kt(1 hunks)core/common/src/main/java/com/hyunjung/core/common/util/Result.kt(2 hunks)core/data/build.gradle.kts(1 hunks)core/data/src/main/java/com/hyunjung/core/data/di/DataModule.kt(1 hunks)core/data/src/main/java/com/hyunjung/core/data/networking/HttpClientExt.kt(1 hunks)core/data/src/main/java/com/hyunjung/core/data/repository/AuthRepositoryImpl.kt(1 hunks)core/domain/build.gradle.kts(1 hunks)core/domain/src/main/java/com/hyunjung/core/domain/repository/AuthRepository.kt(1 hunks)core/domain/src/main/java/com/hyunjung/core/domain/util/Error.kt(0 hunks)core/model/build.gradle.kts(1 hunks)core/model/src/main/java/com/hyunjung/core/model/AuthTokens.kt(1 hunks)core/model/src/main/java/com/hyunjung/core/model/LoginResult.kt(1 hunks)core/model/src/main/java/com/hyunjung/core/model/MyClass.kt(0 hunks)core/model/src/main/java/com/hyunjung/core/model/SocialType.kt(1 hunks)core/model/src/main/java/com/hyunjung/core/model/User.kt(1 hunks)core/network/build.gradle.kts(1 hunks)core/network/src/main/java/com/hyunjung/core/network/datasource/AuthRemoteDataSource.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/datasource/AuthRemoteDataSourceImpl.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/datasource/KakaoAuthDataSource.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/datasource/SocialAuthDataSource.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/di/NetworkModule.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/model/ApiResponse.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/model/LoginResponse.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/model/LoginResultResponse.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/model/SocialLoginRequestResponse.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/model/TokenResponse.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/resource/AuthResource.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/token/AuthTokenManager.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/token/TokenManager.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/util/HttpClientExt.kt(1 hunks)core/presentation/ui/src/main/java/com/hyunjung/core/presentation/ui/DataErrorToText.kt(1 hunks)feature/auth/build.gradle.kts(1 hunks)feature/auth/src/main/java/com/hyunjung/feature/auth/di/AuthViewModelModule.kt(1 hunks)feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInAction.kt(0 hunks)feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInScreen.kt(3 hunks)feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInState.kt(1 hunks)feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInViewModel.kt(1 hunks)gradle/libs.versions.toml(5 hunks)settings.gradle.kts(1 hunks)
💤 Files with no reviewable changes (3)
- core/model/src/main/java/com/hyunjung/core/model/MyClass.kt
- core/domain/src/main/java/com/hyunjung/core/domain/util/Error.kt
- feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInAction.kt
🧰 Additional context used
🧬 Code Graph Analysis (4)
app/src/main/java/com/hyunjung/cherrydan/MainActivity.kt (5)
core/presentation/designsystem/src/main/java/com/hyunjung/core/presentation/designsystem/Theme.kt (1)
CherrydanTheme(24-42)feature/home/src/main/java/com/hyunjung/feature/home/navigation/HomeNavigation.kt (1)
HomeNavigation(45-118)feature/auth/src/main/java/com/hyunjung/feature/auth/splash/SplashScreen.kt (1)
SplashScreen(25-42)feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInScreen.kt (1)
LogInScreenRoot(44-78)app/src/main/java/com/hyunjung/cherrydan/navigation/AppNavigation.kt (1)
AppNavigation(12-62)
core/network/src/main/java/com/hyunjung/core/network/token/AuthTokenManager.kt (1)
core/network/src/main/java/com/hyunjung/core/network/token/TokenManager.kt (3)
getAccessToken(3-8)getAccessToken(4-4)getRefreshToken(5-5)
app/src/main/java/com/hyunjung/cherrydan/navigation/AppNavigation.kt (3)
feature/auth/src/main/java/com/hyunjung/feature/auth/splash/SplashScreen.kt (1)
SplashScreen(25-42)feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInScreen.kt (1)
LogInScreenRoot(44-78)feature/home/src/main/java/com/hyunjung/feature/home/navigation/HomeNavigation.kt (1)
HomeNavigation(45-118)
feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInScreen.kt (1)
core/presentation/designsystem/src/main/java/com/hyunjung/core/presentation/designsystem/component/CherrydanLogInButton.kt (2)
CherrydanLogInButton(70-132)CherrydanLogInOutlinedButton(134-185)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (43)
core/common/.gitignore (1)
1-1: 👍 Module-level.gitignoreis good housekeepingExcluding the local
/buildoutput prevents accidental commits of heavy, generated artifacts.
No further action needed.gradle/libs.versions.toml (3)
39-40: Pinning Kakao SDK to2.21.4– double-check transitive Play-Services conflictsKakao 2.21.4 still pulls
com.google.android.gms:play-services-auth:20.7.0.
If your project already forces a different Play-Services BOM or version, you can run intoDuplicate classor runtimeNoClassDefFoundError.Consider adding an explicit alignment or BOM import to keep Play-Services consistent.
Also applies to: 124-126
94-95:ktor-client-resourcesadded – keep the version in lock-step with core KtorAny version skew between
ktor-client-resources(declared withversion.ref = "ktor") and the rest of the Ktor stack triggers ABI mismatches at runtime.No action required as long as both refs stay on
2.3.8.Also applies to: 172-173
53-54: Firebase Firestore KTX introduced – ensure the GradlegoogleServicesplugin is appliedThe KTX artifact needs the Google services JSON processing step.
If the root or modulebuild.gradle.ktsdoes not already apply:plugins { id("com.google.gms.google-services") }add it, otherwise runtime initialisation of Firestore will fail.
Also applies to: 127-128
core/common/src/main/java/com/hyunjung/core/common/util/DataError.kt (1)
1-1: No remaining references to the old DataError packageI’ve verified with ripgrep that there are zero imports of
com.hyunjung.core.domain.util.DataError. All files already import
com.hyunjung.core.common.util.DataError, so no further updates are needed.core/data/src/main/java/com/hyunjung/core/data/networking/HttpClientExt.kt (1)
3-4: Imports updated correctly – nothing else changedThe file now references the new
core.commonlocation; signature & generic bounds remain intact.
Looks good.core/presentation/ui/src/main/java/com/hyunjung/core/presentation/ui/DataErrorToText.kt (1)
3-3: Import relocation looks good
The switch tocore.commonkeeps the presentation layer free of domain-specific deps.core/data/build.gradle.kts (1)
15-17: Dependencies look correct
core.networkand Koin are essential here and correctly added.core/model/src/main/java/com/hyunjung/core/model/SocialType.kt (1)
3-5: Add Retrofit / Moshi annotation if server payloads differIf the backend returns lowercase provider names (
"kakao","naver", …) you’ll need something like:@SerializedName("kakao") KAKAO,Adding it early prevents subtle deserialization bugs.
settings.gradle.kts (1)
18-21: Repository ordering may leak snapshot precedence
maven { url "https://devrepo.kakao.com/…" }is placed before JCenter/others, but aftermavenCentral().
If a transitive dependency exists in both Kakao repo and Maven Central with different versions, Gradle will now prefer the Kakao one. Confirm that is intentional; otherwise place it aftermavenCentral().build-logic/convention/src/main/kotlin/com/hyunjung/cherrydan/ComposeDependencies.kt (1)
10-10: LGTM! Proper architectural dependency.The addition of the core:domain dependency to the UI layer follows clean architecture principles, allowing UI components to access domain contracts and models.
feature/auth/src/main/java/com/hyunjung/feature/auth/di/AuthViewModelModule.kt (1)
7-9: LGTM! Standard Koin module implementation.The dependency injection setup correctly registers the LogInViewModel with its AuthRepository dependency using standard Koin patterns.
core/network/src/main/java/com/hyunjung/core/network/model/LoginResultResponse.kt (1)
5-9: LGTM! Well-structured network response model.The data class correctly uses
@Serializableannotation and follows good practices for modeling login response data with appropriate types.core/model/build.gradle.kts (1)
2-2: LGTM! Good build script consolidation.The use of a plugin alias improves maintainability and ensures consistent build configuration across core modules.
core/network/src/main/java/com/hyunjung/core/network/model/ApiResponse.kt (1)
5-10: LGTM! Standard API response wrapper pattern.The generic ApiResponse class follows established patterns for API response handling, providing consistent structure for status codes, messages, and typed results.
core/data/src/main/java/com/hyunjung/core/data/di/DataModule.kt (1)
9-17: DI configuration is complete – all dependencies are provided in NetworkModule.Verified in
core/network/src/main/java/com/hyunjung/core/network/di/NetworkModule.kt:
- SocialAuthDataSource named binding for
SocialType.KAKAO.name(line 46)single<AuthRemoteDataSource>→AuthRemoteDataSourceImpl(line 54)single<TokenManager>→AuthTokenManager(line 42)No missing bindings; the Koin setup is correct.
core/network/src/main/java/com/hyunjung/core/network/model/SocialLoginRequestResponse.kt (1)
7-9: Well-structured request model with appropriate defaults.The implementation correctly uses:
- Required
accessTokenfor authentication- Optional
fcmTokenfor push notifications- Sensible default for
deviceTypecore/network/src/main/java/com/hyunjung/core/network/datasource/AuthRemoteDataSource.kt (1)
8-14: Excellent interface design for remote authentication.The interface demonstrates good practices:
- Uses
suspendfor async network operations- Proper error handling with
Resulttype- Clear parameter naming and optional fcmToken
- Appropriate return type with domain model
app/src/main/AndroidManifest.xml (2)
5-6: Appropriate network permissions for authentication features.The added permissions are necessary for:
INTERNET: Network requests for authenticationACCESS_NETWORK_STATE: Checking network availability
32-43: Kakao Scheme Placeholder Configuration VerifiedThe activity configuration correctly:
- Uses the official Kakao SDK activity
- Implements proper intent filters for authentication callbacks
- Uses manifest placeholders for secure key management
The
kakaoSchemeplaceholder is defined inapp/build.gradle.kts(lines 34–35):manifestPlaceholders["kakaoScheme"] = "kakao$kakaoKey" manifestPlaceholders["kakaoKey"] = kakaoKeyNo further changes required.
app/src/main/java/com/hyunjung/cherrydan/CherrydanApplication.kt (3)
17-20: Good logging initialization with debug-only setup.Proper conditional initialization of Timber debug tree for development builds only.
30-31: Proper Kakao SDK initialization.Correct initialization with application context and build configuration key.
33-42: All referenced Koin modules are present and properly configuredVerified that each module used in CherrydanApplication is declared with valid bindings:
- feature/auth/src/main/java/com/hyunjung/feature/auth/di/AuthViewModelModule.kt
- core/data/src/main/java/com/hyunjung/core/data/di/DataModule.kt
- core/network/src/main/java/com/hyunjung/core/network/di/NetworkModule.kt
No further changes needed.
core/common/src/main/java/com/hyunjung/core/common/util/Result.kt (3)
6-7: LGTM: Error type constraint properly updated for package move.The fully qualified type constraint correctly references the new
Errorinterface location after the move tocore.common.util.
21-21: LGTM: Well-defined typealias for empty results.The
EmptyDataResulttypealias provides a clear semantic meaning forResult<Unit, E>, improving code readability.
23-26: LGTM: Well-implemented onSuccess extension function.The extension function follows functional programming best practices by:
- Using inline for performance
- Returning the original result for chaining
- Only executing the action for successful results
core/network/src/main/java/com/hyunjung/core/network/model/LoginResponse.kt (1)
8-13: LGTM: Well-structured LoginResponse data class.The data class properly uses
@Serializableannotation and has a clear structure withcode,message, andresultfields following typical API response patterns.build-logic/convention/src/main/kotlin/com/hyunjung/cherrydan/BuildTypes.kt (1)
52-55: LGTM: Clean build type configuration.The simplified
configureDebugBuildTypefunction is cleaner without theProjectparameter dependency and directly sets the BASE_URL.core/network/build.gradle.kts (3)
4-9: LGTM! Good addition of secrets management.The secrets plugin configuration is properly set up to handle sensitive configuration data like API keys and tokens.
12-12: Namespace update looks correct.The namespace follows proper Android package naming conventions for the network module.
29-44: Review dependency changes and ensure compatibility.The dependency restructuring looks appropriate for the authentication feature. The addition of Kakao SDK dependencies aligns with the PR objectives.
core/network/src/main/java/com/hyunjung/core/network/datasource/AuthRemoteDataSourceImpl.kt (1)
23-28: LGTM! Clean delegation pattern.The main method properly delegates to provider-specific implementations based on the social type.
core/network/src/main/java/com/hyunjung/core/network/resource/AuthResource.kt (1)
5-24: LGTM! Well-structured resource hierarchy.The resource structure is clean and follows REST conventions. The nested class approach with proper parent-child relationships makes the API endpoints type-safe and maintainable.
core/network/src/main/java/com/hyunjung/core/network/datasource/KakaoAuthDataSource.kt (2)
20-43: LGTM! Excellent coroutine integration and fallback handling.The implementation properly converts the callback-based Kakao SDK to suspending functions using
suspendCancellableCoroutine. The fallback from KakaoTalk app to account login is well-implemented.
45-52: Good defensive programming with continuation state checking.The
resumeIfActivemethod prevents potential crashes by checking if the continuation is still active before resuming.feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInViewModel.kt (2)
18-24: LGTM! Clean ViewModel structure with proper state management.The ViewModel follows Android architecture best practices with StateFlow for reactive UI updates and proper state encapsulation.
36-41: LGTM! Clean state definition with sealed interface.The
LoginUiStatesealed interface provides a clean and type-safe way to represent different UI states.core/network/src/main/java/com/hyunjung/core/network/di/NetworkModule.kt (1)
35-49: Well-structured network module implementation.The module setup and HTTP client configuration are comprehensive and follow best practices:
- Proper separation of concerns
- Comprehensive HTTP client configuration with logging, auth, and error handling
- Clean dependency injection setup
Also applies to: 61-99
core/data/src/main/java/com/hyunjung/core/data/repository/AuthRepositoryImpl.kt (1)
22-43: Well-implemented authentication flow.The login implementation properly orchestrates the social login flow:
- Correctly sequences social connection before backend authentication
- Properly saves tokens on success
- Maintains error information throughout the flow
app/src/main/java/com/hyunjung/cherrydan/MainActivity.kt (1)
87-90: Good integration with navigation architecture.The MainActivity changes properly support the new authentication flow with appropriate navigation setup and lifecycle logging.
Also applies to: 97-99
core/network/src/main/java/com/hyunjung/core/network/util/HttpClientExt.kt (1)
22-34: Well-designed HTTP client extensions.The extension functions provide a clean, type-safe API for HTTP operations:
- Proper use of inline functions with reified types
- Consistent error handling across all methods
- Smart URL construction that handles various input formats
Also applies to: 50-61, 106-112
feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInScreen.kt (1)
44-78: Well-structured login screen with proper state management.The refactored login screen properly integrates with the ViewModel and state management:
- Clean separation of concerns between Root and Screen composables
- Proper use of Koin for dependency injection
- State-driven UI that responds to loading states
Also applies to: 80-136
app/build.gradle.kts (1)
101-105: Remove unnecessary Kotlin stdlib dependency checkInspection of the POMs for
com.kakao.sdk:v2-auth,v2-common, andv2-user(version 2.21.4) shows noorg.jetbrains.kotlin:kotlin-stdliborkotlin-reflectentries. The Kakao SDK modules rely on the consumer’s Kotlin stdlib version only, so there’s no risk of pulling in an outdated Kotlin artifact and no need for the suggesteddependencyInsightcheck.Likely an incorrect or invalid review comment.
core/data/src/main/java/com/hyunjung/core/data/repository/AuthRepositoryImpl.kt
Show resolved
Hide resolved
core/network/src/main/java/com/hyunjung/core/network/util/HttpClientExt.kt
Show resolved
Hide resolved
| manifestPlaceholders["kakaoScheme"] = "kakao$kakaoKey" | ||
| manifestPlaceholders["kakaoKey"] = kakaoKey | ||
| } |
There was a problem hiding this comment.
Nil-safe placeholder – avoid producing an invalid scheme
If kakaoKey is empty the scheme becomes just "kakao", which will not match the redirect URI Kakao issues (kakao{APP_KEY}://oauth).
Guard against that to fail fast:
- manifestPlaceholders["kakaoScheme"] = "kakao$kakaoKey"
- manifestPlaceholders["kakaoKey"] = kakaoKey
+ require(kakaoKey.isNotBlank()) { "KAKAO_NATIVE_APP_KEY is missing" }
+ manifestPlaceholders["kakaoScheme"] = "kakao$kakaoKey"
+ manifestPlaceholders["kakaoKey"] = kakaoKey📝 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.
| manifestPlaceholders["kakaoScheme"] = "kakao$kakaoKey" | |
| manifestPlaceholders["kakaoKey"] = kakaoKey | |
| } | |
| require(kakaoKey.isNotBlank()) { "KAKAO_NATIVE_APP_KEY is missing" } | |
| manifestPlaceholders["kakaoScheme"] = "kakao$kakaoKey" | |
| manifestPlaceholders["kakaoKey"] = kakaoKey | |
| } |
🤖 Prompt for AI Agents
In app/build.gradle.kts around lines 34 to 36, the kakaoScheme placeholder is
set without checking if kakaoKey is empty, which can produce an invalid scheme.
Add a guard to check if kakaoKey is not empty before setting kakaoScheme; if
kakaoKey is empty, fail fast by throwing an error or logging a clear message to
prevent generating an invalid redirect URI.
| buildConfigField( | ||
| "String", | ||
| "BASE_URL", | ||
| "\"https://cherrydan.com\"" | ||
| ) | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Hard-coded BASE_URL couples release & staging builds
A single, immutable URL baked into all variants prevents you from pointing staging / QA builds at a different backend without another PR. Consider turning it into a variant-specific value or loading it from gradle.properties / the secrets plugin.
- buildConfigField(
- "String",
- "BASE_URL",
- "\"https://cherrydan.com\""
- )
+ // keeps release default but allows `./gradlew assembleStaging -PBASE_URL=https://staging.api`
+ val baseUrl = (project.findProperty("BASE_URL") ?: "https://cherrydan.com") as String
+ buildConfigField("String", "BASE_URL", "\"$baseUrl\"")🏁 Script executed:
#!/bin/bash
# Locate gradle.properties to see if project-level properties are already used
find . -maxdepth 2 -type f -name gradle.properties
# Inspect the exact context of buildConfigField in the app module
grep -R "buildConfigField" -n app/build.gradle.kts || true
# Check for existing flavor or build type configurations
grep -R -E "productFlavors|flavorDimensions|buildTypes" -n appLength of output: 249
Make BASE_URL configurable via project property
Hard-coding the same endpoint in all variants couples your builds to a single backend. Instead, read BASE_URL from a Gradle property (e.g. in gradle.properties or via -PBASE_URL) with a fallback.
• Location: app/build.gradle.kts (around lines 19–24)
• Steps:
- In your root
gradle.properties, add:BASE_URL=https://cherrydan.com - In
app/build.gradle.kts, replace the hard-coded field with:val baseUrl: String = (project.findProperty("BASE_URL") as? String) ?: "https://cherrydan.com" buildConfigField("String", "BASE_URL", "\"$baseUrl\"")
- Override per build when needed:
./gradlew assembleRelease -PBASE_URL=https://staging.api ./gradlew assembleDebug -PBASE_URL=https://local.api
• Optional: If you require a dedicated “staging” variant, define a staging buildType under android.buildTypes and configure it (e.g., initWith(release)) so you can run ./gradlew assembleStaging directly.
🤖 Prompt for AI Agents
In app/build.gradle.kts around lines 19 to 24, the BASE_URL is hard-coded, which
limits flexibility. Modify the code to read BASE_URL from a Gradle project
property with a fallback to the default URL. First, add
BASE_URL=https://cherrydan.com in the root gradle.properties file. Then, in
app/build.gradle.kts, replace the hard-coded buildConfigField with a variable
that reads the property using project.findProperty("BASE_URL") as a String or
defaults to the original URL. Use this variable in buildConfigField to make
BASE_URL configurable per build.
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
core/model/src/main/java/com/hyunjung/core/model/AuthTokens.kt (1)
3-11: Good implementation of token validation!The init block properly validates that both tokens are non-blank, addressing the previous review comment. The error messages are clear and descriptive.
feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInViewModel.kt (1)
27-36: Exception handling properly implemented!The try-catch block has been added as suggested in the previous review, properly handling unexpected exceptions.
🧹 Nitpick comments (3)
core/network/build.gradle.kts (1)
23-25:buildFeatures.buildConfig = trueis redundant when using the Secrets pluginAGP automatically turns on BuildConfig generation for library modules once any
buildConfigFieldis declared (or when the Secrets plugin injects fields). You can safely delete this block to trim boilerplate.feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInViewModel.kt (2)
29-29: Consider using collect instead of first() for Flow handling.Using
.first()only captures the initial emission from the Flow. If the repository emits multiple values (e.g., for retry logic or state updates), they will be missed.Consider using
collectto handle all emissions:-when (val result = authRepository.login(context, socialType).first()) { +authRepository.login(context, socialType).collect { result -> + when (result) { is Result.Success -> _uiState.update { LoginUiState.Success(result.data) } is Result.Error -> _uiState.update { LoginUiState.Error(result.error) } + } }
41-44: Use data object for singleton sealed interface members.For Kotlin 1.9+,
data objectis preferred overobjectfor sealed interface members as it provides better toString(), equals(), and hashCode() implementations.sealed interface LoginUiState { - object Idle : LoginUiState - object Loading : LoginUiState + data object Idle : LoginUiState + data object Loading : LoginUiState data class Success(val loginResult: LoginResult) : LoginUiState data class Error(val error: DataError) : LoginUiState }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
app/src/main/java/com/hyunjung/cherrydan/MainActivity.kt(1 hunks)core/model/src/main/java/com/hyunjung/core/model/AuthTokens.kt(1 hunks)core/network/build.gradle.kts(1 hunks)core/network/src/main/java/com/hyunjung/core/network/datasource/AuthRemoteDataSourceImpl.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/datasource/KakaoAuthDataSource.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/di/NetworkModule.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/model/LoginResponse.kt(1 hunks)core/network/src/main/java/com/hyunjung/core/network/token/AuthTokenManager.kt(1 hunks)feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInViewModel.kt(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- core/network/src/main/java/com/hyunjung/core/network/model/LoginResponse.kt
- core/network/src/main/java/com/hyunjung/core/network/token/AuthTokenManager.kt
- core/network/src/main/java/com/hyunjung/core/network/di/NetworkModule.kt
- core/network/src/main/java/com/hyunjung/core/network/datasource/KakaoAuthDataSource.kt
- core/network/src/main/java/com/hyunjung/core/network/datasource/AuthRemoteDataSourceImpl.kt
- app/src/main/java/com/hyunjung/cherrydan/MainActivity.kt
🔇 Additional comments (1)
core/network/build.gradle.kts (1)
28-44: Dependencies block looks solidNice job adding AndroidX Crypto, Koin, Timber, and Kakao SDKs alongside the new internal modules. Scope and versions align with their intended usage.
| alias(libs.plugins.mapsplatform.secrets.plugin) | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Avoid redundant use of the Secrets Gradle Plugin
You already apply mapsplatform.secrets.plugin, which is able to export properties directly as BuildConfig fields via defaultPropertiesFileName + buildConfigFrom DSL. Manually loading secrets.properties later duplicates this capability and increases maintenance overhead.
Quick win – let the plugin generate BASE_URL for you:
plugins {
alias(libs.plugins.hyunjung.cherrydan.android.library)
alias(libs.plugins.hyunjung.cherrydan.jvm.ktor)
- alias(libs.plugins.mapsplatform.secrets.plugin)
+ alias(libs.plugins.mapsplatform.secrets.plugin)
}
secrets {
defaultPropertiesFileName = "secrets.properties"
+ // This will automatically expose BASE_URL to BuildConfig
+ buildConfigFieldNames += listOf("BASE_URL")
}
android {This removes the need for the custom Properties() block below and keeps all secrets handling in one place.
🤖 Prompt for AI Agents
In core/network/build.gradle.kts around lines 6 to 7, the secrets.properties
file is manually loaded after applying the mapsplatform.secrets.plugin, which is
redundant. Remove the manual loading of secrets.properties and instead configure
the plugin to export the BASE_URL as a BuildConfig field using its
defaultPropertiesFileName and buildConfigFrom DSL. This centralizes secrets
management and eliminates duplicate code.
| defaultConfig { | ||
| val secrets = Properties().apply { | ||
| load(file("${rootProject.projectDir}/secrets.properties").inputStream()) | ||
| } | ||
| buildConfigField("String", "BASE_URL", "\"${secrets["BASE_URL"]}\"") | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Gracefully handle missing or malformed secrets files
Properties().load(...) will throw if the file is absent (common in CI) and secrets["BASE_URL"] may be null, embedding the string "null" in your BuildConfig. Add a fallback or fail-fast check.
- val secrets = Properties().apply {
- load(file("${rootProject.projectDir}/secrets.properties").inputStream())
- }
- buildConfigField("String", "BASE_URL", "\"${secrets["BASE_URL"]}\"")
+ val secretsFile = rootProject.file("secrets.properties")
+ val baseUrl = Properties().run {
+ if (secretsFile.exists()) load(secretsFile.inputStream())
+ getProperty("BASE_URL") ?: error("BASE_URL not found in secrets.properties")
+ }
+ buildConfigField("String", "BASE_URL", "\"$baseUrl\"")This prevents silent misconfiguration and avoids leaking "null" as a runtime URL.
🤖 Prompt for AI Agents
In core/network/build.gradle.kts around lines 16 to 21, the code loads
secrets.properties without handling missing or malformed files, which can cause
exceptions or embed "null" as the BASE_URL. Modify the code to catch exceptions
from loading the properties file and provide a fallback or fail-fast error if
the file is missing or BASE_URL is null. This ensures the build either uses a
valid URL or fails clearly instead of silently misconfiguring.
| fun login(context: Context, socialType: SocialType) { | ||
| viewModelScope.launch { | ||
| try { | ||
| _uiState.update { LoginUiState.Loading } | ||
| when (val result = authRepository.login(context, socialType).first()) { | ||
| is Result.Success -> _uiState.update { LoginUiState.Success(result.data) } | ||
| is Result.Error -> _uiState.update { LoginUiState.Error(result.error) } | ||
| } | ||
| } catch (e: Exception) { | ||
| _uiState.update { LoginUiState.Error(DataError.Network.UNKNOWN) } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Consider removing Context dependency from ViewModel.
ViewModels should be Android framework agnostic. Passing Context to the repository violates this principle and could lead to memory leaks if the Context is retained.
Consider moving the Context-dependent logic to the repository implementation or using a use case that handles Context internally.
🏁 Script executed:
#!/bin/bash
# Description: Check if Context is used elsewhere in the repository pattern
# Search for Context usage in repository interfaces
echo "=== Searching for Context in repository interfaces ==="
fd -e kt -e java | xargs rg -l "interface.*Repository" | xargs rg -A 5 -B 5 "Context"
# Check AuthRepository interface specifically
echo -e "\n=== Checking AuthRepository interface ==="
fd -e kt "AuthRepository" | xargs catLength of output: 3204
Remove Android Context from ViewModel and Domain Layer
The Context parameter is still propagated through the domain (AuthRepository) and data (AuthRepositoryImpl) layers. To make your ViewModel and domain code framework-agnostic, remove all Context dependencies and localize them to the Android–specific data sources.
• feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInViewModel.kt
– Change
diff - fun login(context: Context, socialType: SocialType) { + fun login(socialType: SocialType) { viewModelScope.launch { - when (val result = authRepository.login(context, socialType).first()) { + when (val result = authRepository.login(socialType).first()) { …
• core/domain/repository/AuthRepository.kt
– Change
diff interface AuthRepository { - fun login(context: Context, socialType: SocialType): Flow<Result<LoginResult, DataError>> + fun login(socialType: SocialType): Flow<Result<LoginResult, DataError>> }
• core/data/repository/AuthRepositoryImpl.kt
– Remove context: Context from login(...) and connectSocialAccount(...) signatures.
– Move calls like kakao.login(context) into the Android-specific SocialAuthDataSource (e.g. pass Context only to its login(context)), then have AuthRepositoryImpl.login(socialType) invoke that data source without ever taking a Context itself.
This refactoring keeps your ViewModel and domain layer free of Android framework classes, prevents accidental Context leaks, and centralizes all platform-specific logic in the data layer.
📝 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.
| fun login(context: Context, socialType: SocialType) { | |
| viewModelScope.launch { | |
| try { | |
| _uiState.update { LoginUiState.Loading } | |
| when (val result = authRepository.login(context, socialType).first()) { | |
| is Result.Success -> _uiState.update { LoginUiState.Success(result.data) } | |
| is Result.Error -> _uiState.update { LoginUiState.Error(result.error) } | |
| } | |
| } catch (e: Exception) { | |
| _uiState.update { LoginUiState.Error(DataError.Network.UNKNOWN) } | |
| } | |
| } | |
| } | |
| // feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInViewModel.kt | |
| fun login(socialType: SocialType) { | |
| viewModelScope.launch { | |
| try { | |
| _uiState.update { LoginUiState.Loading } | |
| when (val result = authRepository.login(socialType).first()) { | |
| is Result.Success -> _uiState.update { LoginUiState.Success(result.data) } | |
| is Result.Error -> _uiState.update { LoginUiState.Error(result.error) } | |
| } | |
| } catch (e: Exception) { | |
| _uiState.update { LoginUiState.Error(DataError.Network.UNKNOWN) } | |
| } | |
| } | |
| } | |
| // core/domain/repository/AuthRepository.kt | |
| interface AuthRepository { | |
| fun login(socialType: SocialType): Flow<Result<LoginResult, DataError>> | |
| } |
🤖 Prompt for AI Agents
In feature/auth/src/main/java/com/hyunjung/feature/auth/login/LogInViewModel.kt
lines 25-37, remove the Context parameter from the login function and all
related calls. Similarly, in core/domain/repository/AuthRepository.kt and
core/data/repository/AuthRepositoryImpl.kt, eliminate Context parameters from
login and connectSocialAccount methods. Move any Context-dependent calls, such
as kakao.login(context), into the Android-specific SocialAuthDataSource, passing
Context only there. Adjust AuthRepositoryImpl to call SocialAuthDataSource
without requiring Context, ensuring ViewModel and domain layers are free of
Android framework dependencies.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.github/workflows/android.yml(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
.github/workflows/android.yml (2)
23-25: Consider removing or parameterising the dummyAPI_KEY.Hard-coding
ci_dummy_keyworks, but if the build ever starts consumingAPI_KEYfor real, CI and local builds will diverge.
Either feed the real value from${{ secrets.API_KEY }}or document why the placeholder is safe.
31-34: Minor: add a newline at EOF to silence YAML-lint.The linter warning is harmless but easy to satisfy:
- run: ./gradlew build + run: ./gradlew build +
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.github/workflows/android.yml(1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.github/workflows/android.yml
[error] 34-34: no new line character at the end of file
(new-line-at-end-of-file)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (1)
.github/workflows/android.yml (1)
26-30: Fixed overwrite bug – good catch.
>>now appends the KAKAO_NATIVE_APP_KEY instead of clobbering the file, so both secrets survive.
Double-check that these secrets are defined in the repo settings; an empty string would still be written and go unnoticed at build time.
PULL REQUEST
Description
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Chores