Skip to content

[Refactor]: Home model#142

Merged
nahy-512 merged 2 commits into
developfrom
feat/#140-home-model-refac
Jan 20, 2026
Merged

[Refactor]: Home model#142
nahy-512 merged 2 commits into
developfrom
feat/#140-home-model-refac

Conversation

@kimjw2003

@kimjw2003 kimjw2003 commented Jan 20, 2026

Copy link
Copy Markdown
Contributor

📮 관련 이슈

📌 작업 내용

  • 홈 모델 수정

Summary by CodeRabbit

  • 새 기능

    • 사용자 이름이 저장되어 앱 전반에서 사용됩니다.
    • 프로필 이미지가 원형 아바타로 표시되고 이미지 로딩이 개선되었습니다.
    • 북마크된 콘텐츠에 고해상도 이미지 지원이 추가되었습니다.
    • 컬렉션 및 저장된 콘텐츠 섹션의 표시 방식이 개선되었습니다.
  • 스타일

    • 앱 배경이 디자인 시스템의 테마 색상으로 변경되었습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@kimjw2003 kimjw2003 self-assigned this Jan 20, 2026
@kimjw2003 kimjw2003 requested a review from a team as a code owner January 20, 2026 15:49
@kimjw2003 kimjw2003 added the Refactor ♻️ 기능 변경 없이 코드 구조를 개선하여 가독성, 유지보수성, 성능을 향상 label Jan 20, 2026
@coderabbitai

coderabbitai Bot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

도메인/DTO 및 UI 모델을 컬렉션·북마크용 래퍼 리스트 모델로 전환하고, 소셜 인증 응답에 userName을 추가해 DataStore에 저장하도록 PreferencesManager 연동을 도입했습니다. 관련 UI·리포지토리·매퍼·API 어노테이션 및 패키지 네임스페이스 일부도 조정되었습니다.

Changes

코호트 / 파일(s) 변경 요약
상수 / DataStoreKey
app/src/main/java/com/flint/core/common/util/Constants.kt
USER_NAME 상수 추가
Auth DTO / 매퍼 / 저장
app/src/main/java/com/flint/data/dto/auth/response/SocialVerifyResponseDto.kt, app/src/main/java/com/flint/domain/mapper/auth/SocialVerifyMapper.kt, app/src/main/java/com/flint/domain/repository/AuthRepository.kt
DTO에 userName 필드 추가, 매퍼 및 리포지토리에서 userName 매핑 및 PreferencesManager에 저장 로직 추가 (AuthRepository 생성자에 PreferencesManager 주입)
PreferencesManager 이동/재도입
app/src/main/java/com/flint/core/common/datastore/PreferencesManager.kt (삭제), app/src/main/java/com/flint/data/local/PreferencesManager.kt (신규)
기존 PreferencesManager 삭제 후 새로운 패키지(com.flint.data.local)로 재도입(저장/조회 API 제공)
토큰/인터셉터 패키지 변경
app/src/main/java/com/flint/data/di/interceptor/TokenInterceptor.kt, app/src/main/java/com/flint/data/di/...
PreferencesManager import 경로 및 DI 패키지 네임스페이스 변경
Bookmarked content DTO 추가 필드 / 매퍼 변경
app/src/main/java/com/flint/data/dto/content/response/BookmarkedContentListResponseDto.kt, app/src/main/java/com/flint/domain/mapper/content/ContentMapper.kt
BookmarkedContentResponseDto에 imageUrl 추가, 리스트 매핑을 BookmarkedContentListModel/BookmarkedContentItemModel로 변경
컬렉션 매퍼 및 모델 추가
app/src/main/java/com/flint/domain/mapper/collection/CollectionMapper.kt, app/src/main/java/com/flint/domain/model/collection/CollectionListModel.kt
Recommend/Recent 매핑을 CollectionListModel으로 반환하도록 변경, 항목용 CollectionItemModel 추가
새 도메인 리스트 모델
app/src/main/java/com/flint/domain/model/content/BookmarkedContentListModel.kt, app/src/main/java/com/flint/domain/model/collection/CollectionListModel.kt
BookmarkedContentListModel 및 CollectionListModel(및 항목 모델) 추가, FakeList 샘플 포함
리포지토리 시그니처 변경
app/src/main/java/com/flint/domain/repository/{Collection,Content,Home}Repository.kt
반환 타입을 List<...> → 각각 CollectionListModel / BookmarkedContentListModel 으로 변경
UI 컴포넌트·프리뷰 변경
app/src/main/java/com/flint/core/designsystem/component/listItem/CollectionItem.kt, .../SavedContentItem.kt, .../listView/CollectionSection.kt, .../listView/SavedContentsSection.kt
Composable 파라미터 타입을 새로운 리스트/항목 모델로 변경, 내부 참조 및 프리뷰 업데이트, ProfileImage 통합
프로필/홈 관련 UI·유아이상태·뷰모델 변경
app/src/main/java/com/flint/presentation/home/{HomeScreen,HomeViewModel,uistate/HomeUiState.kt}, app/src/main/java/com/flint/presentation/profile/{ProfileScreen,ProfileUiState.kt}
Home/Profile의 public UI 상태와 파라미터 타입을 새로운 리스트 모델로 변경, HomeViewModel에서 PreferencesManager로부터 USER_NAME 구독 및 HomeUiState에 포함
ProfileImage / NetworkImage 변경
app/src/main/java/com/flint/core/designsystem/component/image/ProfileImage.kt, .../NetworkImage.kt
ProfileImage에서 Coil AsyncImage 사용으로 전환(placeholder/error/clip 포함), NetworkImage에 background import 추가
Retrofit 어노테이션 경로 수정
app/src/main/java/com/flint/data/api/*.kt (AuthApi, CollectionApi, ContentApi, HomeApi, SearchApi)
엔드포인트 문자열에 선행 슬래시 추가(예: "api/..." → "/api/...")
패키지 네임스페이스 조정
app/src/main/java/com/flint/data/di/*.kt
여러 DI 모듈 패키지를 com.flint.data.di로 변경
삭제된 토큰 저장소
app/src/main/java/com/flint/data/local/TokenStore.kt
TokenStore 파일 삭제
메인 네비호스트 테마 적용
app/src/main/java/com/flint/presentation/main/MainNavHost.kt
배경색을 FlintTheme.colors.background로 변경

Sequence Diagram(s)

sequenceDiagram
  participant UI as Client(UI)
  participant Repo as AuthRepository
  participant API as AuthApi
  participant Pref as PreferencesManager
  rect rgba(200,200,255,0.5)
    UI->>Repo: socialVerify(request)
    Repo->>API: POST /api/v1/auth/social/verify
    API-->>Repo: SocialVerifyResponseDto(userId, userName, tempToken)
    Repo->>Pref: saveString(USER_NAME, userName)
    Repo-->>UI: Result(SocialVerifyResponseModel)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested reviewers

  • nahy-512
  • giovannijunseokim

Poem

🐰 새벽 들판에 코드가 폈네,
리스트들이 모여 한 송이로,
userName은 주머니 속 열쇠,
Preferences에 조심히 담아두고,
바운스하듯 UI에 미소를 남기네 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 3
❌ Failed checks (1 warning, 2 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive PR 설명이 매우 간결하고 최소한의 정보만 포함하고 있어 변경 사항의 세부 내용과 목적이 불명확합니다. 작업 내용(📌 작업 내용) 섹션을 더 자세히 작성하여 어떤 모델이 어떻게 변경되었는지 구체적으로 설명해 주세요.
Out of Scope Changes check ❓ Inconclusive PR에 포함된 변경 사항이 광범위하고 여러 계층(DTO, 도메인 모델, 리포지토리, UI)에 걸쳐 있어, 모두가 home model 수정과 직접 관련이 있는지 확인하기 어렵습니다. API 엔드포인트 경로 변경(leading slash 추가)과 PreferencesManager 이전 등의 변경 사항이 이슈 #140의 home model 수정과 어떤 관계가 있는지 명확히 설명해 주세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목 '[Refactor]: Home model'은 변경 사항의 주요 목적을 명확하게 요약하고 있으며, home 모델의 리팩토링이라는 핵심 변경을 정확하게 반영합니다.
Linked Issues check ✅ Passed PR이 링크된 이슈 #140의 요구사항인 home model 수정을 충족합니다. 변경 사항은 CollectionListModel, BookmarkedContentListModel 등 새로운 모델을 도입하여 home 모델 구조를 개선하고 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
app/src/main/java/com/flint/presentation/login/LoginViewModel.kt (1)

29-34: userName 저장을 네비게이션 이전에 수행 권장

현재 순서에서는 홈 화면 진입 직후 이름이 잠깐 비어 보일 수 있습니다. 저장을 먼저 수행하고 네비게이션을 emit 하는 편이 안전합니다.

✅ 순서 조정 제안
 if (data.isRegistered) {
-    _navigationEvent.emit(UiState.Success(LoginNavigationEvent.NavigateToHome))
-    preferencesManager.saveString(USER_NAME, data.userName.toString())
+    preferencesManager.saveString(USER_NAME, data.userName.toString())
+    _navigationEvent.emit(UiState.Success(LoginNavigationEvent.NavigateToHome))
 } else {
app/src/main/java/com/flint/data/dto/content/response/BookmarkedContentListResponseDto.kt (1)

13-23: imageUrl 필드에 대한 역호환성 처리 필수

imageUrl 필드가 non-null이면서 기본값이 없으면, 서버에서 이 필드를 내려주지 않는 경우 역직렬화가 실패합니다. 현재 설정된 ignoreUnknownKeyscoerceInputValues는 누락된 필드를 처리하지 못합니다.

nullable로 처리하거나 기본값을 제공하여 안전하게 방어하세요.

✅ 안전한 처리 방안
 `@SerialName`("imageUrl")
-    val imageUrl: String,
+    val imageUrl: String? = null,
app/src/main/java/com/flint/presentation/profile/ProfileUiState.kt (1)

22-36: Empty 상태에서 FakeList 사용은 의미적으로 부적절함

Empty 상태는 초기 또는 빈 상태를 나타내야 하는데, FakeList를 사용하면 실제로는 테스트 데이터가 포함됩니다. 이로 인해 초기 UI에 가짜 데이터가 표시되거나 디버깅 시 혼란이 발생할 수 있습니다.

🔧 수정 제안

빈 모델을 위한 Empty 속성이 CollectionListModelBookmarkedContentListModel에 정의되어 있다면 사용하거나, 없다면 추가를 고려해 주세요:

         val Empty =
             ProfileUiState(
                 keywords = persistentListOf(),
                 profile =
                     AuthorModel(
                         userId = "0",
                         nickname = "",
                         profileUrl = "",
                         userRole = UserRoleType.FLINER,
                     ),
-                createCollections = CollectionListModel.FakeList,
-                savedCollections = CollectionListModel.FakeList,
-                savedContent = BookmarkedContentListModel.FakeList,
+                createCollections = CollectionListModel(), // 또는 CollectionListModel.Empty
+                savedCollections = CollectionListModel(),
+                savedContent = BookmarkedContentListModel(),
             )
🤖 Fix all issues with AI agents
In `@app/src/main/java/com/flint/domain/mapper/collection/CollectionMapper.kt`:
- Around line 9-10: 파일 상단에 선언된 import 중 사용되지 않는 CollectionModel 및 AuthorModel
import를 제거하세요; 현재 이 파일은 CollectionItemModel과 CollectionListModel만 사용하므로 불필요한
import 문(CollectionModel, AuthorModel)을 삭제해 정리하고 IDE/빌드 경고가 없도록 하세요.

In `@app/src/main/java/com/flint/presentation/home/HomeScreen.kt`:
- Around line 54-75: HomeScreen is called from HomeRoute without passing the new
userName from HomeUiState, so HomeScreen always shows an empty name; update the
HomeRoute (where HomeScreen(...) is invoked) to pass uiState.userName (or the
appropriate HomeUiState.userName property) into the HomeScreen userName
parameter so the screen receives and displays the actual user name; reference
symbols: HomeRoute, HomeUiState.userName, and HomeScreen(userName = ...).
🧹 Nitpick comments (5)
app/src/main/java/com/flint/core/designsystem/component/image/NetworkImage.kt (1)

4-4: 사용되지 않는 import를 제거하세요.

androidx.compose.foundation.background import가 추가되었지만 파일 내에서 실제로 사용되지 않습니다. 코드 정리를 위해 제거하는 것을 권장합니다.

♻️ 제안된 수정사항
-import androidx.compose.foundation.background
app/src/main/java/com/flint/domain/model/collection/CollectionListModel.kt (1)

30-41: CollectionItemModel 기본값 사용에 대한 고려사항.

모든 프로퍼티에 기본값이 설정되어 있어 편리하지만, 필수 필드(예: id, title)에 기본값이 있으면 매핑 시 누락된 값을 감지하기 어려울 수 있습니다. 필수 필드는 기본값 없이 명시적으로 전달받는 것을 고려해 보세요.

💡 필수 필드에서 기본값 제거 예시
 data class CollectionItemModel(
-    val id: String = "",
-    val thumbnailUrl: String = "",
-    val title: String = "",
+    val id: String,
+    val thumbnailUrl: String,
+    val title: String,
     val description: String = "",
     val imageList: List<String> = listOf(),
     val bookmarkCount: Int = 0,
     val isBookmarked: Boolean = false,
-    val userId: String = "",
-    val nickname: String = "",
+    val userId: String,
+    val nickname: String,
     val profileUrl: String? = null
 )
app/src/main/java/com/flint/domain/mapper/collection/CollectionMapper.kt (1)

19-53: 중복 코드 통합 고려.

RecommendCollectionItemResponseDto.toModel()RecentCollectionItemResponseDto.toModel()의 구현이 동일합니다. 두 DTO가 동일한 필드 구조를 가진다면 공통 인터페이스나 제네릭 매핑 함수로 중복을 제거할 수 있습니다.

♻️ 공통 인터페이스를 활용한 중복 제거 예시
// 공통 인터페이스 정의 (DTO 모듈에서)
interface CollectionItemDto {
    val id: String
    val thumbnailUrl: String
    val title: String
    val description: String
    val imageList: List<String>
    val bookmarkCount: Int
    val isBookmarked: Boolean
    val userId: String
    val nickname: String
    val profileUrl: String?
}

// 단일 매퍼 함수
private fun CollectionItemDto.toModel(): CollectionItemModel =
    CollectionItemModel(
        id = id,
        thumbnailUrl = thumbnailUrl,
        title = title,
        description = description,
        imageList = imageList,
        bookmarkCount = bookmarkCount,
        isBookmarked = isBookmarked,
        userId = userId,
        nickname = nickname,
        profileUrl = profileUrl
    )
app/src/main/java/com/flint/domain/repository/HomeRepository.kt (1)

6-7: 사용하지 않는 import 확인 필요.

CollectionRepository.kt와 마찬가지로 CollectionModel import가 사용되지 않는 것으로 보입니다.

app/src/main/java/com/flint/domain/repository/CollectionRepository.kt (1)

6-7: 사용되지 않는 import 제거 필요

CollectionModel import(Line 7)는 파일에서 사용되지 않습니다. 반환 타입이 CollectionListModel로 변경되었으므로 제거하세요.

Comment on lines 9 to 10
import com.flint.domain.model.collection.CollectionModel
import com.flint.domain.model.user.AuthorModel

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the structure of the file
cd app/src/main/java/com/flint/domain/mapper/collection/ && wc -l CollectionMapper.kt

Repository: imflint/Flint-Android

Length of output: 87


🏁 Script executed:

# Read the full file to see all content
cat -n app/src/main/java/com/flint/domain/mapper/collection/CollectionMapper.kt

Repository: imflint/Flint-Android

Length of output: 2278


🏁 Script executed:

# Search for actual usage of CollectionModel and AuthorModel (excluding import lines)
rg -n "CollectionModel|AuthorModel" app/src/main/java/com/flint/domain/mapper/collection/CollectionMapper.kt | grep -v "^[0-9]*:\s*import"

Repository: imflint/Flint-Android

Length of output: 47


사용하지 않는 import 제거 필요

CollectionModel(9번 줄)과 AuthorModel(10번 줄) import가 파일 내에서 사용되지 않으므로 제거하세요. 현재 코드는 CollectionItemModelCollectionListModel만 사용 중입니다.

🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/domain/mapper/collection/CollectionMapper.kt`
around lines 9 - 10, 파일 상단에 선언된 import 중 사용되지 않는 CollectionModel 및 AuthorModel
import를 제거하세요; 현재 이 파일은 CollectionItemModel과 CollectionListModel만 사용하므로 불필요한
import 문(CollectionModel, AuthorModel)을 삭제해 정리하고 IDE/빌드 경고가 없도록 하세요.

Comment on lines +54 to +75
HomeScreen(
recommendCollectionModelList = recommendedCollectionList,
recentCollectionModelList = recentCollectionList,
savedContentModelList = bookmarkedContentList,
navigateToCollectionCreate = {
navigateToCollectionCreate()
},
navigateToExplore = {
// TODO navigate to explore
},
onRecentCollectionItemClick = { collectionId ->
navigateToCollectionDetail(collectionId)
},
onRecentCollectionAllClick = navigateToCollectionList,
onRecommendCollectionItemClick = { collectionId ->
navigateToCollectionDetail(collectionId)
},
onSavedContentItemClick = { contentId ->
// TODO show OttListBottomSheet
},
modifier = Modifier.padding(paddingValues),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

userName 파라미터가 전달되지 않음

HomeUiStateuserName 속성이 추가되었지만, HomeRoute에서 HomeScreen을 호출할 때 해당 값을 전달하지 않고 있습니다. 이로 인해 사용자 이름이 항상 빈 문자열로 표시됩니다.

🔧 수정 제안
             HomeScreen(
+                userName = uiState.userName,
                 recommendCollectionModelList = recommendedCollectionList,
                 recentCollectionModelList = recentCollectionList,
                 savedContentModelList = bookmarkedContentList,
📝 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.

Suggested change
HomeScreen(
recommendCollectionModelList = recommendedCollectionList,
recentCollectionModelList = recentCollectionList,
savedContentModelList = bookmarkedContentList,
navigateToCollectionCreate = {
navigateToCollectionCreate()
},
navigateToExplore = {
// TODO navigate to explore
},
onRecentCollectionItemClick = { collectionId ->
navigateToCollectionDetail(collectionId)
},
onRecentCollectionAllClick = navigateToCollectionList,
onRecommendCollectionItemClick = { collectionId ->
navigateToCollectionDetail(collectionId)
},
onSavedContentItemClick = { contentId ->
// TODO show OttListBottomSheet
},
modifier = Modifier.padding(paddingValues),
)
HomeScreen(
userName = uiState.userName,
recommendCollectionModelList = recommendedCollectionList,
recentCollectionModelList = recentCollectionList,
savedContentModelList = bookmarkedContentList,
navigateToCollectionCreate = {
navigateToCollectionCreate()
},
navigateToExplore = {
// TODO navigate to explore
},
onRecentCollectionItemClick = { collectionId ->
navigateToCollectionDetail(collectionId)
},
onRecentCollectionAllClick = navigateToCollectionList,
onRecommendCollectionItemClick = { collectionId ->
navigateToCollectionDetail(collectionId)
},
onSavedContentItemClick = { contentId ->
// TODO show OttListBottomSheet
},
modifier = Modifier.padding(paddingValues),
)
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/presentation/home/HomeScreen.kt` around lines 54
- 75, HomeScreen is called from HomeRoute without passing the new userName from
HomeUiState, so HomeScreen always shows an empty name; update the HomeRoute
(where HomeScreen(...) is invoked) to pass uiState.userName (or the appropriate
HomeUiState.userName property) into the HomeScreen userName parameter so the
screen receives and displays the actual user name; reference symbols: HomeRoute,
HomeUiState.userName, and HomeScreen(userName = ...).

@nahy-512 nahy-512 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

고생하셨습니다~! 길 잘 닦아주셔서 감사합니다

Comment on lines +11 to +26
val FakeList = CollectionListModel(
collections = persistentListOf(
CollectionItemModel(
id = "0",
thumbnailUrl = "",
title = "드라마 제목",
description = "드라마 제목 드라마 제목 드라마 제목 드라마 제목 드라마 제목",
imageList = emptyList(),
bookmarkCount = 0,
isBookmarked = false,
userId = "0",
nickname = "nickname",
profileUrl = null
)
)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

p3
CollectionItemModel에 Fake 객체를 만들고,

Suggested change
val FakeList = CollectionListModel(
collections = persistentListOf(
CollectionItemModel(
id = "0",
thumbnailUrl = "",
title = "드라마 제목",
description = "드라마 제목 드라마 제목 드라마 제목 드라마 제목 드라마 제목",
imageList = emptyList(),
bookmarkCount = 0,
isBookmarked = false,
userId = "0",
nickname = "nickname",
profileUrl = null
)
)
)
val FakeList = CollectionListModel(
collections = persistentListOf(
CollectionItemMode.Fake
)
)

식으로 작성해봐도 좋을 것 같아요

Comment on lines +55 to +57
recommendCollectionModelList = recommendedCollectionList,
recentCollectionModelList = recentCollectionList,
savedContentModelList = bookmarkedContentList,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

p2
화면에 표시될 데이터들은 ScreenuiState로 묶어서 한번에 넘기는 방식은 어떨까요?

Comment on lines +33 to +35
private val _recommendCollectionListLoadState = MutableStateFlow<UiState<CollectionListModel>>(UiState.Loading)
private val _bookmarkedContentListLoadState = MutableStateFlow<UiState<BookmarkedContentListModel>>(UiState.Loading)
private val _recentCollectionListLoadState = MutableStateFlow<UiState<CollectionListModel>>(UiState.Loading)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

p3
HomeUiState에 이미 얘네들이 다 들어가 있는 거 아닌가요??
copy 메서드를 써서 구현할 수도 있었을 거 같은데, 이렇게 구현하신 이유가 궁금합니다

.onSuccess { data ->
if (data.isRegistered) {
_navigationEvent.emit(UiState.Success(LoginNavigationEvent.NavigateToHome))
preferencesManager.saveString(USER_NAME, data.userName.toString())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

p2
saveString의 책임이 레포지토리일 수 있지 않을까요? ViewModel에서 구현하신 이유가 있으신지 궁금합니다

@@ -54,34 +47,32 @@ fun HomeRoute(

when (uiState.loadState) {
is UiState.Success -> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

로딩 처리는 나중에 해주시나요?

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/flint/data/di/interceptor/TokenInterceptor.kt (1)

29-30: 🚨 보안 취약점: 하드코딩된 JWT 토큰을 즉시 제거해야 합니다.

프로덕션 코드에 JWT 토큰이 하드코딩되어 있습니다. 이 토큰은 민감한 사용자 정보(userId, role)를 포함하고 있으며, 소스 코드에 커밋되어서는 안 됩니다.

또한, 26-28번 라인에서 동적으로 설정한 토큰을 이 라인에서 덮어쓰고 있어 정상적인 인증 흐름이 무시됩니다.

🔒 수정 제안
         if (accessToken.isNotEmpty()) {
             requestBuilder.header("Authorization", "Bearer $accessToken")
         }
-        // sample
-        requestBuilder.header("Authorization", "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VySWQiOjgwMDAyMTcxMTM1NzExODE5MSwicm9sZSI6IkZMSU5HIiwidHlwZSI6IkFDQ0VTUyIsImlhdCI6MTc2ODgzODU0MCwiZXhwIjoxNzcwMDQ4MTQwfQ.A2XYyu24IoGAXNSQHJ1S-iudWmg8II2_ivI4EdyyWw9KS9oJlxHKOAhcKrsLpLkc9kllZyxwaTJO1t4vI7oZlg")
🤖 Fix all issues with AI agents
In `@app/src/main/java/com/flint/domain/repository/AuthRepository.kt`:
- Line 24: The call that writes the username uses result.userName.toString(),
which will store the literal "null" if userName is null; update the persistence
to use a null-safe conversion such as result.userName.orEmpty() (or otherwise
handle the null before calling preferencesManager.saveString) so
preferencesManager.saveString(USER_NAME, ...) receives an empty string instead
of "null" — locate the line in AuthRepository where
preferencesManager.saveString(USER_NAME, result.userName.toString()) is called
and replace the toString() usage with a null-safe alternative.
- Around line 22-27: The socialVerify function calls api.socialVerify() outside
the suspendRunCatching, so network exceptions can escape and crash the app; wrap
the entire API call and mapping inside suspendRunCatching (i.e., call
api.socialVerify(model.toDto()), access .data.toModel(), and only on success
call preferencesManager.saveString(USER_NAME, result.userName.toString())) so
that exceptions are captured and a Result<SocialVerifyResponseModel> is
returned; keep references to the existing symbols: function socialVerify,
api.socialVerify, suspendRunCatching, preferencesManager.saveString, and the
Result<SocialVerifyResponseModel> return type.
🧹 Nitpick comments (2)
app/src/main/java/com/flint/data/local/PreferencesManager.kt (1)

25-28: DataStore 읽기 시 예외 처리를 고려해 주세요.

dataStore.data는 디스크 I/O 오류 시 IOException을 throw할 수 있습니다. 현재 구현에서는 호출자가 예외를 처리해야 합니다. 필요시 catch 블록을 추가하거나, 호출부에서 예외 처리가 되어 있는지 확인해 주세요.

♻️ 예외 처리 추가 예시
 fun getString(key: String): Flow<String> =
-    dataStore.data.map { preferences ->
-        preferences[stringPreferencesKey(key)].orEmpty()
-    }
+    dataStore.data
+        .catch { exception ->
+            if (exception is IOException) {
+                emit(emptyPreferences())
+            } else {
+                throw exception
+            }
+        }
+        .map { preferences ->
+            preferences[stringPreferencesKey(key)].orEmpty()
+        }
app/src/main/java/com/flint/presentation/home/HomeViewModel.kt (1)

60-88: 실패 시 에러 상태를 UI에 전달하는 것을 고려해 주세요.

현재 onFailure 핸들러에서 로그만 남기고 있어, 사용자에게 에러 상태가 표시되지 않습니다. UiState.Error를 emit하여 UI에서 적절한 피드백을 제공할 수 있습니다.

♻️ 에러 상태 처리 예시
 fun getRecommendedCollectionList() = viewModelScope.launch {
     homeRepository.getRecommendedCollectionList()
         .onSuccess {
             _recommendCollectionListLoadState.emit(UiState.Success(it))
         }
         .onFailure {
             Log.d("Logd", it.message.toString())
+            _recommendCollectionListLoadState.emit(UiState.Error(it.message))
         }
 }

다른 함수들에도 동일하게 적용해 주세요.

Comment on lines +22 to +27
suspend fun socialVerify(model: SocialVerifyRequestModel): Result<SocialVerifyResponseModel> {
val result = api.socialVerify(model.toDto()).data.toModel()
preferencesManager.saveString(USER_NAME, result.userName.toString())

return suspendRunCatching { result }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

예외 처리가 누락되어 API 호출 실패 시 크래시가 발생합니다.

api.socialVerify() 호출이 suspendRunCatching 블록 바깥에 있어서, 네트워크 오류나 API 실패 시 예외가 전파되어 앱이 크래시될 수 있습니다. 현재 suspendRunCatching은 이미 계산된 result만 감싸고 있어 의미가 없습니다.

🐛 수정 제안
 suspend fun socialVerify(model: SocialVerifyRequestModel): Result<SocialVerifyResponseModel> =
-    val result = api.socialVerify(model.toDto()).data.toModel()
-    preferencesManager.saveString(USER_NAME, result.userName.toString())
-
-    return suspendRunCatching { result }
+    suspendRunCatching {
+        val result = api.socialVerify(model.toDto()).data.toModel()
+        preferencesManager.saveString(USER_NAME, result.userName.orEmpty())
+        result
+    }
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/domain/repository/AuthRepository.kt` around lines
22 - 27, The socialVerify function calls api.socialVerify() outside the
suspendRunCatching, so network exceptions can escape and crash the app; wrap the
entire API call and mapping inside suspendRunCatching (i.e., call
api.socialVerify(model.toDto()), access .data.toModel(), and only on success
call preferencesManager.saveString(USER_NAME, result.userName.toString())) so
that exceptions are captured and a Result<SocialVerifyResponseModel> is
returned; keep references to the existing symbols: function socialVerify,
api.socialVerify, suspendRunCatching, preferencesManager.saveString, and the
Result<SocialVerifyResponseModel> return type.

suspendRunCatching { api.socialVerify(model.toDto()).data.toModel() }
suspend fun socialVerify(model: SocialVerifyRequestModel): Result<SocialVerifyResponseModel> {
val result = api.socialVerify(model.toDto()).data.toModel()
preferencesManager.saveString(USER_NAME, result.userName.toString())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

toString() 대신 orEmpty()를 사용하세요.

result.userNamenull인 경우, toString()은 문자열 "null"을 저장합니다. 의도한 동작이 아니라면 orEmpty()나 null-safe 처리를 사용해야 합니다.

🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/domain/repository/AuthRepository.kt` at line 24,
The call that writes the username uses result.userName.toString(), which will
store the literal "null" if userName is null; update the persistence to use a
null-safe conversion such as result.userName.orEmpty() (or otherwise handle the
null before calling preferencesManager.saveString) so
preferencesManager.saveString(USER_NAME, ...) receives an empty string instead
of "null" — locate the line in AuthRepository where
preferencesManager.saveString(USER_NAME, result.userName.toString()) is called
and replace the toString() usage with a null-safe alternative.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Refactor ♻️ 기능 변경 없이 코드 구조를 개선하여 가독성, 유지보수성, 성능을 향상

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 홈 model 수정

2 participants