Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
2ad303c
feat: 인증 관련 데이터 및 도메인 레이어 구현 및 서버 로그인 연동
HamBeomJoon Apr 17, 2026
bd5df98
feat: 인증 관련 UseCase 구현 및 AuthRepository 로직 확장
HamBeomJoon Apr 17, 2026
c98eb96
feat: DataStore 기반의 인증 토큰 관리 및 자동 갱신(Refresh) 시스템 구현
HamBeomJoon Apr 17, 2026
5a02bb4
refactor: `AuthTokenStore` 비동기 처리 및 로깅 보안 강화
HamBeomJoon Apr 17, 2026
f5e02cc
refactor: 네트워크 로깅 정책 개선 및 AuthTokenStore 초기화 로직 단순화
HamBeomJoon Apr 17, 2026
d443929
feat: 로그인 상태 확인 로직 구현 및 스플래시 화면 흐름 개선
HamBeomJoon Apr 17, 2026
5dcda5b
feat: 프로필 화면 내 로그아웃 및 회원 탈퇴 기능 구현
HamBeomJoon Apr 17, 2026
e622066
refactor: UseCase 토큰 획득 로직 캡슐화 및 프로필 UI 피드백 개선
HamBeomJoon Apr 17, 2026
baf9fcb
feat: 로그아웃 및 회원 탈퇴 시 로컬 인증 상태 연동 및 AuthManager 개선
HamBeomJoon Apr 17, 2026
7996d3c
feat: 로그인 성공 후 홈 화면 이동 로직 및 토큰 저장 방식 개선
HamBeomJoon Apr 18, 2026
51954aa
refactor: 네트워크 관련 DI 모듈 구조 개선 및 UseCase 주석 추가
HamBeomJoon Apr 18, 2026
f51f162
refactor: 인증 경로 정책 모듈화 및 AuthRepository 로직 개선
HamBeomJoon Apr 18, 2026
0e23931
refactor: 인증 관련 도메인 레이어 패키지 구조 재정의 및 로직 개선
HamBeomJoon Apr 18, 2026
5830a2e
feat: API 에러 응답 처리 강화 및 프로필 기능 내 인증 예외 처리 구현
HamBeomJoon Apr 18, 2026
f8ca97d
refactor: `AuthTokenStore` 모듈 분리 및 인증 예외 처리 로직 강화
HamBeomJoon Apr 18, 2026
09fba1b
refactor: 인증 토큰 관리 로직 개선 및 ProfileViewModel 안정성 강화
HamBeomJoon Apr 18, 2026
efa1332
refactor: `AuthActionResult` 도입 및 인증 관련 비즈니스 로직 리팩터링
HamBeomJoon Apr 18, 2026
cbbed10
refactor: AuthActionResult 위치 이동 및 패키지 구조 개선
HamBeomJoon Apr 18, 2026
c9f57b2
refactor: 인증 토큰 관리 로직 개선 및 네트워크 모듈 리팩터링
HamBeomJoon Apr 18, 2026
ccdf683
refactor: 네트워크 모듈 주요 클래스 및 함수의 접근 제어자 수정
HamBeomJoon Apr 18, 2026
c09ea5b
chore: .gitignore 파일 정리
HamBeomJoon Apr 18, 2026
28fc53a
refactor: `AuthTokenStore` 초기화 동기화 로직 추가 및 관련 레이어 개선
HamBeomJoon Apr 19, 2026
032403e
refactor: 인증 토큰 관리 로직 강화 및 사용자 경험 개선
HamBeomJoon Apr 19, 2026
3dc0319
refactor: AuthRepositoryImpl 내 토큰 재발급 로직 및 예외 처리 방식 개선
HamBeomJoon Apr 19, 2026
9ae183a
feat: 로그인 상태 확인 로직 개선 및 네트워크 오류 처리 추가
HamBeomJoon Apr 19, 2026
3885177
refactor: 인증 토큰 재발급 로직 개선 및 불필요한 예외 클래스 제거
HamBeomJoon Apr 19, 2026
da2c7be
refactor: Splash 및 Profile 기능 안정성 강화 및 UI 로직 개선
HamBeomJoon Apr 19, 2026
70f7aa7
refactor: 인증 관련 Repository 구조 개선 및 UseCase 로직 리팩터링
HamBeomJoon Apr 20, 2026
a9ac0eb
refactor: Ktor Auth 플러그인 도입 및 네트워크 설정 강화
HamBeomJoon Apr 21, 2026
f18cf3b
Merge remote-tracking branch 'origin/develop' into feat/#103-auth-api2
HamBeomJoon Apr 21, 2026
a2e5c01
build: merge origin/develop to feat/#103-auth-api2
HamBeomJoon Apr 21, 2026
e9e4801
refactor: 인증 토큰 관리 로직 개선 및 초기화 방식 변경
HamBeomJoon Apr 21, 2026
0af0791
feat: AuthLocalDataSource 도입 및 로컬 인증 관리 로직 추상화
HamBeomJoon Apr 21, 2026
291d98f
refactor: 네트워크 모듈 구조 개선 및 `@RefreshNetwork` 한정자 도입
HamBeomJoon Apr 21, 2026
4416efc
Merge remote-tracking branch 'origin/develop' into feat/#103-auth-api2
HamBeomJoon Apr 25, 2026
df56a25
refactor: 인증 토큰 관리 로직 개선 및 Ktor BearerAuth 연동 최적화
HamBeomJoon Apr 25, 2026
6e83339
refactor: 토큰 재발급 로직 개선 및 불필요한 네트워크 구성 요소 제거
HamBeomJoon Apr 25, 2026
4495ee5
refactor: AuthTokenRefresher 리팩터링 및 토큰 재발급 로직 개선
HamBeomJoon Apr 25, 2026
9026f75
refactor: UI 및 디자인 시스템 패키지 구조 개선
HamBeomJoon Apr 25, 2026
fb6db59
refactor: AuthLocalDataSource 통합 및 인증 토큰 관리 로직 개선
HamBeomJoon Apr 26, 2026
ea64dc3
refactor: 인증 토큰 관리 로직 리팩터링 및 Ktor 인증 캐시 무효화 시스템 도입
HamBeomJoon Apr 26, 2026
451417d
refactor: 인증 토큰 관리 로직 및 토큰 재발급 프로세스 개선
HamBeomJoon Apr 26, 2026
af23eb7
feat: 인증 세션 만료 이벤트 버스 및 DataStore 기반 토큰 관리 시스템 고도화
HamBeomJoon Apr 26, 2026
a7bc170
refactor: 인증 세션 이벤트 버스 구조 개선 및 모듈 분리
HamBeomJoon Apr 26, 2026
9e5f010
refactor: 인증 세션 이벤트 관리 로직 리팩터링 (`AuthSessionEventBus` -> `AuthSession…
HamBeomJoon Apr 26, 2026
8afcac0
test: AuthTokenRefresher 유닛 테스트 구현 및 테스트 환경 설정
HamBeomJoon Apr 26, 2026
a59c8a5
feat: 인증 및 세션 관리 로직 개선
HamBeomJoon Apr 26, 2026
9e577c4
refactor: 인증 토큰 관리 로직 최적화 및 안정성 강화
HamBeomJoon Apr 26, 2026
c5cae27
refactor: 인증 응답 모델 및 토큰 관리 구조 개선
moondev03 Apr 27, 2026
a1dc1e9
refactor: 전역 이벤트 기반 인증 만료 처리 구조 개선
moondev03 Apr 27, 2026
c023b0a
refactor: 카카오 로그인 흐름 및 인증 UI 상태 단순화
moondev03 Apr 27, 2026
bbc93ed
refactor: 공용 CoroutineScope 모듈 위치 및 의존 구조 정리
moondev03 Apr 27, 2026
f62403f
refactor: ForceLogout 후 Splash 라우팅 및 앱 내비게이션 구조 정리
moondev03 Apr 27, 2026
de12d44
refactor: core-ui 로딩 애셋 리소스 prefix 규칙 정리
moondev03 Apr 27, 2026
0c6d885
refactor: 인증 모듈 구조 개선
moondev03 Apr 27, 2026
5440023
refactor: 인터페이스 구현체 명명 규칙 변경 (Default -> Impl)
moondev03 Apr 27, 2026
9ff6884
refactor: GlobalEventModule 위치 이동 및 패키지 구조 개선
moondev03 Apr 27, 2026
a4b2ca2
refactor: MyViewModel 내 미사용 의존성 및 import 제거
moondev03 Apr 27, 2026
26d24f9
refactor: 네트워크 클라이언트 생성 로직 분리 및 `HttpClientFactory` 도입
moondev03 Apr 27, 2026
d1f7c4b
refactor: Ktor 로깅 개선 및 네트워크 응답 처리 로직 고도화
HamBeomJoon Apr 30, 2026
7e1bd76
refactor: KtorPrettyLogger 싱글톤 전환 및 로깅 로직 개선
moondev03 Apr 30, 2026
ee3a53e
style: SplashViewModel 코드 스타일 및 가독성 개선
moondev03 Apr 30, 2026
4561d48
feat: Logger 라이브러리 추가 및 PrettyLoggerTree 구현
moondev03 Apr 30, 2026
36320da
refactor: KtorPrettyLogger 네트워크 로그 가독성 및 포맷팅 개선
moondev03 Apr 30, 2026
6e7516a
refactor: 네비게이션 화면 로깅 데코레이터 제거
moondev03 Apr 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Prezel/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ dependencies {
implementation(projects.coreAuth)
implementation(projects.coreData)
implementation(projects.coreDesignsystem)
implementation(projects.coreDomain)
implementation(projects.coreNavigation)
implementation(projects.coreUi)
implementation(projects.coreCommon)

implementation(projects.featureSplashApi)
implementation(projects.featureSplashImpl)
Expand All @@ -51,6 +53,7 @@ dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.navigation3.ui)
implementation(libs.orhanobut.logger)
implementation(libs.timber)
implementation(libs.kotlinx.collections.immutable)
}
1 change: 1 addition & 0 deletions Prezel/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/Theme.PrezelSplashScreen">
<activity
android:name=".MainActivity"
Expand Down
9 changes: 6 additions & 3 deletions Prezel/app/src/main/java/com/team/prezel/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.navigation3.runtime.EntryProviderScope
import androidx.navigation3.runtime.NavKey
import com.team.prezel.core.common.event.GlobalEventBus
import com.team.prezel.core.data.NetworkMonitor
import com.team.prezel.core.designsystem.theme.PrezelTheme
import com.team.prezel.ui.PrezelApp
Expand All @@ -19,6 +20,9 @@ class MainActivity : ComponentActivity() {
@Inject
lateinit var networkMonitor: NetworkMonitor

@Inject
lateinit var globalEventBus: GlobalEventBus

@Inject
lateinit var entryBuilders: Set<@JvmSuppressWildcards EntryProviderScope<NavKey>.() -> Unit>

Expand All @@ -28,12 +32,11 @@ class MainActivity : ComponentActivity() {

setContent {
PrezelTheme {
val appState = rememberPrezelAppState(
networkMonitor = networkMonitor,
)
val appState = rememberPrezelAppState(networkMonitor = networkMonitor)

PrezelApp(
appState = appState,
globalEventBus = globalEventBus,
entryBuilders = entryBuilders.toImmutableSet(),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@ package com.team.prezel

import android.app.Application
import com.team.prezel.core.auth.AuthInitializer
import com.team.prezel.util.PrettyLoggerTree
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber

@HiltAndroidApp
class PrezelApplication : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}

Timber.plant(PrettyLoggerTree())
AuthInitializer.init(this)
}
}
59 changes: 45 additions & 14 deletions Prezel/app/src/main/java/com/team/prezel/ui/PrezelApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,31 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.navigation3.runtime.EntryProviderScope
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.ui.NavDisplay
import com.team.prezel.core.common.event.GlobalEvent
import com.team.prezel.core.common.event.GlobalEventBus
import com.team.prezel.core.designsystem.component.PrezelNavigationScaffold
import com.team.prezel.core.designsystem.component.PrezelNavigationScope
import com.team.prezel.core.navigation.LocalNavigator
import com.team.prezel.core.navigation.Navigator
import com.team.prezel.core.navigation.ProvideSharedTransitionScope
import com.team.prezel.core.navigation.toEntries
import com.team.prezel.core.ui.state.LocalSnackbarHostState
import com.team.prezel.feature.splash.api.SplashNavKey
import com.team.prezel.navigation.MAIN_NAV_ITEMS
import kotlinx.collections.immutable.ImmutableSet

@Composable
fun PrezelApp(
appState: PrezelAppState,
globalEventBus: GlobalEventBus,
entryBuilders: ImmutableSet<EntryProviderScope<NavKey>.() -> Unit>,
) {
val navigator = remember(appState.navigationState) { Navigator(appState.navigationState) }
Expand All @@ -41,6 +47,7 @@ fun PrezelApp(

PrezelAppContent(
appState = appState,
globalEventBus = globalEventBus,
entryBuilders = entryBuilders,
)
}
Expand All @@ -49,11 +56,15 @@ fun PrezelApp(
@Composable
private fun PrezelAppContent(
appState: PrezelAppState,
globalEventBus: GlobalEventBus,
entryBuilders: ImmutableSet<EntryProviderScope<NavKey>.() -> Unit>,
) {
val navigator = LocalNavigator.current
val snackbarHostState = LocalSnackbarHostState.current
val showNavigationBar = appState.shouldShowNavigationBar

ObserveGlobalEvents(
globalEventBus = globalEventBus,
navigateToSplash = { navigator.replaceRoot(SplashNavKey) },
)

SharedTransitionLayout {
ProvideSharedTransitionScope(this@SharedTransitionLayout) {
Expand All @@ -64,18 +75,9 @@ private fun PrezelAppContent(
}

PrezelNavigationScaffold(
showNavigationBar = showNavigationBar,
snackbarHostState = snackbarHostState,
navigationItems = {
MAIN_NAV_ITEMS.forEach { (key, item) ->
Item(
selected = key == appState.navigationState.currentTopLevelKey,
onClick = { navigator.navigate(key) },
label = stringResource(item.titleTextId),
iconResId = item.iconRes,
)
}
},
showNavigationBar = appState.shouldShowNavigationBar,
snackbarHostState = LocalSnackbarHostState.current,
navigationItems = { AppNavigationItems(appState = appState, navigateToKey = { key -> navigator.navigate(key) }) },
) { padding ->
NavDisplay(
entries = appState.navigationState.toEntries(provider),
Expand All @@ -98,3 +100,32 @@ private fun PrezelAppContent(
}
}
}

@Composable
private fun ObserveGlobalEvents(
globalEventBus: GlobalEventBus,
navigateToSplash: () -> Unit,
) {
LaunchedEffect(globalEventBus) {
globalEventBus.events.collect { event ->
when (event) {
GlobalEvent.ForceLogout -> navigateToSplash()
}
}
}
}

@Composable
private fun PrezelNavigationScope.AppNavigationItems(
appState: PrezelAppState,
navigateToKey: (NavKey) -> Unit,
) {
MAIN_NAV_ITEMS.forEach { (key, item) ->
Item(
selected = key == appState.navigationState.currentTopLevelKey,
onClick = { navigateToKey(key) },
label = stringResource(item.titleTextId),
iconResId = item.iconRes,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.team.prezel.util

import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.Logger
import com.orhanobut.logger.PrettyFormatStrategy
import timber.log.Timber

internal class PrettyLoggerTree : Timber.DebugTree() {
init {
Logger.clearLogAdapters()
Logger.addLogAdapter(
AndroidLogAdapter(
PrettyFormatStrategy
.newBuilder()
.showThreadInfo(false)
.methodCount(0)
.tag("PREZEL")
.build(),
),
)
}

override fun log(
priority: Int,
tag: String?,
message: String,
t: Throwable?,
) {
Logger.log(priority, tag, message, t)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import android.content.Context
import com.team.prezel.core.auth.model.AuthResult

interface AuthClient {
suspend fun isLoggedIn(): Boolean

suspend fun login(context: Context): AuthResult

suspend fun logout(): Result<Unit>

suspend fun unlink(): Result<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,45 +1,23 @@
package com.team.prezel.core.auth

import android.content.Context
import com.team.prezel.core.auth.model.AuthProvider
import com.team.prezel.core.auth.model.AuthResult
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class AuthManager
@Inject
constructor(
private val authClients: Map<AuthProvider, @JvmSuppressWildcards AuthClient>,
) {
var currentProvider: AuthProvider? = null
private set

suspend fun login(
context: Context,
provider: AuthProvider,
): AuthResult {
val authClient = authClients[provider] ?: return AuthResult.Failure.Unknown
val result = authClient.login(context = context)

if (result is AuthResult.Success) {
currentProvider = provider
}

return result
}

suspend fun logout(): Result<Unit> {
val provider = currentProvider ?: return Result.failure(
IllegalStateException("로그인된 AuthProvider가 없습니다."),
)

val authClient = authClients[provider] ?: return Result.failure(
IllegalStateException("해당 AuthProvider에 대한 AuthClient를 찾을 수 없습니다. provider=$provider"),
)
class AuthManager @Inject constructor(
private val authClient: AuthClient,
) {
suspend fun login(context: Context): AuthResult = authClient.login(context = context)

suspend fun logout(): Result<Unit> {
if (!authClient.isLoggedIn()) return Result.success(Unit)
return authClient.logout()
}

return authClient.logout().onSuccess {
currentProvider = null
}
}
suspend fun unlink(): Result<Unit> {
if (!authClient.isLoggedIn()) return Result.success(Unit)
return authClient.unlink()
}
}
Loading