Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.umc.edison.data.model.bubble.BubbleEntity
interface BubbleLocalDataSource {
// CREATE
suspend fun addBubbles(bubbles: List<BubbleEntity>)
suspend fun addBubble(bubble: BubbleEntity) : BubbleEntity
suspend fun addBubble(bubble: BubbleEntity, userId: String? = null) : BubbleEntity

// READ
suspend fun getAllActiveBubbles(): List<BubbleEntity>
Expand All @@ -24,6 +24,7 @@ interface BubbleLocalDataSource {
suspend fun trashBubbles(bubbles: List<BubbleEntity>)
suspend fun markAsSynced(bubble: BubbleEntity)
suspend fun syncBubbles(bubbles: List<BubbleEntity>)
suspend fun linkGuestBubblesToUser(userId: String)

// DELETE
suspend fun deleteBubbles(bubbles: List<BubbleEntity>)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.umc.edison.data.datasources.BubbleRemoteDataSource
import com.umc.edison.data.model.bubble.ClusteredBubbleEntity
import com.umc.edison.data.model.bubble.KeywordBubbleEntity
import com.umc.edison.data.model.bubble.toData
import com.umc.edison.data.token.TokenManager
import com.umc.edison.domain.DataResource
import com.umc.edison.domain.model.bubble.Bubble
import com.umc.edison.domain.model.bubble.ClusteredBubble
Expand All @@ -19,7 +20,8 @@ import javax.inject.Inject
class BubbleRepositoryImpl @Inject constructor(
private val bubbleLocalDataSource: BubbleLocalDataSource,
private val bubbleRemoteDataSource: BubbleRemoteDataSource,
private val resourceFactory: FlowBoundResourceFactory
private val resourceFactory: FlowBoundResourceFactory,
private val tokenManager: TokenManager
) : BubbleRepository {
// CREATE
override fun addBubbles(bubbles: List<Bubble>): Flow<DataResource<Unit>> =
Expand All @@ -41,7 +43,10 @@ class BubbleRepositoryImpl @Inject constructor(

override fun addBubble(bubble: Bubble): Flow<DataResource<Bubble>> =
resourceFactory.sync(
localAction = { bubbleLocalDataSource.addBubble(bubble.toData()) },
localAction = {
val currentUserId = tokenManager.getUserId()
bubbleLocalDataSource.addBubble(bubble.toData())
},
remoteSync = {
val newBubble = bubbleLocalDataSource.getActiveBubble(bubble.id)
bubbleRemoteDataSource.syncBubble(newBubble)
Expand Down Expand Up @@ -193,6 +198,10 @@ class BubbleRepositoryImpl @Inject constructor(
}
)

override suspend fun linkGuestBubblesToUser(userId: String) {
bubbleLocalDataSource.linkGuestBubblesToUser(userId)
}

// DELETE
override fun deleteBubbles(bubbles: List<Bubble>): Flow<DataResource<Unit>> =
resourceFactory.sync(
Expand All @@ -212,7 +221,8 @@ class BubbleRepositoryImpl @Inject constructor(
}
},
onRemoteSuccess = { deletedBubbles ->
val localBubbles = deletedBubbles.map { remote -> bubbleLocalDataSource.getRawBubble(remote.id) }
val localBubbles =
deletedBubbles.map { remote -> bubbleLocalDataSource.getRawBubble(remote.id) }
bubbleLocalDataSource.deleteBubbles(localBubbles)
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.umc.edison.data.token.TokenManager
import com.umc.edison.domain.DataResource
import com.umc.edison.domain.model.identity.Identity
import com.umc.edison.domain.model.user.User
import com.umc.edison.domain.repository.BubbleRepository
import com.umc.edison.domain.repository.UserRepository
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
Expand All @@ -17,12 +18,16 @@ class UserRepositoryImpl @Inject constructor(
private val userRemoteDataSource: UserRemoteDataSource,
private val resourceFactory: FlowBoundResourceFactory,
private val tokenManager: TokenManager,
private val bubbleRepository: BubbleRepository
) : UserRepository {
// CREATE

override fun googleLogin(idToken: String): Flow<DataResource<User>> = resourceFactory.remote(
dataAction = {
val userWithToken: UserWithTokenEntity = userRemoteDataSource.googleLogin(idToken)
val userEmail = userWithToken.user.email
tokenManager.setToken(userWithToken.accessToken, userWithToken.refreshToken)
tokenManager.saveUserId(userEmail)
bubbleRepository.linkGuestBubblesToUser(userEmail)
Copy link
Contributor

Choose a reason for hiding this comment

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

로컬 DB에 저장되는 userId가 email의 의미라면 userId 보다는 email 필드로 추가되는 것이 적절해보여요!

Copy link
Contributor

@SuHyeon00 SuHyeon00 Feb 19, 2026

Choose a reason for hiding this comment

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

추가로 로그인/회원가입 API 성공 후에 대한 처리는 비즈니스 시나리오에 가깝기 때문에 Repository보다 UseCase에 두는 건 어떨까요?

  • UserRepository: 로그인/회원가입 API 호출 + 토큰 저장만 담당
  • GoogleLoginUseCase / GoogleSignUpUseCase: userRepository 호출 결과가 성공일 때 bubbleRepository.linkGuestBubblesToUser(userEmail) 호출하도록 이동

이렇게 하면 API 성공 후 처리가 비즈니스 로직으로 UseCase에 모이고, Repository는 데이터 접근만 담당하게될 수 있을 거 같아요. 토큰 저장의 역할도 repository가 할지 UseCase에서 할지 생각해보면 좋을 거 같네요!

userWithToken
}
)
Expand All @@ -39,17 +44,19 @@ class UserRepositoryImpl @Inject constructor(
nickname = nickname,
identity = identity.map { it.toData() }
)
val userEmail = userWithToken.user.email
tokenManager.setToken(userWithToken.accessToken, userWithToken.refreshToken)
tokenManager.saveUserId(userEmail)
bubbleRepository.linkGuestBubblesToUser(userEmail)

userWithToken
}
)



// READ
override fun getLogInState(): Flow<DataResource<Boolean>> = resourceFactory.local(
dataAction = {
tokenManager.loadAccessToken()?.isNotEmpty()
tokenManager.loadAccessToken()?.isNotEmpty() == true
}
)

Expand Down
20 changes: 20 additions & 0 deletions app/src/main/java/com/umc/edison/data/token/TokenManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ class TokenManager @Inject constructor(
applicationScope.launch {
loadAccessToken()
loadRefreshToken()
loadUserId()
}
}

private var cachedAccessToken: String? = null
private var cachedRefreshToken: String? = null
private var cachedUserId: String? = null

override fun getAccessToken(): String? {
if (cachedAccessToken == null) {
Expand All @@ -37,9 +39,12 @@ class TokenManager @Inject constructor(
return cachedRefreshToken
}

fun getUserId(): String? = cachedUserId

override fun clearCachedTokens() {
cachedAccessToken = null
cachedRefreshToken = null
cachedUserId = null
}

override fun setCachedTokens(accessToken: String, refreshToken: String?) {
Expand All @@ -61,6 +66,17 @@ class TokenManager @Inject constructor(
return token
}

suspend fun loadUserId(): String? {
val id = prefDataSource.get(USER_ID_KEY, "")
cachedUserId = id.ifEmpty { null }
return cachedUserId
}

suspend fun saveUserId(userId: String) {
cachedUserId = userId
prefDataSource.set(USER_ID_KEY, userId)
}

suspend fun setToken(accessToken: String, refreshToken: String? = null) {
cachedAccessToken = accessToken
prefDataSource.set(ACCESS_TOKEN_KEY, accessToken)
Expand All @@ -73,12 +89,16 @@ class TokenManager @Inject constructor(
suspend fun deleteToken() {
cachedAccessToken = null
cachedRefreshToken = null
cachedUserId = null

prefDataSource.remove(ACCESS_TOKEN_KEY)
prefDataSource.remove(REFRESH_TOKEN_KEY)
prefDataSource.remove(USER_ID_KEY)
}

companion object {
private const val ACCESS_TOKEN_KEY = "access_token"
private const val REFRESH_TOKEN_KEY = "refresh_token"
private const val USER_ID_KEY = "user_id"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface BubbleRepository {
fun recoverBubbles(bubbles: List<Bubble>): Flow<DataResource<Unit>>
fun updateBubbles(bubbles: List<Bubble>): Flow<DataResource<Unit>>
fun updateBubble(bubble: Bubble): Flow<DataResource<Bubble>>
suspend fun linkGuestBubblesToUser(userId: String)

// DELETE
fun deleteBubbles(bubbles: List<Bubble>): Flow<DataResource<Unit>>
Expand Down
Loading
Loading