Conversation
Walkthrough카카오 소셜 로그인 연동을 위해 SDK 초기화, Retrofit AuthService 및 AuthRepository, LoginViewModel/UI(스플래시·로그인·회원가입)와 네비게이션, DataStore 기반 TokenManager, 빌드 설정(키·의존성·레포지토리) 및 매니페스트 리디렉션 액티비티를 추가/수정했습니다. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Splash as SplashScreen
participant Login as LoginScreen
participant VM as LoginViewModel
participant Repo as AuthRepository
participant Kakao as Kakao SDK
participant AuthSvc as AuthService
participant Backend as Backend API
participant Token as TokenManager
participant Nav as NavController
User->>Splash: 앱 실행
Splash-->>Nav: 3초 후 Login으로 navigate
User->>Login: 카카오 로그인 클릭
Login->>VM: kakaoLogin(context)
VM->>Repo: loginWithKakao(context)
Repo->>Kakao: 카카오 로그인/사용자 정보 요청
Kakao-->>Repo: 사용자 ID 반환
Repo->>AuthSvc: POST /oauth2/users (oauth2Id)
AuthSvc->>Backend: 서버 요청
Backend-->>AuthSvc: AuthResponse(token,isNewUser)
AuthSvc-->>Repo: 응답 전달
Repo-->>VM: Result<AuthResponse?>
VM-->>Login: Success / Error 상태 방출
Login->>Token: saveToken(token) (성공 시)
alt isNewUser == true
Login-->>Nav: Signup으로 navigate
else
Login-->>Nav: Feed로 navigate
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 11
🔭 Outside diff range comments (1)
app/src/main/java/com/texthip/thip/ui/signin/screen/SignupNicknameScreen.kt (1)
64-65: 네비게이션 로직 누락닉네임 검증 성공 시 다음 화면으로 이동하는 네비게이션 로직이 구현되지 않았습니다. navController 파라미터를 받았지만 사용하지 않고 있습니다.
다음과 같이 네비게이션 로직을 추가하세요:
} else { showWarning = false warningMessageResId = null - // 다음 페이지로 이동 + // 다음 페이지로 이동 + navController.navigate(/* 다음 회원가입 단계 라우트 */) }
🧹 Nitpick comments (9)
settings.gradle.kts (1)
19-20: Kakao 전용 레포지토리의 Content Filter 추가로 공급망/충돌 리스크 축소Kakao Dev Repo는 퍼블릭 그룹 번들을 제공하여 광범위한 아티팩트를 노출합니다. 레포지토리 콘텐츠 필터를 적용해
com.kakao.sdk그룹으로 한정하면, 불필요한 아티팩트 해상 및 잠재적 버전 충돌/공급망 리스크를 줄일 수 있습니다.적용 제안(diff):
- maven(url = "https://devrepo.kakao.com/nexus/content/groups/public/") + maven(url = "https://devrepo.kakao.com/nexus/content/groups/public/") { + content { + includeGroup("com.kakao.sdk") + } + }app/src/main/java/com/texthip/thip/data/model/auth/request/AuthRequest.kt (1)
5-8: 요청 스키마 확장성 고려: provider 분리 검토 및 불필요한 SerialName 제거 가능
- 현재
oauth2Id에 공급자 프리픽스(kakao_...)를 포함시키는 대신, API가 허용한다면provider필드를 분리하면 확장성(구글/카카오 추가)과 서버의 명확성이 좋아집니다.- 필드명이 JSON과 동일하므로
@SerialName은 생략 가능합니다(선호/팀 컨벤션에 따름).선택적 리팩터 제안(모델 확장 예시):
enum class SocialProvider { KAKAO, GOOGLE } @Serializable data class AuthRequest( val provider: SocialProvider, val oauth2Id: String )
@SerialName제거만 적용(diff):- @SerialName("oauth2Id") val oauth2Id: String + val oauth2Id: String추가로, 위 변경 시 사용되지 않는
import kotlinx.serialization.SerialName도 제거하세요.app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt (2)
19-24: preferencesDataStore 위임 프로퍼티는 파일 최상위로 이동하는 것을 권장합니다.권장 패턴은
val Context.dataStore by preferencesDataStore(name = "...")를 파일 최상위에 두는 것입니다. 현재 @singleton으로 리스크는 낮지만, 모듈 전반에서 일관된 싱글톤 인스턴스를 보장하기 위해 관용 패턴을 따르는 것이 좋습니다.예시(파일 상단, 클래스 밖):
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "thip_auth_tokens")그리고 클래스 내부의 동일 선언은 제거하세요.
26-31: 액세스 토큰은 평문 저장 대신 암호화를 고려하세요.DataStore(Preferences)는 평문 저장입니다. 토큰 민감도에 따라 AndroidX Security Crypto(Keystore 기반)로 암호화하여 저장하거나, 최소한 전송/로그 시 마스킹을 적용하세요.
원하시면 Security Crypto를 이용한 암호화 저장 구현(마스터키 생성, AES-GCM 변환기 적용) 패치를 제안드리겠습니다. 필요하신가요?
app/src/main/java/com/texthip/thip/data/di/NetworkModule.kt (1)
5-5: 사용되지 않는 import를 제거하세요.
AuthService는 이 모듈에서 사용되지 않습니다. 정리하지 않으면 빌드 도구(ktlint/detekt) 경고를 유발할 수 있습니다.적용 diff:
-import com.texthip.thip.data.service.AuthService추가로, 인증 토큰을 다루는 요청/응답이 포함되므로
HttpLoggingInterceptor.Level.BODY는 release 빌드에서 비활성화하거나 민감정보 마스킹을 권장합니다.app/build.gradle.kts (1)
96-100: 직접 문자열 의존성 대신 버전 카탈로그로 관리하세요.Kakao SDK와 DataStore를 버전 카탈로그로 옮기면 버전/의존성 관리가 용이해집니다.
예시:
- gradle/libs.versions.toml
- [versions]에
kakao = "2.21.6",datastorePreferences = "1.1.1"추가- [libraries]에
kakao-v2-all = { module = "com.kakao.sdk:v2-all", version.ref = "kakao" }androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }- 본 파일 변경(diff):
- implementation("com.kakao.sdk:v2-all:2.21.6") + implementation(libs.kakao.v2.all) - implementation ("androidx.datastore:datastore-preferences:1.1.1") + implementation(libs.androidx.datastore.preferences)app/src/main/java/com/texthip/thip/ui/signin/screen/SignupNicknameScreen.kt (1)
54-67: TODO 주석에 따른 서버 연동 구현 필요Line 55의 TODO 주석이 있는 서버 연동 로직 구현이 필요합니다. 현재는 테스트용 시뮬레이션 코드만 있습니다.
닉네임 중복 확인 API 연동 코드를 생성하시겠습니까? 아니면 이 작업을 추적할 새 이슈를 생성하시겠습니까?
app/src/main/java/com/texthip/thip/data/repository/AuthRepository.kt (1)
60-71: 널 단언(!!) 제거 및 가독성 향상
user?.id != null체크 후user.id!!를 사용하는 패턴은 불필요한 단언입니다.let으로 안전하게 처리해 주세요.- } else if (user?.id != null) { - continuation.resume(user.id!!) + } else if (user?.id != null) { + continuation.resume(user.id)app/src/main/java/com/texthip/thip/ui/signin/screen/LoginScreen.kt (1)
54-54: 주석 정리 권장
//by 오류로 인해 변경함과 같은 이력성 주석은 혼선을 줍니다. 필요 시 커밋 메시지로 남기고 코드에서는 제거를 권장합니다.- val uiState = viewModel.uiState.collectAsStateWithLifecycle().value //by 오류로 인해 변경함 + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
.idea/gradle.xml(1 hunks)app/build.gradle.kts(3 hunks)app/src/main/AndroidManifest.xml(2 hunks)app/src/main/java/com/texthip/thip/MainActivity.kt(2 hunks)app/src/main/java/com/texthip/thip/ThipApplication.kt(1 hunks)app/src/main/java/com/texthip/thip/data/di/NetworkModule.kt(1 hunks)app/src/main/java/com/texthip/thip/data/di/ServiceModule.kt(2 hunks)app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt(1 hunks)app/src/main/java/com/texthip/thip/data/model/auth/request/AuthRequest.kt(1 hunks)app/src/main/java/com/texthip/thip/data/model/auth/response/AuthResponse.kt(1 hunks)app/src/main/java/com/texthip/thip/data/repository/AuthRepository.kt(1 hunks)app/src/main/java/com/texthip/thip/data/service/AuthService.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/navigator/routes/CommonRoutes.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/signin/screen/LoginScreen.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/signin/screen/SignupNicknameScreen.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/signin/screen/SplashScreen.kt(3 hunks)app/src/main/java/com/texthip/thip/ui/signin/viewmodel/KakaoLoginViewModel.kt(1 hunks)gradle.properties(1 hunks)gradle/libs.versions.toml(2 hunks)settings.gradle.kts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
app/src/main/java/com/texthip/thip/ui/signin/screen/LoginScreen.kt (1)
app/src/main/java/com/texthip/thip/ui/theme/Theme.kt (1)
ThipTheme(41-69)
app/src/main/java/com/texthip/thip/MainActivity.kt (8)
app/src/main/java/com/texthip/thip/ui/signin/screen/SplashScreen.kt (1)
SplashScreen(32-71)app/src/main/java/com/texthip/thip/ui/signin/screen/LoginScreen.kt (1)
LoginScreen(48-101)app/src/main/java/com/texthip/thip/ui/signin/screen/SignupNicknameScreen.kt (1)
SigninNicknameScreen(33-99)app/src/main/java/com/texthip/thip/ui/navigator/navigations/FeedNavigation.kt (1)
feedNavigation(10-23)app/src/main/java/com/texthip/thip/ui/navigator/navigations/GroupNavigation.kt (1)
groupNavigation(39-217)app/src/main/java/com/texthip/thip/ui/navigator/navigations/SearchNavigation.kt (1)
searchNavigation(9-13)app/src/main/java/com/texthip/thip/ui/navigator/navigations/MyPageNavigation.kt (1)
myPageNavigation(10-19)app/src/main/java/com/texthip/thip/ui/navigator/navigations/CommonNavigation.kt (1)
commonNavigation(14-29)
🔇 Additional comments (15)
app/src/main/java/com/texthip/thip/data/model/auth/response/AuthResponse.kt (2)
6-10: 모델 스키마 적절함 (token, isNewUser) — LGTM서버 응답 요건(신규/기존 사용자 분기, 토큰 반환)에 부합하는 간결한 모델입니다. 직렬화 애노테이션 사용도 일관적입니다.
6-10: Kotlinx Serialization 플러그인 및 Retrofit 컨버터 설정 재확인 요청
libs.versions.toml에서kotlinx-serialization-json과retrofit2-kotlinx-serialization-converter의존성 등록이 확인되었습니다.NetworkModule.kt에서json.asConverterFactory("application/json".toMediaType())호출로 컨버터도 Retrofit에 잘 적용된 것을 확인했습니다.- Gradle 스크립트(예:
plugins { id("org.jetbrains.kotlin.plugin.serialization") }또는kotlin("plugin.serialization"))에 kotlinx.serialization 플러그인이 실제로 적용되어 있는지 다시 한번 검토해 주세요.- 보안 주의: 발급된 토큰이 로그나 크래시 리포팅에 노출되지 않도록 반드시 마스킹하거나 제외해 주세요.
gradle/libs.versions.toml (1)
62-62: 라이브러리 항목 추가는 적절합니다. 다만 상단 버전 별칭을 안정 버전으로 조정 후 반영하세요.라이브러리 선언 자체는 문제 없습니다. 위 코멘트대로 버전 별칭을 안정화한 뒤 그대로 사용하면 됩니다.
app/src/main/java/com/texthip/thip/data/service/AuthService.kt (1)
9-15: BaseResponse import 경로 확인 완료: 문제 없습니다AuthService.kt에서 import한
com.texthip.thip.data.model.base.BaseResponse
가 실제 정의된 패키지(com.texthip.thip.data.model.base)와 일치하므로 별도 수정이 필요 없습니다.app/src/main/java/com/texthip/thip/ui/navigator/routes/CommonRoutes.kt (1)
10-18: 인증 관련 라우트 추가 확인Splash, Login, Signup 라우트가 적절하게 추가되었습니다. 카카오 소셜 로그인 플로우를 위한 네비게이션 구조가 잘 구성되었습니다.
app/src/main/java/com/texthip/thip/data/di/ServiceModule.kt (1)
35-39: AuthService 프로바이더 메서드 추가 확인AuthService를 제공하는 메서드가 올바르게 추가되었습니다. Retrofit을 통한 의존성 주입이 적절하게 구성되었습니다.
app/src/main/AndroidManifest.xml (2)
5-5: INTERNET 권한 추가 적절카카오 로그인 및 서버 통신을 위해 필수 권한입니다.
23-35: AuthCodeHandlerActivity 선언 적절카카오 OAuth 리다이렉트를 수신하기 위해 필요한 설정이며, exported/intent-filter 구성도 적절합니다.
app/src/main/java/com/texthip/thip/data/repository/AuthRepository.kt (2)
21-32: 카카오 로그인 → 서버 확인 플로우 구성 적절
- Kakao SDK로 사용자 ID 확보 후 서버에 신규/기존 여부 확인하는 흐름이 명확합니다.
runCatching { ... }.getOrThrow()조합으로 예외를 Result로 감싸는 처리도 타당합니다.
35-58: 카카오톡 로그인 실패 시 계정 로그인으로 안전하게 폴백하세요현재는
loginWithKakaoTalk에서 오류가 나면 즉시 예외로 종료합니다. 사용자 취소(Cancelled)가 아닌 경우에는loginWithKakaoAccount로 폴백하는 것이 권장 패턴입니다. 또한 코루틴 취소 시 콜백 이후 추가 resume 방지를 위해continuation.isActive체크도 안전합니다.
[Suggest_essential_refactor]
아래와 같이 보완을 제안합니다:@@ - UserApiClient.instance.loginWithKakaoTalk(context) { token, error -> - if (error != null) { - continuation.resumeWithException(error) - } else if (token != null) { - // 로그인 성공 시 사용자 정보 요청 - fetchUserInfo(continuation) - } - } + UserApiClient.instance.loginWithKakaoTalk(context) { token, error -> + if (error != null) { + // 사용자 취소는 그대로 에러 전달 + val isCancelled = error::class.java.name.contains("ClientError") && + (error.message ?: "").contains("Cancelled", ignoreCase = true) + if (isCancelled) { + if (continuation.isActive) continuation.resumeWithException(error) + } else { + // 그 외 오류는 카카오계정 로그인으로 폴백 + UserApiClient.instance.loginWithKakaoAccount(context) { accountToken, accountError -> + if (accountError != null) { + if (continuation.isActive) continuation.resumeWithException(accountError) + } else if (accountToken != null) { + fetchUserInfo(continuation) + } + } + } + } else if (token != null) { + fetchUserInfo(continuation) + } + }추가로, 취소 처리 시 리스너 정리를 원하시면 다음도 고려해 주세요(선택):
continuation.invokeOnCancellation { // 필요 시 콜백 기반 API 취소/정리 로직 추가 }app/src/main/java/com/texthip/thip/MainActivity.kt (1)
30-31: RootNavHost 도입과 네비게이션 모듈화 구성 좋습니다Typed routes를 활용한 그래프 구성, 인증/메인 섹션 분리 모두 명확합니다. 네비게이션 허브로의 책임도 적절합니다.
app/src/main/java/com/texthip/thip/ui/signin/screen/LoginScreen.kt (2)
92-99: 로딩 인디케이터 오버레이 처리 적절전체 화면 오버레이로 Loading 상태를 명확히 표시합니다.
71-73: popUpTo 제네릭 타입 사용 검토현재 코드에서
navigation-compose의존성 버전을 자동으로 찾을 수 없어 수동 확인이 필요합니다.
아래 사항을 확인 후 반영해 주세요.• build.gradle(.kts)에서
androidx.navigation:navigation-compose버전이 2.8.0 이상인지 확인
• 만약 2.8.0 이상이면,popUpTo도 제네릭 형태로 통일
• 2.8.0 미만이라면, 반대로 문자열 라우트 방식으로 일관되게 사용제안하는 코드 변경 예시:
- navController.navigate(destination) { - popUpTo(CommonRoutes.Login) { inclusive = true } - } + navController.navigate(destination) { + popUpTo<CommonRoutes.Login> { inclusive = true } + }app/src/main/java/com/texthip/thip/ui/signin/viewmodel/KakaoLoginViewModel.kt (2)
16-21: LoginUiState 정의 명확하고 적절Idle/Loading를 data object로, Success/Error를 data class로 분리하여 상태 표현이 깔끔합니다.
31-49: 에러/성공 결과 매핑 로직 명확
onSuccess/onFailure로 결과를 UI 상태로 전환하는 흐름이 깔끔하며, 기본 에러 메시지 폴백 처리도 적절합니다. 로그에는 민감정보가 포함되지 않도록 유지해 주세요.
| <option name="testRunner" value="CHOOSE_PER_TEST" /> | ||
| <option name="externalProjectPath" value="$PROJECT_DIR$" /> | ||
| <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" /> | ||
| <option name="gradleJvm" value="jbr-21" /> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
IDE 전용 설정(.idea) 커밋 지양 및 JDK는 Gradle Toolchain으로 관리 권장
.idea/gradle.xml의 JDK 설정은 로컬 IDE 환경 의존성이므로 VCS에 포함하지 않는 것이 좋습니다. 팀/CI 환경과의 충돌을 야기할 수 있어요. 해당 변경은 되돌리거나 .gitignore로 관리하고, JDK 버전은 Gradle Toolchain으로 일관되게 지정하는 방식을 권장합니다.
Line 9에 대해 되돌림 제안:
- <option name="gradleJvm" value="jbr-21" />
+ <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />추가 제안(다른 파일에 적용):
- Kotlin DSL 예시 (각 모듈 build.gradle.kts)
kotlin {
jvmToolchain(21)
}
android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
}🤖 Prompt for AI Agents
In .idea/gradle.xml around line 9, remove or revert the IDE-specific JDK setting
("gradleJvm" value) from version control because it ties the repo to a local IDE
configuration; instead, revert this file change (or restore the original), add
.idea/ files to .gitignore if not already ignored, and enforce the JDK version
via Gradle Toolchain in your build scripts (e.g., configure jvmToolchain/compile
options in each module) so JDK is managed consistently across developer and CI
environments.
| testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||
|
|
||
| buildConfigField("String", "BASE_URL", "\"${properties["BASE_URL"]}\"") | ||
| buildConfigField("String", "NATIVE_APP_KEY", "\"${properties["NATIVE_APP_KEY"]}\"") |
There was a problem hiding this comment.
🛠️ Refactor suggestion
local.properties 미설정 시 “null” 문자열이 주입될 수 있습니다. 강제 검증 로직으로 빌드를 fail-fast 하세요.
현재 properties["NATIVE_APP_KEY"]가 없으면 "null" 문자열이 들어갈 수 있습니다. 빌드 시점에 존재 여부를 검증하고 없으면 명시적으로 실패시키는 것이 안전합니다.
선택 범위 내 변경(diff):
- buildConfigField("String", "NATIVE_APP_KEY", "\"${properties["NATIVE_APP_KEY"]}\"")
+ buildConfigField("String", "NATIVE_APP_KEY", "\"$nativeAppKey\"")선택 범위 밖에 필요한 보조 코드(상단 프로퍼티 로드 직후):
val nativeAppKey = properties.getProperty("NATIVE_APP_KEY")
?: throw GradleException("Missing NATIVE_APP_KEY in local.properties")🤖 Prompt for AI Agents
In app/build.gradle.kts around line 30, the buildConfigField uses
properties["NATIVE_APP_KEY"] which can inject the literal "null" when the key is
absent; add a fail-fast check immediately after loading properties: read the
value with properties.getProperty("NATIVE_APP_KEY"), and if it's null throw a
GradleException("Missing NATIVE_APP_KEY in local.properties"), then use that
validated variable in buildConfigField so the build explicitly fails when the
key is not set.
| implementation(libs.kotlinx.serialization.json) | ||
| implementation(libs.coil.compose) | ||
| implementation(libs.foundation) | ||
| implementation(libs.androidx.lifecycle.runtime.compose) |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
알파 채널 의존성 사용 주의: lifecycle-runtime-compose는 안정 버전으로 정렬 권장
여기서 사용하는 libs.androidx.lifecycle.runtime.compose가 toml에서 2.10.0-alpha01로 지정되어 있습니다. 다른 라이프사이클 라이브러리와 안정 버전으로 맞추는 게 안전합니다. toml의 lifecycleRuntimeCompose 버전을 안정 버전으로 내리고, 여기 의존성은 그대로 alias를 사용하세요.
위 파일 코멘트에 남긴 웹 검색으로 최신 안정 버전을 확인해 주세요.
먼저 libs.versions.toml에서 lifecycleRuntimeCompose가 어떤 버전으로 지정되어 있는지 확인하고, 이어서 최신 안정 버전을 웹에서 조회합니다.
🏁 Script executed:
#!/bin/bash
# 버전 카탈로그 파일 경로 찾기
catalog=$(fd --hidden --ignore-case "libs.versions.toml" | head -n1)
if [[ -n "$catalog" ]]; then
echo "== $catalog 에서 lifecycleRuntimeCompose 버전 추출 =="
rg "lifecycleRuntimeCompose" -n "$catalog"
else
echo "Error: libs.versions.toml 파일을 찾을 수 없습니다."
fiLength of output: 525
🌐 Web query:
androidx.lifecycle:lifecycle-runtime-compose latest stable version
💡 Result:
The latest stable version is 2.9.2 (released July 16, 2025). (developer.android.com, mvnrepository.com)
Gradle (Groovy):
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.9.2"
Gradle (Kotlin DSL):
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.9.2")
This artifact is published on Google’s Maven repository, so ensure you have google() in your repositories. (mvnrepository.com, developer.android.com)
Would you like the Maven XML snippet or the corresponding lifecycle/viewmodel-compose version info as well?
Citations:
- 1: https://developer.android.com/jetpack/androidx/releases/lifecycle?utm_source=chatgpt.com
- 2: https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-runtime-compose/2.9.2?utm_source=chatgpt.com
- 3: https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-runtime-compose/2.9.2?utm_source=chatgpt.com
- 4: https://developer.android.com/jetpack/androidx/releases/lifecycle?utm_source=chatgpt.com
안정 버전 사용 권장: lifecycle-runtime-compose 2.9.2로 변경
아래와 같이 버전 카탈로그를 안정 버전으로 롤백하고, build.gradle.kts에서는 기존 alias 사용을 유지하세요.
• gradle/libs.versions.toml (28행)
- lifecycleRuntimeCompose = "2.10.0-alpha01"
+ lifecycleRuntimeCompose = "2.9.2"• app/build.gradle.kts (72행)
implementation(libs.androidx.lifecycle.runtime.compose)🤖 Prompt for AI Agents
In app/build.gradle.kts around line 72, keep the existing alias usage
(implementation(libs.androidx.lifecycle.runtime.compose)) but update the version
in gradle/libs.versions.toml (around line 28) to the stable
lifecycle-runtime-compose 2.9.2; edit the TOML entry to set the version to
"2.9.2" so the alias continues to resolve to the stable release without changing
build.gradle.kts.
| <meta-data | ||
| android:name="com.kakao.sdk.AppKey" | ||
| android:value="${NATIVE_APP_KEY}" /> |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Manifest placeholder 주입 경로 확인 필요 (${NATIVE_APP_KEY})
Manifest의 meta-data 값에 ${NATIVE_APP_KEY} placeholder를 사용하고 있는데, app/build.gradle(.kts)의 defaultConfig.manifestPlaceholders["NATIVE_APP_KEY"]에 실제 값이 매핑되지 않으면 런타임에 그대로 문자열로 남아 Kakao SDK 초기화가 실패합니다. BuildConfig 필드와 Manifest placeholder는 별개이므로, manifestPlaceholders를 명시적으로 설정했는지 확인해 주세요. 필요하다면 설정 스니펫 제공 가능합니다.
다음 스크립트로 설정 여부를 점검해 주세요:
🏁 Script executed:
#!/bin/bash
# manifestPlaceholders에 NATIVE_APP_KEY 정의 여부 확인
fd build.gradle.kts -a | while read -r f; do
echo ">>> $f"
rg -n "manifestPlaceholders" "$f" -A 5 -n || true
rg -n "NATIVE_APP_KEY" "$f" -A 2 -n || true
doneLength of output: 663
Manifest placeholder 설정 누락: NATIVE_APP_KEY
app/build.gradle.kts의 defaultConfig에 manifestPlaceholders가 정의되어 있지 않아, ${NATIVE_APP_KEY}가 런타임에 치환되지 않고 그대로 남습니다. 아래 위치에 매핑을 추가해주세요.
• 수정 대상
- 파일: app/build.gradle.kts
- 섹션: android { defaultConfig { … } }
• 예시 스니펫 (Kotlin DSL)
android {
defaultConfig {
// 기존 buildConfigField는 그대로 유지
buildConfigField("String", "NATIVE_APP_KEY", "\"${properties["NATIVE_APP_KEY"]}\"")
// manifestPlaceholders 설정 추가
manifestPlaceholders += mapOf(
"NATIVE_APP_KEY" to properties["NATIVE_APP_KEY"] as String
)
}
}위와 같이 설정하면 AndroidManifest.xml의
<meta-data
android:name="com.kakao.sdk.AppKey"
android:value="${NATIVE_APP_KEY}" />가 실제 앱 키로 정상 치환됩니다.
🤖 Prompt for AI Agents
In app/src/main/AndroidManifest.xml around lines 19-21 the meta-data value uses
${NATIVE_APP_KEY} but app/build.gradle.kts's android.defaultConfig is missing a
manifestPlaceholders entry so the placeholder isn't replaced at runtime; open
app/build.gradle.kts and inside android { defaultConfig { ... } } add a
manifestPlaceholders mapping that binds "NATIVE_APP_KEY" to your project
property (e.g., properties["NATIVE_APP_KEY"] as String), keeping any existing
buildConfigField entries intact so the manifest placeholder is properly
substituted at build time.
| LaunchedEffect(key1 = Unit) { | ||
| //3초 delay | ||
| delay(3000L) | ||
|
|
||
| // 로그인 화면으로 이동 | ||
| navController.navigate(CommonRoutes.Login) { | ||
| popUpTo(CommonRoutes.Splash) { | ||
| inclusive = true | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
네비게이션 타이밍 고려 사항
3초 고정 딜레이는 네트워크 상태나 초기화 시간과 무관하게 실행됩니다. 실제 초기화 작업이 3초보다 오래 걸리면 문제가 발생할 수 있습니다.
초기화 상태를 확인한 후 네비게이션하도록 개선하는 것을 고려하세요:
// ViewModel이나 Repository에서 초기화 상태를 관리하고
// 초기화 완료 시 최소 딜레이 이후 네비게이션
LaunchedEffect(key1 = Unit) {
val startTime = System.currentTimeMillis()
// 초기화 작업 수행 또는 상태 확인
val elapsedTime = System.currentTimeMillis() - startTime
val remainingDelay = maxOf(0, 3000L - elapsedTime)
delay(remainingDelay)
navController.navigate(CommonRoutes.Login) {
popUpTo(CommonRoutes.Splash) {
inclusive = true
}
}
}🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ui/signin/screen/SplashScreen.kt around
lines 36 to 46, replace the fixed 3s delay with a check of an
initialization/completion state from the ViewModel (or repository) and ensure
navigation occurs only after initialization is complete and at least the minimum
splash duration has elapsed: record start time, await the ViewModel's
initComplete flag (or suspend until initialization finishes), compute elapsed
time and delay the remaining time if any to reach 3000ms, then call
navController.navigate(CommonRoutes.Login) with the same
popUpTo(CommonRoutes.Splash){ inclusive = true } behavior.
app/src/main/java/com/texthip/thip/ui/signin/viewmodel/KakaoLoginViewModel.kt
Outdated
Show resolved
Hide resolved
| android.nonTransitiveRClass=true | ||
| android.defaults.buildfeatures.buildconfig=true No newline at end of file |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
BuildConfig 전역 속성 키 케이스 확인 필요 + 모듈 단위 명시 권장
- Line 23:
android.nonTransitiveRClass=true설정은 성능/빌드 속도 측면에서 유지 권장합니다. - Line 24:
android.defaults.buildfeatures.buildconfig=true키의 케이스가 AGP가 인식하는 형태와 다를 수 있습니다. 일반적으로는android.defaults.buildFeatures.buildConfig=true형태를 사용합니다. 케이스가 맞지 않으면 속성이 무시되어 BuildConfig가 생성되지 않을 수 있습니다. 또한 애플리케이션 모듈에서는 기본적으로 BuildConfig가 생성되므로, 필요 시 라이브러리 모듈 대상이거나 확실성을 위해 모듈의 DSL에서 명시하는 것을 권장합니다.
제안(diff):
-android.defaults.buildfeatures.buildconfig=true
+android.defaults.buildFeatures.buildConfig=true추가 제안(다른 파일에 적용 — app/build.gradle.kts 등 모듈 DSL에 명시):
android {
buildFeatures {
buildConfig = true
}
}정확한 Gradle 속성 키를 확인하기 위해 웹 검색을 요청드립니다(AGP 8+ 기준):
🌐 Web query:
What is the correct gradle.properties key to enable BuildConfig generation by default for Android Gradle Plugin 8+? Is it `android.defaults.buildFeatures.buildConfig=true`?
💡 Result:
No. For AGP 8+, the global gradle.properties key is android.defaults.buildfeatures.buildconfig=true (all lowercase, no dots between words like “buildFeatures” or “buildConfig”). However, that property is now deprecated and the default for BuildConfig is false in AGP 8, with removal planned in AGP 9.[1][5][10]
What to use instead:
- Prefer enabling per-module in the module’s build.gradle(.kts):
- Groovy:
android { buildFeatures { buildConfig = true } }[4][5] - Kotlin DSL:
android { buildFeatures { buildConfig = true } }[5]
- Groovy:
Notes:
- The older API reference pages show the global property name exactly as android.defaults.buildfeatures.buildconfig=true, but those defaults (true) are outdated; AGP 8 changed the default to false for performance.[2][10]
- Android Studio will warn that the global gradle.properties flag is deprecated and suggest migrating BuildConfig usage into build.gradle files.[1][9]
Citations:
- 1: https://www.youtube.com/watch?v=Ti4AG9GSncA
- 2: https://developer.android.com/reference/tools/gradle-api/7.4/com/android/build/api/dsl/BuildFeatures
- 3: https://docs.gradle.org/current/userguide/build_environment.html
- 4: Add AGP8 support by adding buildConfig = true to buildFeatures software-mansion/react-native-gesture-handler#2571
- 5: https://developer.android.com/reference/tools/gradle-api/8.3/null/com/android/build/api/dsl/BuildFeatures
- 6: https://developer.android.com/build
- 7: https://discuss.gradle.org/t/cert-issues-with-android-studio-gradle/48723
- 8: https://developer.android.com/build/gradle-tips
- 9: https://forum.ionicframework.com/t/problem-in-play-store-about-broadcast-reciever/243438/19
- 10: https://developer.android.com/build/releases/past-releases/agp-8-0-0-release-notes
Deprecated된 BuildConfig 전역 속성 제거 및 모듈 단위 설정 마이그레이션 권장
-
gradle.properties
android.nonTransitiveRClass=true– 성능·빌드 속도 최적화 측면에서 유지 권장android.defaults.buildfeatures.buildconfig=true– AGP 8+에서 올바른 all-lowercase 키이나 더 이상 권장되지 않고 AGP 9에서 제거 예정이므로 전역 설정 대신 모듈별 DSL로 전환하세요.
-
모듈별 build.gradle(.kts)에 아래 설정 추가:
android { buildFeatures { buildConfig = true } }
제안(diff):
- android.defaults.buildfeatures.buildconfig=true // AGP 8+에서는 deprecated, AGP 9 제거 예정🤖 Prompt for AI Agents
In gradle.properties around lines 23-24, remove the deprecated global property
"android.defaults.buildfeatures.buildconfig=true" and keep
"android.nonTransitiveRClass=true"; then migrate the BuildConfig setting into
each module's build.gradle(.kts) by adding the buildFeatures.buildConfig = true
entry inside the android { } DSL for each module that needs BuildConfig
generated. Ensure you update all module build files accordingly and delete the
global buildconfig key from gradle.properties.
| retrofit = "3.0.0" | ||
| retrofitKotlinSerializationConverter = "1.0.0" | ||
| androidxComposeNavigation = "2.8.2" | ||
| lifecycleRuntimeCompose = "2.10.0-alpha01" |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
lifecycle-runtime-compose를 알파 버전에 고정하는 것은 버전 호환성 리스크가 큽니다. 안정 버전으로 정렬하세요.
현재 lifecycle-runtime-compose를 2.10.0-alpha01로 추가했고, 다른 라이프사이클 아티팩트는 2.8.7/2.9.1을 사용 중입니다. 알파(2.10.x)와 안정(2.8.x/2.9.x)을 혼용하면 미묘한 런타임/바이너리 호환성 문제가 발생할 수 있습니다. viewmodel-compose(2.9.1)나 lifecycle-runtime-ktx(2.8.7)와 같은 계열의 안정 버전으로 정렬하는 것을 권장합니다.
최신 안정 버전을 확인해 주세요. 아래 질의를 웹 검색으로 실행해 주시면 제가 버전 정렬을 제안드리겠습니다.
🌐 Web query:
What is the latest stable version of androidx.lifecycle:lifecycle-runtime-compose?
💡 Result:
The latest stable version is 2.9.2.[1]
- MavenCentral/MvnRepository lists 2.9.2 as the most recent stable release of androidx.lifecycle:lifecycle-runtime-compose (dated Jul 16, 2025).[1]
- JetBrains’ mirrored multiplatform coordinates also show 2.9.1 as a recent stable, but 2.9.2 is newer per the official artifact listing.[3][7]
Citations:
- 1: https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-runtime-compose
- 2: https://www.nuget.org/packages/Xamarin.AndroidX.Lifecycle.Runtime.Compose/2.8.6
- 3: https://cloudsmith.com/navigator/maven/org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose-uikitsimarm64
- 4: https://developer.android.com/jetpack/androidx/releases/lifecycle
- 5: https://developer.android.com/jetpack/androidx/versions/all-channel
- 6: https://jetc.dev/issues/276
- 7: https://central.sonatype.com/artifact/org.jetbrains.androidx.lifecycle/lifecycle-runtime-compose
- 8: https://issuetracker.google.com/336842920
- 9: https://github.com/JetBrains/compose-multiplatform/releases
- 10: https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-lifecycle.html
lifecycleRuntimeCompose 버전 안정화 필요: 2.10.0-alpha01 → 2.9.2로 변경
최신 안정 릴리즈(2.9.2)[1] 사용을 권장드립니다. 알파(2.10.x)와 안정(2.8.x/2.9.x)를 혼용할 경우 런타임/바이너리 호환성 문제가 발생할 수 있습니다.
- 파일: gradle/libs.versions.toml
- 변경 전:
lifecycleRuntimeCompose = "2.10.0-alpha01" - 변경 후:
lifecycleRuntimeCompose = "2.9.2"
- 변경 전:
[1] https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-runtime-compose
🤖 Prompt for AI Agents
In gradle/libs.versions.toml around line 28, the lifecycleRuntimeCompose
dependency is pinned to an alpha release ("2.10.0-alpha01"); change it to the
stable release "2.9.2" to avoid runtime/binary compatibility issues by replacing
the version string accordingly so the file reads lifecycleRuntimeCompose =
"2.9.2".
There was a problem hiding this comment.
Actionable comments posted: 4
🔭 Outside diff range comments (3)
app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt (3)
62-67: 단발 조회(getTempToken)에도 예외 복구 로직을 동일하게 적용하세요.
first()이전의 스트림에catch를 붙여 IO 에러로 인한 크래시를 방지하세요.적용 diff:
- suspend fun getTempToken(): String? { - return context.dataStore.data.map { prefs -> - prefs[TEMP_TOKEN_KEY] - }.first() // Flow에서 첫 번째 값을 한번만 읽어옴 - } + suspend fun getTempToken(): String? { + return context.dataStore.data + .catch { e -> if (e is IOException) emit(emptyPreferences()) else throw e } + .map { prefs -> prefs[TEMP_TOKEN_KEY] } + .first() + }
78-82: getAccessToken도 동일하게 예외 복구를 적용하고, 반환 타입 표기를 import된 Flow로 일관화하세요.현재
kotlinx.coroutines.flow.Flow로 FQCN을 사용하고 있습니다. 상단에Flowimport가 있으므로 일관되게Flow<String?>로 표기하세요. 또한catch로 IO 예외를 복구하세요.적용 diff:
- fun getAccessToken(): kotlinx.coroutines.flow.Flow<String?> { - return context.dataStore.data.map { prefs -> - prefs[ACCESS_TOKEN_KEY] - } - } + fun getAccessToken(): Flow<String?> { + return context.dataStore.data + .catch { e -> if (e is IOException) emit(emptyPreferences()) else throw e } + .map { prefs -> prefs[ACCESS_TOKEN_KEY] } + }
48-53: 중복 companion object 제거 안내위 코멘트 적용 시(상단 companion으로 키 통합), 본 블록은 삭제해야 합니다. 그대로 두면 컴파일 에러가 납니다.
♻️ Duplicate comments (1)
app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt (1)
36-41: DataStore 스트림 예외 처리(catch) 누락 — IOException 시 크래시 방지 로직 추가 권장이전에 동일 지적이 있었습니다.
dataStore.data는 IO 시 예외를 던질 수 있습니다.catch로IOException을 복구하고 그 외 예외는 재던지세요.적용 diff:
- fun getToken(): Flow<String?> { - return context.dataStore.data.map { prefs -> - prefs[APP_TOKEN_KEY] - } - } + fun getToken(): Flow<String?> { + return context.dataStore.data + .catch { e -> if (e is IOException) emit(emptyPreferences()) else throw e } + .map { prefs -> prefs[APP_TOKEN_KEY] } + }선택 범위 외 필요한 import:
import java.io.IOException import kotlinx.coroutines.flow.catch import androidx.datastore.preferences.core.emptyPreferences
🧹 Nitpick comments (5)
app/src/main/java/com/texthip/thip/ui/navigator/routes/CommonRoutes.kt (2)
10-17: 하위 타입의 @serializable 중복 표기는 선택 사항입니다sealed base(
CommonRoutes)가@Serializable이면 직계 하위 타입은 별도 표기 없이도 직렬화 지원이 됩니다. 중복 표기를 줄여 간결하게 갈 수 있어요. 변경 시 아래처럼 정리 가능합니다(선택 사항).- @Serializable data object Splash : CommonRoutes() - @Serializable data object Login : CommonRoutes() - @Serializable data object Signup : CommonRoutes()
10-17: 릴리즈 빌드 난독화 대비 ProGuard/R8 룰 추가 권장현재 확인 결과:
- app/proguard-rules.pro: 경로 타입 보존(keepnames) 관련 룰 미등록
- app/build.gradle.kts:
isMinifyEnabled = false(난독화 비활성화)
▶️ 향후 릴리즈 빌드에서 난독화를 활성화(isMinifyEnabled = true)할 경우,@Serializable데이터 객체와CommonRoutes타입 이름(FQCN)이 보존되도록 아래 룰을 추가하시길 권장합니다.# Kotlinx Serialization/Typed Navigation 안전장치 -keepattributes *Annotation*, InnerClasses, EnclosingMethod -keep class kotlinx.serialization.** { *; } -keepclassmembers class **$serializer { *; } -keep @kotlinx.serialization.Serializable class ** { *; } # 라우트 타입 이름 보존 (패키지 경로는 필요에 맞게 조정) -keepnames class com.texthip.thip.ui.navigator.routes.** { *; }app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt (2)
10-10: 추가 import 정리 제안예외 복구를 적용하려면 아래 import가 필요합니다. 또한 FQCN 대신 이미 import된
Flow타입을 일관되게 사용하세요.선택 범위 외 필요한 import:
import java.io.IOException import kotlinx.coroutines.flow.catch import androidx.datastore.preferences.core.emptyPreferences
1-90: 보안/설계 권고: 토큰은 암호화 저장 고려Access/Refresh Token은 민감 정보입니다. Preferences DataStore는 기본적으로 평문 저장이므로, 다음 중 하나를 고려하세요.
- Jetpack Security Crypto(EncryptedSharedPreferences)로 토큰을 암호화 저장
- Proto DataStore + AES/GCM 변환기(Transform) 적용
- 최소한 파일 시스템 접근 위험을 낮추기 위한 OS 레벨 보호 + 앱 백업 제외 설정
또한 메서드 네이밍을 명확히 해 혼동을 줄이세요:
getToken→getAppToken(기존 레거시 토큰이라면 @deprecated로 명시)- 사용되는 토큰 타입과 라우팅(신규/기존 회원)에 대한 KDoc 주석을 추가해 의도를 문서화
필요 시, 위 암호화/주석/네이밍 일괄 패치를 제안 드릴 수 있습니다.
app/src/main/java/com/texthip/thip/ThipApplication.kt (1)
3-7: 초기화 실패 시 안전한 처리와 로깅 정비, 빈 키 방어 추가 제안try-catch 적용은 적절합니다. 다만 다음 3가지를 보완하면 현장 안정성이 높아집니다.
- printStackTrace 대신 Log.e(또는 Crashlytics)로 에러를 기록
- BuildConfig.NATIVE_APP_KEY가 빈 문자열/누락인 경우 조기 반환(불필요한 예외 방지)
- Application을 전달할 때 applicationContext를 명시(의도 명확화)
아래처럼 변경을 제안드립니다.
@@ -import com.kakao.sdk.common.KakaoSdk +import com.kakao.sdk.common.KakaoSdk +import android.util.Log @@ - // 카카오 SDK 초기화 - try { - KakaoSdk.init(this, BuildConfig.NATIVE_APP_KEY) - }catch (e: Exception){ - e.printStackTrace() - } + // 카카오 SDK 초기화 + if (BuildConfig.NATIVE_APP_KEY.isBlank()) { + Log.e("ThipApplication", "NATIVE_APP_KEY가 비어 있어 Kakao SDK 초기화를 건너뜁니다.") + return + } + try { + KakaoSdk.init(applicationContext, BuildConfig.NATIVE_APP_KEY) + } catch (e: Exception) { + Log.e("ThipApplication", "Kakao SDK 초기화 실패: ${e.message}", e) + }추가로, 로그인 흐름에서 SDK 준비 상태를 확인할 수 있도록 플래그를 노출하는 것도 권장합니다(선택). 클래스 내부에 다음을 두고, 성공/실패 지점에서 값을 설정하세요.
companion object { @Volatile var isKakaoSdkInitialized: Boolean = false private const val TAG = "ThipApplication" }그리고 위 diff에서 Log 태그 문자열 대신 TAG를 사용하면 더 일관됩니다.
필요하시면 위 변경을 반영한 전체 파일 패치를 준비해 드릴게요.
Also applies to: 14-20
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (10)
app/build.gradle.kts(3 hunks)app/src/main/AndroidManifest.xml(2 hunks)app/src/main/java/com/texthip/thip/MainActivity.kt(2 hunks)app/src/main/java/com/texthip/thip/ThipApplication.kt(1 hunks)app/src/main/java/com/texthip/thip/data/di/ServiceModule.kt(2 hunks)app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/navigator/routes/CommonRoutes.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/signin/screen/SignupNicknameScreen.kt(1 hunks)app/src/main/java/com/texthip/thip/ui/signin/viewmodel/KakaoLoginViewModel.kt(1 hunks)gradle/libs.versions.toml(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- app/src/main/java/com/texthip/thip/ui/signin/screen/SignupNicknameScreen.kt
- app/build.gradle.kts
- app/src/main/java/com/texthip/thip/ui/signin/viewmodel/KakaoLoginViewModel.kt
- gradle/libs.versions.toml
- app/src/main/java/com/texthip/thip/data/di/ServiceModule.kt
- app/src/main/AndroidManifest.xml
- app/src/main/java/com/texthip/thip/MainActivity.kt
🔇 Additional comments (5)
app/src/main/java/com/texthip/thip/ui/navigator/routes/CommonRoutes.kt (2)
10-17: 타입드 네비게이션 라우트 추가 좋습니다Kotlinx Serialization 기반의 typed destination 패턴에 맞춰 Splash/Login/Signup을
@Serializable data object로 확장한 점이 적절합니다. 기존CommonRoutes체계와도 일관성이 있습니다.
21-21: 말미 개행 추가 변경 사항은 무해합니다파일 말미 개행 추가/정리는 기능에 영향 없습니다. 현재 상태 유지해도 좋습니다.
app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt (2)
29-34: LGTM — 토큰 저장 로직 적절합니다.
edit {}사용과 키 접근 모두 정상입니다.
84-89: LGTM — 전체 토큰 삭제(clearTokens) 구현 적절합니다.
prefs.clear()로 전체 키 삭제 동작은 의도에 부합합니다. 위의 DataStore 단일화가 선행되어야 의미가 일관됩니다.app/src/main/java/com/texthip/thip/ThipApplication.kt (1)
11-12: 초기화 위치와 super 호출 적절합니다Application.onCreate에서 SDK를 초기화하고 super.onCreate()를 선행 호출한 점, @HiltAndroidApp 사용 흐름 모두 적합합니다.
| private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "thip_auth_tokens") | ||
|
|
There was a problem hiding this comment.
Context.dataStore를 클래스 내부에서 다시 정의하면 DataStore 인스턴스가 이중으로 생성될 수 있습니다. 하나로 통일하세요.
동일 파일에
- 파일 상단(top-level)
Context.dataStore(name = "thip_tokens") - 클래스 내부 멤버 확장
Context.dataStore(name = "thip_auth_tokens")
가 동시에 존재합니다. 호출 위치에 따라 서로 다른 파일명으로 분리된 두 개의 DataStore를 사용할 위험이 있습니다. 토큰 저장/조회가 서로 다른 저장소를 바라보면 데이터 유실·불일치가 발생합니다.
권장: 클래스 내부 정의를 제거하고, top-level 하나만 남기되 파일명을 원하는 최종값(예: "thip_auth_tokens")으로 맞추세요.
적용 diff(선택 범위 내 제거):
- private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "thip_auth_tokens")선택 범위 밖(참고): top-level 정의를 다음과 같이 통일하세요.
// line 16 제안
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "thip_auth_tokens")🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt around lines
22-23, there are two Context.dataStore declarations (a top-level one named
"thip_tokens" and a class-internal one named "thip_auth_tokens") which can
create two separate DataStore instances; remove the class-internal
Context.dataStore declaration so only the top-level extension remains, and
ensure the top-level preferencesDataStore uses the final filename
"thip_auth_tokens" (update its name if needed) so all token reads/writes use the
single unified DataStore.
| companion object { | ||
| //토큰저장에 사용되는 키 | ||
| private val APP_TOKEN_KEY = stringPreferencesKey("app_token") | ||
| } |
There was a problem hiding this comment.
companion object가 중복 선언되어 컴파일 오류가 납니다. 키 정의를 하나의 companion으로 통합하세요.
현재 클래스 아래쪽(라인 49-53)에 또 다른 companion object가 존재합니다. Kotlin은 클래스 당 하나의 companion만 허용합니다. 또한 키가 두 곳으로 분산되면 유지보수성이 떨어집니다.
한 곳으로 합치고, 아래쪽의 중복 companion은 제거하세요.
적용 diff(상단 companion에 모든 키 통합, 하단 중복 companion 제거는 다음 코멘트 설명 참고):
- companion object {
- //토큰저장에 사용되는 키
- private val APP_TOKEN_KEY = stringPreferencesKey("app_token")
- }
+ companion object {
+ // Preferences Keys
+ private val APP_TOKEN_KEY = stringPreferencesKey("app_token")
+ private val TEMP_TOKEN_KEY = stringPreferencesKey("temp_token")
+ private val ACCESS_TOKEN_KEY = stringPreferencesKey("access_token")
+ private val REFRESH_TOKEN_KEY = stringPreferencesKey("refresh_token")
+ }선택 범위 밖(설명): 라인 49-53의 하단 companion object 블록은 통째로 삭제하세요.
📝 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.
| companion object { | |
| //토큰저장에 사용되는 키 | |
| private val APP_TOKEN_KEY = stringPreferencesKey("app_token") | |
| } | |
| companion object { | |
| // Preferences Keys | |
| private val APP_TOKEN_KEY = stringPreferencesKey("app_token") | |
| private val TEMP_TOKEN_KEY = stringPreferencesKey("temp_token") | |
| private val ACCESS_TOKEN_KEY = stringPreferencesKey("access_token") | |
| private val REFRESH_TOKEN_KEY= stringPreferencesKey("refresh_token") | |
| } |
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt around lines
24-27 and 49-53, there are two companion object declarations causing a compile
error; merge the key definitions into the top companion by moving any keys from
the bottom companion into the existing companion object at lines ~24-27 (e.g.,
consolidate stringPreferencesKey("app_token") and any other keys into that
single companion) and then delete the entire lower companion object block (lines
~49-53) so the class contains only one companion with all token-related keys.
| //저장된 토큰 삭제 (로그아웃 시?) | ||
| suspend fun deleteToken() { | ||
| context.dataStore.edit { prefs -> | ||
| prefs.remove(APP_TOKEN_KEY) |
There was a problem hiding this comment.
중괄호 누락으로 컴파일 오류 발생 — deleteToken 블록을 닫아주세요.
edit {} 람다와 함수의 닫는 중괄호가 없습니다.
적용 diff:
suspend fun deleteToken() {
context.dataStore.edit { prefs ->
prefs.remove(APP_TOKEN_KEY)
+ }
+ }추가 제안: 본 메서드는 APP_TOKEN만 지우고, 아래의 clearTokens()는 전체 삭제를 수행합니다. 로그아웃 정책에 따라 둘 중 하나로 일원화하거나, 메서드명을 deleteAppToken() 등으로 명확히 구분하는 것을 권장합니다.
📝 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.
| //저장된 토큰 삭제 (로그아웃 시?) | |
| suspend fun deleteToken() { | |
| context.dataStore.edit { prefs -> | |
| prefs.remove(APP_TOKEN_KEY) | |
| //저장된 토큰 삭제 (로그아웃 시?) | |
| suspend fun deleteToken() { | |
| context.dataStore.edit { prefs -> | |
| prefs.remove(APP_TOKEN_KEY) | |
| } | |
| } |
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/data/manager/TokenManager.kt around lines
43 to 46, the deleteToken() function is missing closing braces for the
dataStore.edit { ... } lambda and the function itself, causing a compile error;
add the two missing closing braces to properly close the edit lambda and the
function, and (optionally) rename the method to deleteAppToken() or consolidate
with clearTokens() depending on logout semantics to avoid ambiguity.
|
|
||
| @HiltAndroidApp | ||
| class ThipApplication : Application() No newline at end of file | ||
| class ThipApplication : Application(){ |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
AndroidManifest에 Application 등록 및 Kakao 리디렉션 구성 확인 권장
@HiltAndroidApp를 사용하는 Application은 매니페스트 application android:name에 반드시 등록되어야 합니다. 또한 카카오 로그인 리디렉션을 위해 com.kakao.sdk.AppKey 메타데이터와 AuthCodeHandlerActivity 등록이 필요합니다. 로컬 환경/브랜치에 따라 누락되지 않았는지 한번 점검 부탁드립니다.
다음 스크립트로 매니페스트/빌드 설정을 빠르게 확인할 수 있습니다.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "1) Application 클래스 등록 확인"
rg -n -C2 -P '<application[^>]*android:name\s*=\s*"(?:\.|com\.texthip\.thip\.)ThipApplication"' -g 'app/**/AndroidManifest.xml' || echo "⚠️ AndroidManifest에 ThipApplication 등록이 보이지 않습니다."
echo
echo "2) Kakao AppKey 메타데이터 확인"
rg -n -C2 -P '<meta-data[^>]*name="com\.kakao\.sdk\.AppKey"[^>]*/>' -g 'app/**/AndroidManifest.xml' || echo "⚠️ com.kakao.sdk.AppKey 메타데이터가 보이지 않습니다."
echo
echo "3) Kakao AuthCodeHandlerActivity 등록 확인"
rg -n -C2 -P 'com\.kakao\.sdk\.auth\.AuthCodeHandlerActivity' -g 'app/**/AndroidManifest.xml' || echo "⚠️ AuthCodeHandlerActivity 등록이 보이지 않습니다."
echo
echo "4) BuildConfig NATIVE_APP_KEY 정의 확인"
rg -n -C2 -P 'buildConfigField\([^)]*"String"\s*,\s*"NATIVE_APP_KEY"' -g 'app/**/build.gradle*' || echo "⚠️ build.gradle에 NATIVE_APP_KEY buildConfigField가 보이지 않습니다."Length of output: 1692
AndroidManifest에 ThipApplication 및 Kakao AppKey 메타데이터 등록 필요
확인 결과, 아래 항목이 누락되어 있어 카카오 로그인 리디렉션이 정상 동작하지 않습니다. 적용 부탁드립니다.
• app/src/main/AndroidManifest.xml
<application>태그에
android:name=".ThipApplication"
또는
android:name="com.texthip.thip.ThipApplication"
속성이 없습니다.
• app/src/main/AndroidManifest.xml<application>내부에메타데이터 항목이 없습니다.<meta-data android:name="com.kakao.sdk.AppKey" android:value="${NATIVE_APP_KEY}" />
• app/src/main/AndroidManifest.xml- AuthCodeHandlerActivity 등록은 올바르게 되어 있습니다.
• app/build.gradle.kts buildConfigField("String", "NATIVE_APP_KEY", …)설정이 올바르게 되어 있습니다.
위 두 가지를 추가한 뒤 카카오 SDK 리디렉션이 정상 작동하는지 재확인 부탁드립니다.
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/ThipApplication.kt around line 10,
add/update app/src/main/AndroidManifest.xml: set the <application> android:name
attribute to ".ThipApplication" or the full "com.texthip.thip.ThipApplication"
value, and inside <application> add the Kakao SDK meta-data element with
android:name="com.kakao.sdk.AppKey" and android:value="${NATIVE_APP_KEY}";
ensure app/build.gradle.kts already defines buildConfigField("String",
"NATIVE_APP_KEY", …) and then rebuild and verify Kakao login redirection works.
➕ 이슈 링크
🔎 작업 내용
📸 스크린샷
신규 사용자
bandicam.2025-08-12.19-33-14-745.mp4
bandicam.2025-08-12.19-33-47-408.mp4
기존 사용자
bandicam.2025-08-12.19-41-38-393.mp4
서버 통신 완료
😢 해결하지 못한 과제
구글 로그인 진행중입니다. 따로 pr 올리겠습니다!
📢 리뷰어들에게
Summary by CodeRabbit
New Features
Refactor
Chores