[Feature] 마이페이지 api 연결#211
Hidden character warning
Conversation
|
Warning Review limit reached
More reviews will be available in 52 minutes and 22 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 Walkthrough워크스루PR은 Route.SavedContentList를 userId를 받는 데이터 클래스로 바꾸고, 북마크 목록 API를 커서 기반으로 전환했습니다. Bookmarked 응답/도메인 모델에 totalCount/bookmarkCount/isBookmarked가 추가되고, BookmarkRepository는 변경 이벤트를 SharedFlow로 발행합니다. Profile에 키워드 재계산 API·UI가 연결됩니다. 변경 사항북마크 목록 및 키워드 재계산 기능
수열 다이어그램sequenceDiagram
participant User
participant ProfileScreen
participant MainNavigator
participant SavedContentViewModel
participant UserRepository
participant BookmarkRepository
participant BookmarkApi
User->>ProfileScreen: "저장작품 전체 보기" 클릭
ProfileScreen->>MainNavigator: navigateToSavedContent(userId)
MainNavigator->>SavedContentViewModel: Route.SavedContentList(userId)
SavedContentViewModel->>UserRepository: getUserBookmarkedContents(userId)
UserRepository->>BookmarkApi: 커서 기반 페이지네이션 호출
BookmarkApi-->>UserRepository: MyBookmarkedContentListResponseDto
UserRepository-->>SavedContentViewModel: BookmarkedContentListModel
SavedContentViewModel->>SavedContentViewModel: 상태 갱신
Note over SavedContentViewModel: UiState.Success(data)
예상 코드 리뷰 난이도🎯 4 (Complex) | ⏱️ ~60분 관련 PR들
제안 라벨
제안 리뷰어
시 🐰
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
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/dto/user/response/UserProfileResponseDto.kt (1)
1-18:⚠️ Potential issue | 🟡 Minor
UserProfileResponseDto직렬화 애노테이션 불일치 수정 필요
NetworkModule에서 RetrofitaddConverterFactory는kotlinx.serialization(asConverterFactory)만 사용 중입니다.- 그런데
UserProfileResponseDto는@Serializable(kotlinx)와@SerializedName(Gson)을 함께 쓰고 있어, Gson@SerializedName은 kotlinx 직렬화에서는 적용되지 않습니다.BookmarkedContentListResponseDto를 포함한 대부분의 DTO가kotlinx.serialization.SerialName을 쓰므로,UserProfileResponseDto도@SerializedName을@SerialName으로 바꾸거나 Gson 애노테이션/임포트를 제거해 일관성을 맞추세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/flint/data/dto/user/response/UserProfileResponseDto.kt` around lines 1 - 18, UserProfileResponseDto mixes Gson (`@SerializedName`) with kotlinx.serialization (`@Serializable`) while NetworkModule uses Retrofit with kotlinx.asConverterFactory; replace all `@SerializedName` usages in UserProfileResponseDto with kotlinx.serialization.SerialName (or remove Gson imports) so field names are honored by kotlinx serialization, e.g., update the annotations on id, profileImageUrl, isFliner, nickname, keywordRecalculatable to `@SerialName` and remove com.google.gson imports to match the rest of DTOs and NetworkModule’s asConverterFactory usage.
🧹 Nitpick comments (3)
app/src/main/java/com/flint/presentation/savedcontent/SavedContentListScreen.kt (1)
5-16: 💤 Low valuesavedcontent 패키지에서 profile 패키지로의 크로스 패키지 의존성
SavedContentListRoute가profile.SavedContentRoute로 단순 위임하면서 savedcontent → profile 방향의 프레젠테이션 레이어 간 의존성이 생성되었습니다. 이는 SavedContentRoute가 profile 패키지로 통합된 의도적인 리팩토링으로 보이지만, 패키지 간 결합도가 증가하는 점을 유의하시기 바랍니다.만약 향후 savedcontent와 profile 기능을 독립적으로 유지하려는 경우, SavedContentRoute의 위치를 재고하거나 공통 모듈로 추출하는 것을 검토해보세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/flint/presentation/savedcontent/SavedContentListScreen.kt` around lines 5 - 16, SavedContentListRoute currently delegates to profile.SavedContentRoute, introducing a cross-package dependency from savedcontent to profile; either move SavedContentRoute into the savedcontent package, extract it into a shared/common module, or create a local SavedContentRoute implementation/adapter in savedcontent that wraps the profile implementation to avoid direct package coupling—update references to use the chosen location and ensure the function signature (SavedContentListRoute, SavedContentRoute, paddingValues, navigateUp) remains consistent.app/src/main/java/com/flint/presentation/profile/SavedContentViewModel.kt (1)
85-141: ⚖️ Poor tradeoff수동 JSON 파싱의 취약성
북마크 토글 실패 시 에러 응답을 수동으로 JSON 파싱하여
BOOKMARK.CONTENT_MIN_LIMIT에러 코드를 확인하고 있습니다(124-132줄). 이 접근 방식은 다음과 같은 문제가 있습니다:
- 에러 응답 구조 변경 시 파싱 실패 가능
- JSON 파싱 예외 처리가
runCatching으로만 되어 있어 실패 원인 추적 어려움- 타입 안정성 부재
다만 PR 목표에 따르면 해당 비즈니스 에러를 글로벌 네트워크 에러 처리에서 제외하기 위한 의도적인 설계로 보입니다.
장기적으로는 에러 응답을 별도의 DTO로 정의하고
Converter를 통해 파싱하는 것을 권장합니다:data class ErrorResponse( val errorCode: String, val message: String? ) // Retrofit Converter 또는 별도 파싱 유틸리티 활용현재는 PR 목표에 부합하므로 승인하되, 향후 리팩토링 시 고려해주세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/flint/presentation/profile/SavedContentViewModel.kt` around lines 85 - 141, The toggleBookmark failure handling in SavedContentViewModel currently does fragile manual JSON parsing to detect BOOKMARK.CONTENT_MIN_LIMIT; replace this with a typed ErrorResponse DTO and use Retrofit's converter (or a shared parsing utility) to convert throwable.response().errorBody() into ErrorResponse, then check errorResponse.errorCode == "BOOKMARK.CONTENT_MIN_LIMIT"; update the onFailure block (where isMinLimitError is computed) to use the converter and proper try/catch that logs parsing errors, and then call _uiState.update/showBookmarkRestrictionModal or Timber.e accordingly.app/src/main/java/com/flint/presentation/profile/SavedContentScreen.kt (1)
209-273: ⚡ Quick win프리뷰 데이터에 북마크 상태 추가를 권장합니다.
SavedContentPreviewData.FakeList의BookmarkedContentItemModel인스턴스들이isBookmarked와bookmarkCount속성을 설정하지 않고 있습니다. 이제 실제 화면에서 이 속성들을 사용하므로(lines 196-197), 프리뷰에서도 현실적인 북마크 상태를 보여주도록 데이터를 업데이트하는 것이 좋습니다.♻️ 프리뷰 데이터 개선 제안
BookmarkedContentItemModel( id = "0", title = "은하수를 여행하는 히치하이커를 위한 안내서", year = 2005, imageUrl = "", getOttSimpleList = listOf( OttType.Netflix, OttType.Disney, OttType.Tving, ), + isBookmarked = true, + bookmarkCount = 42, ),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/flint/presentation/profile/SavedContentScreen.kt` around lines 209 - 273, SavedContentPreviewData.FakeList contains BookmarkedContentItemModel entries missing isBookmarked and bookmarkCount; update each BookmarkedContentItemModel in SavedContentScreen.kt (FakeList) to set realistic isBookmarked (true/false) and bookmarkCount integers so previews reflect actual UI usage (see usages at lines referencing isBookmarked and bookmarkCount). Locate the FakeList declaration and add the isBookmarked and bookmarkCount properties to each BookmarkedContentItemModel constructor (vary values across items to show different states: bookmarked vs not and different counts).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/main/java/com/flint/data/di/interceptor/NetworkErrorInterceptor.kt`:
- Around line 29-31: The current detection uses
response.peekBody(Long.MAX_VALUE).string().contains("\"errorCode\"") which risks
OOM and false positives; change NetworkErrorInterceptor to call
response.peekBody with a bounded buffer (e.g., 8KB–64KB) instead of
Long.MAX_VALUE and replace the naive contains check with a proper JSON field
existence test (use your project's JSON parser or JSONObject to parse the peeked
body and check for the "errorCode" key) when computing isBusinessError so large
bodies are not fully buffered and only a parsed JSON check determines presence
of the errorCode field.
In `@app/src/main/java/com/flint/domain/mapper/content/ContentMapper.kt`:
- Around line 23-28: The current MyBookmarkedContentListResponseDto.toModel()
sets totalCount = data.size which only reflects items in the current cursor
page; change it to use the DTO's meta.returned value when available (e.g.,
totalCount = meta?.returned ?: data.size) so the model's totalCount reflects the
DTO's intended count metric, and leave UserRepository's aggregation logic (which
builds BookmarkedContentListModel(totalCount = allContents.size)) to override as
needed; update the MyBookmarkedContentListResponseDto.toModel() implementation
accordingly.
In `@app/src/main/java/com/flint/domain/repository/BookmarkRepository.kt`:
- Around line 26-40: The current use of Result.onSuccess in
toggleCollectionBookmark and toggleContentBookmark attempts to call the suspend
function _bookmarkChanges.emit(...) from a non-suspending lambda
(Result.onSuccess), causing a compile error; fix by replacing the onSuccess
usage with a suspend-friendly check such as val isBookmarked =
result.getOrNull(); if (isBookmarked != null) {
_bookmarkChanges.emit(BookmarkChange.Collection(collectionId, isBookmarked)) }
(and similarly for BookmarkChange.Content in toggleContentBookmark) so the emit
call runs directly in the surrounding suspend function.
In `@app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt`:
- Around line 64-70: 현재 코드에서 savedContents.contents를 필터한 뒤 totalCount를
filtered.size로 덮어써 전체 개수 계약이 깨집니다; 대신 북마크 해제 로직(예: where change.id is
removed)에서는 contents를 filtered로 갱신하되 savedContents.totalCount는 기존 totalCount에서
1만 감소시키는 방식으로 유지하세요 (즉, data.savedContents.copy(contents = filtered, totalCount
= maxOf(data.savedContents.totalCount - 1, 0))처럼 기존 totalCount를 직접 조작),
savedContents와 화면 리스트 길이를 분리해서 다루도록 ProfileViewModel의 해당 분기(데이터 업데이트:
data.savedContents.contents, totalCount)를 수정하십시오.
---
Outside diff comments:
In
`@app/src/main/java/com/flint/data/dto/user/response/UserProfileResponseDto.kt`:
- Around line 1-18: UserProfileResponseDto mixes Gson (`@SerializedName`) with
kotlinx.serialization (`@Serializable`) while NetworkModule uses Retrofit with
kotlinx.asConverterFactory; replace all `@SerializedName` usages in
UserProfileResponseDto with kotlinx.serialization.SerialName (or remove Gson
imports) so field names are honored by kotlinx serialization, e.g., update the
annotations on id, profileImageUrl, isFliner, nickname, keywordRecalculatable to
`@SerialName` and remove com.google.gson imports to match the rest of DTOs and
NetworkModule’s asConverterFactory usage.
---
Nitpick comments:
In `@app/src/main/java/com/flint/presentation/profile/SavedContentScreen.kt`:
- Around line 209-273: SavedContentPreviewData.FakeList contains
BookmarkedContentItemModel entries missing isBookmarked and bookmarkCount;
update each BookmarkedContentItemModel in SavedContentScreen.kt (FakeList) to
set realistic isBookmarked (true/false) and bookmarkCount integers so previews
reflect actual UI usage (see usages at lines referencing isBookmarked and
bookmarkCount). Locate the FakeList declaration and add the isBookmarked and
bookmarkCount properties to each BookmarkedContentItemModel constructor (vary
values across items to show different states: bookmarked vs not and different
counts).
In `@app/src/main/java/com/flint/presentation/profile/SavedContentViewModel.kt`:
- Around line 85-141: The toggleBookmark failure handling in
SavedContentViewModel currently does fragile manual JSON parsing to detect
BOOKMARK.CONTENT_MIN_LIMIT; replace this with a typed ErrorResponse DTO and use
Retrofit's converter (or a shared parsing utility) to convert
throwable.response().errorBody() into ErrorResponse, then check
errorResponse.errorCode == "BOOKMARK.CONTENT_MIN_LIMIT"; update the onFailure
block (where isMinLimitError is computed) to use the converter and proper
try/catch that logs parsing errors, and then call
_uiState.update/showBookmarkRestrictionModal or Timber.e accordingly.
In
`@app/src/main/java/com/flint/presentation/savedcontent/SavedContentListScreen.kt`:
- Around line 5-16: SavedContentListRoute currently delegates to
profile.SavedContentRoute, introducing a cross-package dependency from
savedcontent to profile; either move SavedContentRoute into the savedcontent
package, extract it into a shared/common module, or create a local
SavedContentRoute implementation/adapter in savedcontent that wraps the profile
implementation to avoid direct package coupling—update references to use the
chosen location and ensure the function signature (SavedContentListRoute,
SavedContentRoute, paddingValues, navigateUp) remains consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9c09fff1-2fe7-4eed-b808-61be63be29f2
📒 Files selected for processing (25)
app/src/main/java/com/flint/core/navigation/Route.ktapp/src/main/java/com/flint/data/api/ContentApi.ktapp/src/main/java/com/flint/data/api/UserApi.ktapp/src/main/java/com/flint/data/di/interceptor/NetworkErrorInterceptor.ktapp/src/main/java/com/flint/data/dto/content/response/BookmarkedContentListResponseDto.ktapp/src/main/java/com/flint/data/dto/user/response/UserProfileResponseDto.ktapp/src/main/java/com/flint/domain/mapper/content/ContentMapper.ktapp/src/main/java/com/flint/domain/mapper/user/ProfileMapper.ktapp/src/main/java/com/flint/domain/model/bookmark/BookmarkChange.ktapp/src/main/java/com/flint/domain/model/content/BookmarkedContentListModel.ktapp/src/main/java/com/flint/domain/model/user/UserProfileResponseModel.ktapp/src/main/java/com/flint/domain/repository/BookmarkRepository.ktapp/src/main/java/com/flint/domain/repository/UserRepository.ktapp/src/main/java/com/flint/presentation/main/MainNavHost.ktapp/src/main/java/com/flint/presentation/main/MainNavigator.ktapp/src/main/java/com/flint/presentation/profile/ProfileScreen.ktapp/src/main/java/com/flint/presentation/profile/ProfileViewModel.ktapp/src/main/java/com/flint/presentation/profile/SavedContentScreen.ktapp/src/main/java/com/flint/presentation/profile/SavedContentViewModel.ktapp/src/main/java/com/flint/presentation/profile/component/ProfileKeywordSection.ktapp/src/main/java/com/flint/presentation/profile/navigation/ProfileNavigation.ktapp/src/main/java/com/flint/presentation/profile/uistate/ProfileUiState.ktapp/src/main/java/com/flint/presentation/profile/uistate/SavedContentUiState.ktapp/src/main/java/com/flint/presentation/savedcontent/SavedContentListScreen.ktapp/src/main/java/com/flint/presentation/savedcontent/navigation/SavedContentNavigation.kt
|
kimjw2003
left a comment
There was a problem hiding this comment.
전반적으로 설계가 깔끔하고, 북마크 상태 동기화를 SharedFlow로 처리한 방식도 좋습니다 👍 몇 가지 확인이 필요한 부분 남겼어요!
| BookmarkedContentListModel( | ||
| totalCount = allContents.size, | ||
| contents = allContents.toImmutableList() | ||
| ) |
There was a problem hiding this comment.
[페이지네이션 루프] 북마크가 많은 유저의 경우 do-while 루프로 전체 페이지를 한 번에 다 불러오면 요청 횟수가 늘어나고 메모리 사용량도 커질 수 있어요. 지금은 단순하게 전부 로드하는 게 MVP에선 괜찮지만, 추후 SavedContentListScreen에서 실제 무한스크롤(커서 기반 페이지네이션)로 교체하는 걸 고려해보면 좋겠어요!
There was a problem hiding this comment.
count API가 분리되면서 totalCount = allContents.size 방식은 /api/v1/contents/bookmarks/count를 별도 호출하는 방식으로 수정했습니다.
| BookmarkedContentListModel( | ||
| totalCount = allContents.size, | ||
| contents = allContents.toImmutableList() | ||
| ) |
There was a problem hiding this comment.
[고민해볼 점 - 페이지네이션] 북마크가 많은 유저의 경우 do-while 루프로 전체 페이지를 한 번에 다 불러오면 API 요청이 여러 번 순차적으로 발생하고, 모든 결과를 메모리에 올리게 돼요. 지금 구조에서 MVP 단순화로 이해하긴 하는데, 추후 SavedContentListScreen에서 실제 무한스크롤(커서 기반)로 개선하면 초기 로딩 속도도 빠르고 메모리도 절약될 것 같아요!
| } | ||
| } | ||
| state.copy(sectionData = UiState.Success(updated)) | ||
| } |
There was a problem hiding this comment.
[버그 가능성] BookmarkChange.Content는 userId == null(내 프로필)일 때만 목록에서 제거하고, 타 유저 프로필에서는 isBookmarked 토글만 하도록 분기하고 있는데요, BookmarkChange.Collection 쪽은 이 분기가 없어서 타 유저 프로필을 보다가 컬렉션 북마크를 해제하면 상대방의 저장 컬렉션 목록에서 해당 항목이 사라지는 문제가 발생할 수 있어요.
Content와 동일하게 userId 기준으로 분기해주는 게 좋을 것 같아요!
is BookmarkChange.Collection -> {
val updatedCollections = if (userId == null) {
// 내 프로필: 북마크 취소 시 목록에서 제거
if (change.isBookmarked) data.savedCollections
else { ... filter ... }
} else {
// 타 유저 프로필: isBookmarked 토글만
data.savedCollections.copy(
collections = data.savedCollections.collections
.map { if (it.id == change.id) it.copy(isBookmarked = change.isBookmarked) else it }
.toPersistentList()
)
}
...
}There was a problem hiding this comment.
BookmarkChange.Collection에도 userId 기준 분기를 추가했습니다. 내 프로필에선 기존처럼 목록에서 제거하고, 타 유저 프로필에선 isBookmarked 토글만 하도록 수정했습니다.
| ) | ||
| } | ||
|
|
||
| // /api/v1/contents/bookmarks (내 프로필) |
There was a problem hiding this comment.
[사용되지 않는 코드] 이 toModel()은 UserRepository.getUserBookmarkedContents 내부에서 page.data.map { it.toModel() }로 항목 단위 매핑만 쓰고, MyBookmarkedContentListResponseDto.toModel() 자체는 실제로 호출되지 않아요. 그리고 totalCount = meta.returned는 단일 페이지의 반환 수라서, 전체 목록 수와도 달라서 혼란을 줄 수 있어요. 혹시 추후 단일 페이지 조회로 바꿀 계획이 있으시면 남겨두셔도 좋고, 아니라면 제거하는 게 깔끔할 것 같아요!
There was a problem hiding this comment.
MyBookmarkedContentListResponseDto.toModel() 제거했습니다. 단일 페이지 조회로 전환할 계획은 현재 없어서 같이 정리했습니다!
| .onFailure { throwable -> | ||
| if (throwable.isContentMinLimitError()) { | ||
| _uiState.update { it.copy(showBookmarkRestrictionModal = true) } | ||
| } else { |
There was a problem hiding this comment.
[아키텍처] ViewModel에서 Json을 직접 주입받아 에러 바디를 파싱하는 건 데이터 레이어의 관심사를 presentation 레이어로 올린 케이스예요. BookmarkRepository.toggleContentBookmark에서 HTTP 응답을 파싱해 도메인 예외(ContentMinLimitException 같은 sealed class)로 변환하면, ViewModel은 에러 타입만 보고 분기할 수 있어서 레이어 경계가 명확해질 것 같아요. 지금 구조도 동작은 하지만, 같은 패턴이 다른 ViewModel에서도 필요해질 때 중복되기 쉬워서 한번 고민해보시면 좋겠어요!
There was a problem hiding this comment.
BookmarkException을 domain 레이어에 sealed class로 추가하고, BookmarkRepository.toggleContentBookmark에서 HTTP 에러 파싱 후 도메인 예외로 변환하도록 수정했습니다. SavedContentViewModel에서는 Json 주입을 제거하고 throwable is BookmarkException.ContentMinLimitExceeded로 단순화했습니다.
|
[UserApi.kt - nit] |
There was a problem hiding this comment.
Actionable comments posted: 1
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/presentation/profile/ProfileViewModel.kt (1)
152-159:⚠️ Potential issue | 🟠 Major | ⚡ Quick win타 유저 프로필 컨텍스트에서 키워드 재계산을 차단해야 합니다.
Line [152]~Line [159]는
userId != null이어도 실행 가능하고, 성공 시getUserKeywords(userId = null)로 내 키워드를 현재 화면에 반영할 수 있습니다. ViewModel에서 명시적으로 가드해 컨텍스트 오염을 막아주세요.🛠 제안 패치
fun recalculateKeywords() = viewModelScope.launch { + if (userId != null) return@launch + _uiState.update { it.copy(isRecalculating = true) } userRepository.recalculateKeywords() .onSuccess { // 버튼 즉시 비활성화 후 키워드 재조회 _uiState.update { it.copy(profile = it.profile.copy(keywordRecalculatable = false)) } - userRepository.getUserKeywords(userId = null) + userRepository.getUserKeywords(userId = userId)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt` around lines 152 - 159, The recalculateKeywords() function in ProfileViewModel should not execute when viewing another user's profile (when userId is not null). Add a guard clause at the beginning of the recalculateKeywords() function to check if userId is not null and return early if true, preventing the keyword recalculation logic and subsequent getUserKeywords(userId = null) call from executing in other user's profile context. This prevents context pollution where the current user's keywords could be inadvertently updated while viewing another user's profile.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/main/java/com/flint/domain/model/bookmark/BookmarkException.kt`:
- Around line 3-5: The ContentMinLimitExceeded exception is declared as a
singleton object, which causes the exception instance to be reused across
multiple throws, leading to shared stacktraces and internal state that degrades
debugging reliability. Change ContentMinLimitExceeded from an object declaration
to a class declaration so that a new exception instance is created each time it
is thrown. This ensures each thrown exception has its own independent stacktrace
and state for proper error tracking and debugging.
---
Outside diff comments:
In `@app/src/main/java/com/flint/presentation/profile/ProfileViewModel.kt`:
- Around line 152-159: The recalculateKeywords() function in ProfileViewModel
should not execute when viewing another user's profile (when userId is not
null). Add a guard clause at the beginning of the recalculateKeywords() function
to check if userId is not null and return early if true, preventing the keyword
recalculation logic and subsequent getUserKeywords(userId = null) call from
executing in other user's profile context. This prevents context pollution where
the current user's keywords could be inadvertently updated while viewing another
user's profile.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 914b0829-4e61-4d25-acd1-9018dd6ff2a9
📒 Files selected for processing (13)
app/src/main/java/com/flint/core/navigation/Route.ktapp/src/main/java/com/flint/data/api/ContentApi.ktapp/src/main/java/com/flint/data/dto/content/response/BookmarkedContentListResponseDto.ktapp/src/main/java/com/flint/domain/mapper/content/ContentMapper.ktapp/src/main/java/com/flint/domain/model/bookmark/BookmarkException.ktapp/src/main/java/com/flint/domain/repository/BookmarkRepository.ktapp/src/main/java/com/flint/domain/repository/ContentRepository.ktapp/src/main/java/com/flint/domain/repository/UserRepository.ktapp/src/main/java/com/flint/presentation/main/MainNavHost.ktapp/src/main/java/com/flint/presentation/main/MainNavigator.ktapp/src/main/java/com/flint/presentation/profile/ProfileScreen.ktapp/src/main/java/com/flint/presentation/profile/ProfileViewModel.ktapp/src/main/java/com/flint/presentation/profile/SavedContentViewModel.kt
💤 Files with no reviewable changes (3)
- app/src/main/java/com/flint/domain/repository/ContentRepository.kt
- app/src/main/java/com/flint/presentation/profile/ProfileScreen.kt
- app/src/main/java/com/flint/domain/mapper/content/ContentMapper.kt
🚧 Files skipped from review as they are similar to previous changes (6)
- app/src/main/java/com/flint/core/navigation/Route.kt
- app/src/main/java/com/flint/presentation/main/MainNavigator.kt
- app/src/main/java/com/flint/data/api/ContentApi.kt
- app/src/main/java/com/flint/presentation/main/MainNavHost.kt
- app/src/main/java/com/flint/domain/repository/UserRepository.kt
- app/src/main/java/com/flint/data/dto/content/response/BookmarkedContentListResponseDto.kt
| sealed class BookmarkException : Exception() { | ||
| /** 최소 저장 작품 수 제한으로 콘텐츠 북마크 해제 불가 */ | ||
| object ContentMinLimitExceeded : BookmarkException() |
There was a problem hiding this comment.
Throwable을 object로 선언하면 예외 인스턴스가 재사용됩니다.
Line [5]의 singleton 예외는 반복 throw 시 stacktrace/내부 상태가 공유되어 디버깅 신뢰도가 떨어집니다. 예외는 매번 새 인스턴스로 생성되는 class로 바꾸는 편이 안전합니다.
🛠 제안 패치
sealed class BookmarkException : Exception() {
/** 최소 저장 작품 수 제한으로 콘텐츠 북마크 해제 불가 */
- object ContentMinLimitExceeded : BookmarkException()
+ class ContentMinLimitExceeded : BookmarkException()
}// throw 지점 예시 (BookmarkRepository)
throw BookmarkException.ContentMinLimitExceeded()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/main/java/com/flint/domain/model/bookmark/BookmarkException.kt`
around lines 3 - 5, The ContentMinLimitExceeded exception is declared as a
singleton object, which causes the exception instance to be reused across
multiple throws, leading to shared stacktraces and internal state that degrades
debugging reliability. Change ContentMinLimitExceeded from an object declaration
to a class declaration so that a new exception instance is created each time it
is thrown. This ensures each thrown exception has its own independent stacktrace
and state for proper error tracking and debugging.
📮 관련 이슈
📌 작업 내용
작업 요약
마이페이지 API를 최신 스펙에 맞게 연동했습니다.
/users/me) 적용저장한 작품 목록 기능을 개선했습니다.
북마크 상태 동기화를 추가했습니다.
취향 키워드 재계산 기능을 구현했습니다.
북마크 최소 개수 제한 처리를 서버 에러 응답 기반으로 변경했습니다.
BOOKMARK.CONTENT_MIN_LIMIT에러 수신 시 제한 안내 모달 노출😅 미구현
🫛 To. 리뷰어
Summary by CodeRabbit