[FEAT] 마이페이지 키스크린 통합 데이터 컬럼 추가#138
Conversation
📝 WalkthroughWalkthroughRefactored MyPage controller (renamed from Changes
Sequence DiagramsequenceDiagram
participant Client
participant Controller as MyPageKeyScreenController
participant Facade as MyPageKeyScreenFacadeService
participant ProfileService as MeProfileWithStatsService
participant Repository as MeProfileWithStatsQueryRepository
participant Database
Client->>Controller: GET /mypage?month=YYYY-MM
Controller->>Controller: Extract userId, email from userDetails
Controller->>Facade: getMyPage(userId, email, month)
Facade->>ProfileService: getMyProfileWithStats(userId, email)
ProfileService->>Repository: findMeProfileWithStats(userId, "DONE")
Repository->>Database: Execute native SQL query
Database-->>Repository: MeProfileWithStatsProjection
Repository-->>ProfileService: Query result
ProfileService->>ProfileService: Map to MeProfileWithStatsResponse
ProfileService-->>Facade: MeProfileWithStatsResponse
Facade->>Facade: Build MyPageKeyScreenResponse with profile + insights
Facade-->>Controller: MyPageKeyScreenResponse
Controller->>Controller: Wrap in ApiResponse
Controller-->>Client: ApiResponse<MyPageKeyScreenResponse>
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly Related Issues
Possibly Related PRs
Suggested Labels
Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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: 2
🤖 Fix all issues with AI agents
In
`@booklog/src/main/java/com/example/booklog/domain/users/dto/MyPageKeyScreenResponse.java`:
- Around line 34-39: MyPageKeyScreenResponse currently exposes the user's email
(PII) via the ProfileSummary/ email field; remove or hide it from the serialized
API response by either removing the email property from
MyPageKeyScreenResponse/ProfileSummary or marking the email accessor with a
serialization ignore (e.g., annotate getEmail in ProfileSummary or the email
field in MyPageKeyScreenResponse with `@JsonIgnore`) and ensure any internal-only
access uses a separate internal DTO or method; also audit usages of
MyPageKeyScreenResponse/ProfileSummary to avoid caching or debug-logging the
email (remove logging of email or wrap with redaction) so PII is never sent to
shared caches or logs.
In
`@booklog/src/main/java/com/example/booklog/domain/users/repository/MeProfileWithStatsQueryRepository.java`:
- Around line 13-48: Add missing DB indexes used by
MeProfileWithStatsQueryRepository's native query: update the JPA entity for the
user_follows table to include two `@Index` entries named idx_user_follows_follower
(columnList="follower_id") and idx_user_follows_followee
(columnList="followee_id"), and update the booklog_bookmark entity to add an
`@Index` named idx_booklog_bookmark_user (columnList="user_id"); ensure these
annotations are placed on the `@Table`(...) of the corresponding entity classes so
COUNT subqueries in MeProfileWithStatsQueryRepository will use single-column
indexes for follower_id, followee_id and user_id.
| String email, | ||
| long followerCount, | ||
| long followingCount, | ||
| long completedBookCount, | ||
| long myBooklogCount, | ||
| long bookmarkCount |
There was a problem hiding this comment.
Consider whether email should be exposed in this API response.
The user's email (PII) is now included in the ProfileSummary returned by the MyPage endpoint. Since this is the authenticated user's own profile, it's likely intentional, but ensure this response is not cached in shared caches or logged at debug level, as it would leak PII.
🤖 Prompt for AI Agents
In
`@booklog/src/main/java/com/example/booklog/domain/users/dto/MyPageKeyScreenResponse.java`
around lines 34 - 39, MyPageKeyScreenResponse currently exposes the user's email
(PII) via the ProfileSummary/ email field; remove or hide it from the serialized
API response by either removing the email property from
MyPageKeyScreenResponse/ProfileSummary or marking the email accessor with a
serialization ignore (e.g., annotate getEmail in ProfileSummary or the email
field in MyPageKeyScreenResponse with `@JsonIgnore`) and ensure any internal-only
access uses a separate internal DTO or method; also audit usages of
MyPageKeyScreenResponse/ProfileSummary to avoid caching or debug-logging the
email (remove logging of email or wrap with redaction) so PII is never sent to
shared caches or logs.
| @Query(value = """ | ||
| SELECT | ||
| u.user_id AS userId, | ||
| u.nickname AS nickname, | ||
| u.profile_image_url AS avatarUrl, | ||
|
|
||
| /* settings 없으면 기본 true(=1) */ | ||
| IFNULL(us.is_shelf_public, 1) AS isShelfPublic, | ||
| IFNULL(us.is_post_public, 1) AS isBooklogPublic, | ||
|
|
||
| (SELECT COUNT(*) | ||
| FROM user_follows f | ||
| WHERE f.followee_id = u.user_id) AS followerCount, | ||
|
|
||
| (SELECT COUNT(*) | ||
| FROM user_follows f | ||
| WHERE f.follower_id = u.user_id) AS followingCount, | ||
|
|
||
| (SELECT COUNT(*) | ||
| FROM user_books ub | ||
| WHERE ub.user_id = u.user_id | ||
| AND ub.status = :completedStatus) AS completedBookCount, | ||
|
|
||
| (SELECT COUNT(*) | ||
| FROM booklog_posts p | ||
| WHERE p.user_id = u.user_id) AS myBooklogCount, | ||
|
|
||
| (SELECT COUNT(*) | ||
| FROM booklog_bookmark b | ||
| WHERE b.user_id = u.user_id) AS bookmarkCount | ||
|
|
||
| FROM users u | ||
| LEFT JOIN user_settings us ON us.user_id = u.user_id | ||
| WHERE u.user_id = :userId | ||
| LIMIT 1 | ||
| """, nativeQuery = true) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -type f \( -name "*.sql" -o -name "*Migration*.java" -o -name "*migration*.xml" \) | head -20Repository: Project-BookLog/BookLog-BackEnd
Length of output: 57
🏁 Script executed:
rg -l "user_follows|user_books|booklog_posts|booklog_bookmark" --type sql --type java | head -20Repository: Project-BookLog/BookLog-BackEnd
Length of output: 1789
🏁 Script executed:
rg -n "CREATE INDEX|ADD INDEX|@Index|@Table" -C 3 --type sql --type java | grep -A3 -B3 "user_follows\|user_books\|booklog_posts\|booklog_bookmark\|user_settings" | head -60Repository: Project-BookLog/BookLog-BackEnd
Length of output: 4992
🏁 Script executed:
# Look for the entity files themselves
fd -e java "User" -o "Book" -o "Follow" -o "Post" | grep -i "entity\|domain" | head -20Repository: Project-BookLog/BookLog-BackEnd
Length of output: 202
🏁 Script executed:
# Check the specific file being reviewed
cat -n "booklog/src/main/java/com/example/booklog/domain/users/repository/MeProfileWithStatsQueryRepository.java"Repository: Project-BookLog/BookLog-BackEnd
Length of output: 2139
🏁 Script executed:
cat -n booklog/src/main/java/com/example/booklog/domain/users/entity/UserFollows.javaRepository: Project-BookLog/BookLog-BackEnd
Length of output: 2898
🏁 Script executed:
cat -n booklog/src/main/java/com/example/booklog/domain/booklog/entity/BooklogBookmark.javaRepository: Project-BookLog/BookLog-BackEnd
Length of output: 1110
🏁 Script executed:
# Search for ReadingStatus enum and completedStatus usage
rg -n "ReadingStatus\|completedStatus" --type java -B2 -A2 | head -60Repository: Project-BookLog/BookLog-BackEnd
Length of output: 57
🏁 Script executed:
# Find the service/controller that calls findMeProfileWithStats to check enum handling
rg -n "findMeProfileWithStats\|ReadingStatus.COMPLETED" --type java -B3 -A3Repository: Project-BookLog/BookLog-BackEnd
Length of output: 57
🏁 Script executed:
# Search for ReadingStatus enum
rg -n "enum ReadingStatus|class ReadingStatus" --type java -A10Repository: Project-BookLog/BookLog-BackEnd
Length of output: 2258
🏁 Script executed:
# Search for where MeProfileWithStatsQueryRepository is called
rg -n "MeProfileWithStatsQueryRepository|findMeProfileWithStats" --type java -B2 -A4Repository: Project-BookLog/BookLog-BackEnd
Length of output: 4930
🏁 Script executed:
# Look for migration files that might define indexes
find . -type f \( -name "*migration*" -o -name "*Migration*" -o -name "*.sql" \) 2>/dev/null | head -20Repository: Project-BookLog/BookLog-BackEnd
Length of output: 57
🏁 Script executed:
# Check if there are Flyway or Liquibase migrations
find . -path "*/db/migration*" -o -path "*/flyway*" -o -path "*/liquibase*" 2>/dev/null | head -20Repository: Project-BookLog/BookLog-BackEnd
Length of output: 57
Add missing indexes on user_follows and booklog_bookmark tables for query performance.
The correlated subqueries are acceptable for single-user lookups, but three of the five subquery tables lack the necessary indexes:
-
user_follows: No@Indexonfollowee_idorfollower_id. These columns are part of a composite primary key but filtering by a single column requires individual indexes. Add:indexes = { `@Index`(name = "idx_user_follows_follower", columnList = "follower_id"), `@Index`(name = "idx_user_follows_followee", columnList = "followee_id") }
-
booklog_bookmark: Has a unique constraint on(user_id, post_id)but no dedicated index onuser_idalone. Add:`@Index`(name = "idx_booklog_bookmark_user", columnList = "user_id")
-
user_booksandbooklog_postsalready have the required indexes.
Without these indexes, the COUNT queries will degrade as these tables grow.
🤖 Prompt for AI Agents
In
`@booklog/src/main/java/com/example/booklog/domain/users/repository/MeProfileWithStatsQueryRepository.java`
around lines 13 - 48, Add missing DB indexes used by
MeProfileWithStatsQueryRepository's native query: update the JPA entity for the
user_follows table to include two `@Index` entries named idx_user_follows_follower
(columnList="follower_id") and idx_user_follows_followee
(columnList="followee_id"), and update the booklog_bookmark entity to add an
`@Index` named idx_booklog_bookmark_user (columnList="user_id"); ensure these
annotations are placed on the `@Table`(...) of the corresponding entity classes so
COUNT subqueries in MeProfileWithStatsQueryRepository will use single-column
indexes for follower_id, followee_id and user_id.
#137
Summary by CodeRabbit