Skip to content

[hotfix] 사용자 팔로워 조회시 나인지 여부 반환 플래그 반환#269

Merged
buzz0331 merged 2 commits into
developfrom
hotfix/#268-get-follower
Aug 20, 2025
Merged

[hotfix] 사용자 팔로워 조회시 나인지 여부 반환 플래그 반환#269
buzz0331 merged 2 commits into
developfrom
hotfix/#268-get-follower

Conversation

@buzz0331

@buzz0331 buzz0331 commented Aug 20, 2025

Copy link
Copy Markdown
Contributor

#️⃣ 연관된 이슈

closes #268

📝 작업 내용

@heeeeyong 님의 요청에 따라 사용자 팔로워 조회시에 로그인한 사용자인지 아닌지를 구분하는 isMyself 플래그를 추가합니다.

추가적으로 앞에서 수정했던 특정 책으로 작성된 피드 조회에서 내 피드도 조회되도록 수정하였는데 이에 따른 통합 테스트도 수정하였습니다.

📸 스크린샷

💬 리뷰 요구사항

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

📌 PR 진행 시 이러한 점들을 참고해 주세요

* P1 : 꼭 반영해 주세요 (Request Changes) - 이슈가 발생하거나 취약점이 발견되는 케이스 등
* P2 : 반영을 적극적으로 고려해 주시면 좋을 것 같아요 (Comment)
* P3 : 이런 방법도 있을 것 같아요~ 등의 사소한 의견입니다 (Chore)

Summary by CodeRabbit

  • 신기능
    • 팔로워 목록에 ‘내 계정 여부’ 정보가 추가되어, 목록에서 본인을 명확히 식별할 수 있습니다.
  • 버그 수정
    • 책 관련 피드 조회에서 비공개 피드는 계속 제외되며, 이제 본인의 공개 피드가 정상적으로 함께 표시됩니다(이전에는 자기 자신 피드가 누락될 수 있었습니다).

@coderabbitai

coderabbitai Bot commented Aug 20, 2025

Copy link
Copy Markdown

Walkthrough

사용자 팔로워 응답 DTO에 isMyself 필드가 추가되었고, 이를 매핑하기 위해 FollowQueryMapper가 @context 파라미터(loginUserId)를 받도록 변경되었으며, 서비스에서 해당 파라미터를 전달하도록 수정되었다. 피드 관련 테스트에서 자기 자신 피드 제외 기대값이 변경되었다.

Changes

Cohort / File(s) Change Summary
Follower DTO 확장
src/main/java/konkuk/thip/user/adapter/in/web/response/UserFollowersResponse.java
FollowerDtoboolean isMyself 컴포넌트 추가. 레코드 시그니처 변경 및 빌더/자동 생성 메서드 반영.
Mapper 컨텍스트 추가 및 로직
src/main/java/konkuk/thip/user/application/mapper/FollowQueryMapper.java
toFollowerDto(UserQueryDto, @Context Long)로 시그니처 변경. @Named("isMyself") default boolean isMyself(Long, @Context Long) 추가하여 로그인 사용자와의 동일인 여부 매핑.
서비스 매핑 호출 수정
src/main/java/konkuk/thip/user/application/service/following/UserGetFollowService.java
followQueryMapper.toFollowerDto(dto, userId)로 호출 변경하여 로그인 사용자 ID 컨텍스트 전달. 나머지 페이징/응답 구성은 동일.
피드 테스트 기대값 조정
src/test/java/konkuk/thip/feed/adapter/in/web/FeedRelatedWithBookApiTest.java
테스트 표시 이름 수정 및 예상 개수 1→2로 변경(자기 자신 공개 피드 포함, 비공개 제외 유지).

Sequence Diagram(s)

sequenceDiagram
  participant C as Client
  participant S as UserGetFollowService
  participant M as FollowQueryMapper
  participant R as UserFollowersResponse

  C->>S: getUserFollowers(targetUserId, loginUserId, page)
  S->>S: 조회/페이징 데이터 준비
  loop for each follower UserQueryDto
    S->>M: toFollowerDto(dto, loginUserId)
    M->>M: isMyself(dto.userId, loginUserId)
    M-->>S: FollowerDto(userId, ..., isMyself)
  end
  S-->>C: UserFollowersResponse(list<FollowerDto>, total, pageInfo)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Assessment against linked issues

Objective Addressed Explanation
사용자 팔로워 조회 시 나인지 여부 반환 플래그 추가 (#268)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
자기 자신 피드 제외 기대값 변경 및 테스트 명 수정 (src/test/java/konkuk/thip/feed/adapter/in/web/FeedRelatedWithBookApiTest.java) 링크된 이슈는 팔로워 응답에 isMyself 플래그 추가에 한정되어 있으며, 피드 가시성/필터링 로직 변경은 범위를 벗어남.

Possibly related PRs

Suggested reviewers

  • seongjunnoh

Poem

당근 흔들며 깡총깡총, 깃허브 들판을 달려가요 🥕
팔로워 이름 틈새에, 나인가요? 깃털처럼 가벼운 flag 하나
매퍼는 살짝 귓속말, “맞다면 true!” 하고 윙크
서비스는 조심스레 바구니에 담고
오늘도 PR 한 묶음, 초록 잎사귀처럼 반짝!

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hotfix/#268-get-follower

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions

Copy link
Copy Markdown

Test Results

416 tests   416 ✅  31s ⏱️
124 suites    0 💤
124 files      0 ❌

Results for commit b9792f6.

@buzz0331 buzz0331 merged commit 4985f53 into develop Aug 20, 2025
3 of 4 checks passed
@buzz0331 buzz0331 deleted the hotfix/#268-get-follower branch August 20, 2025 10:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/test/java/konkuk/thip/feed/adapter/in/web/FeedRelatedWithBookApiTest.java (1)

265-269: 표현 변경은 적절합니다만, 메서드명과 불일치합니다

DisplayName은 "비공개 피드 제외 검증"으로 바뀌었는데, 메서드명은 여전히 getFeedsByBook_visibility_and_self_filter로 자기 자신 제외를 암시합니다. 혼동을 줄이기 위해 메서드명을 DisplayName과 일치하도록 정리하는 것을 권장합니다.

src/main/java/konkuk/thip/user/adapter/in/web/response/UserFollowersResponse.java (1)

21-23: API 스키마 확장: isMyself 추가는 요구사항과 부합합니다

클라이언트가 추가 필드에 관대하다면 하위 호환에 큰 문제는 없습니다. 다만 다음을 고려해 주세요:

  • OpenAPI/Swagger 문서에 isMyself 추가 반영 필요.
  • Jackson 환경에서 레코드 컴포넌트 isMyself는 기본적으로 "isMyself"로 직렬화됩니다. 사내 Naming 전략에 특이규칙이 있다면 한 번만 확인해 주세요.

선택사항: 직렬화 명시성을 높이고자 한다면 다음과 같이 @JsonProperty를 추가할 수 있습니다.

+import com.fasterxml.jackson.annotation.JsonProperty;
 ...
     public record FollowerDto(
             Long userId,
             String nickname,
             String profileImageUrl,
             String aliasName,
             String aliasColor,
             Integer followerCount,
-            boolean isMyself
+            @JsonProperty("isMyself") boolean isMyself
     ){

isMyself 추가가 공개 API에 반영되었는지(문서/Mock/스냅샷 테스트 등) 한 번만 확인 부탁드립니다.

src/main/java/konkuk/thip/user/application/mapper/FollowQueryMapper.java (1)

14-21: MapStruct 컨텍스트 매핑 적절합니다

  • @Context@Named를 사용한 isMyself 주입은 의도에 부합합니다.
  • null 방어 로직도 포함되어 있어 안전합니다.

사소한 개선사항: 가독성을 위해 Objects.equals 사용을 고려해 보세요.

다음처럼 단순화 가능합니다:

+import java.util.Objects;
 ...
     @Named("isMyself")
     default boolean isMyself(Long userId, @Context Long loginUserId) {
-        return userId != null && userId.equals(loginUserId);
+        return Objects.equals(userId, loginUserId);
     }

추가로, 서비스에서 반드시 "로그인 사용자 ID"를 Context로 전달해야 의미가 있으므로, 해당 부분이 올바르게 연결되었는지 확인 바랍니다(현재는 대상 사용자 ID가 넘어가고 있어 오동작 가능성이 있습니다 — 서비스 파일 코멘트 참고).

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bd391e1 and b9792f6.

📒 Files selected for processing (4)
  • src/main/java/konkuk/thip/user/adapter/in/web/response/UserFollowersResponse.java (1 hunks)
  • src/main/java/konkuk/thip/user/application/mapper/FollowQueryMapper.java (1 hunks)
  • src/main/java/konkuk/thip/user/application/service/following/UserGetFollowService.java (1 hunks)
  • src/test/java/konkuk/thip/feed/adapter/in/web/FeedRelatedWithBookApiTest.java (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

Comment on lines 38 to 40
var followers = result.contents().stream()
.map(followQueryMapper::toFollowerDto)
.map(dto -> followQueryMapper.toFollowerDto(dto, userId))
.toList();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

isMyself 컨텍스트에 잘못된 userId가 전달되어 항상 false가 됩니다

현재 .map(dto -> followQueryMapper.toFollowerDto(dto, userId))에서 전달되는 userId는 "조회 대상 사용자"의 ID입니다. 그러나 요구사항의 isMyself는 "로그인 사용자" 기준이어야 합니다. 대상 사용자의 팔로워 목록에는 대상 사용자 본인이 포함될 수 없기 때문에, 현 구현은 isMyself가 사실상 항상 false가 되는 버그를 유발합니다.

즉, Mapper에는 로그인 사용자 ID를 전달해야 합니다.

권장 수정 방향:

  • 서비스/유스케이스 시그니처를 확장하여 targetUserId와 loginUserId를 구분 전달합니다.
  • 컨트롤러에서 인증 컨텍스트의 로그인 사용자 ID를 받아 서비스로 전달합니다.

해당 라인에 대한 변경 예시는 다음과 같습니다(참고: 아래 코드는 새로운 매개변수 도입을 전제로 합니다).

-        var followers = result.contents().stream()
-                .map(dto -> followQueryMapper.toFollowerDto(dto, userId))
+        var followers = result.contents().stream()
+                .map(dto -> followQueryMapper.toFollowerDto(dto, loginUserId))
                 .toList();

시그니처 변경(파일 외부 변경)은 아래처럼 반영되어야 합니다:

// UserGetFollowUsecase
UserFollowersResponse getUserFollowers(Long targetUserId, Long loginUserId, String cursor, int size);

// UserGetFollowService
public UserFollowersResponse getUserFollowers(Long targetUserId, Long loginUserId, String cursor, int size) {
    User user = userCommandPort.findById(targetUserId);
    ...
    var followers = result.contents().stream()
            .map(dto -> followQueryMapper.toFollowerDto(dto, loginUserId))
            .toList();
    ...
}

다음 스크립트로 호출부와 시그니처를 점검해 주세요. 기대: 컨트롤러(혹은 호출자)가 로그인 사용자 ID를 별도 인자로 전달하지 않고 있을 가능성이 높습니다.

원하시면 컨트롤러/유스케이스/테스트까지 포함한 전체 변경 패치를 준비하겠습니다.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Interface & Service signatures =="
rg -n -C3 --type=java '\binterface\s+UserGetFollowUsecase\b|class\s+UserGetFollowService\b'
rg -n -C3 --type=java '\bgetUserFollowers\s*\('

echo
echo "== Call sites of getUserFollowers =="
rg -n -C3 --type=java '\bgetUserFollowers\s*\('

echo
echo "== Controllers/resources mentioning followers endpoints =="
rg -n -C3 --type=java 'followers|getUserFollowers|/followers'

Length of output: 16191


로그인 사용자 ID를 컨트롤러→서비스→매퍼로 전달해 isMyself를 올바르게 계산하세요

현재 getUserFollowers(Long userId, String cursor, int size) 메서드에 대상 사용자 ID만 전달되고 있어,
followQueryMapper.toFollowerDto(dto, userId) 호출 시 isMyself가 항상 false로 처리됩니다.
isMyself는 “로그인한 사용자” 기준이어야 합니다.

수정이 필요한 위치:

  • UserGetFollowUsecase#getUserFollowers 시그니처 (src/main/java/.../port/in/UserGetFollowUsecase.java)
  • UserGetFollowService#getUserFollowers 시그니처 및 mapper 호출부
    (src/main/java/.../service/following/UserGetFollowService.java: 라인 29–40)
  • UserQueryController#showFollowers
    (src/main/java/.../adapter/in/web/UserQueryController.java: 라인 81)
  • Mapper 호출부:
    followQueryMapper.toFollowerDto(dto, userId)followQueryMapper.toFollowerDto(dto, loginUserId)

예시 diff:

// src/main/java/konkuk/thip/user/application/port/in/UserGetFollowUsecase.java
-public interface UserGetFollowUsecase {
-    UserFollowersResponse getUserFollowers(Long userId, String cursor, int size);
+public interface UserGetFollowUsecase {
+    UserFollowersResponse getUserFollowers(Long targetUserId, Long loginUserId, String cursor, int size);

// src/main/java/konkuk/thip/user/application/service/following/UserGetFollowService.java
-    public UserFollowersResponse getUserFollowers(Long userId, String cursor, int size) {
+    public UserFollowersResponse getUserFollowers(Long targetUserId, Long loginUserId, String cursor, int size) {
         User user = userCommandPort.findById(targetUserId);
         ...
-        var followers = result.contents().stream()
-            .map(dto -> followQueryMapper.toFollowerDto(dto, userId))
+        var followers = result.contents().stream()
+            .map(dto -> followQueryMapper.toFollowerDto(dto, loginUserId))
             .toList();

// src/main/java/konkuk/thip/user/adapter/in/web/UserQueryController.java
-    return BaseResponse.ok(userGetFollowUsecase.getUserFollowers(userId, cursor, size));
+    Long loginUserId = authContext.getLoginUserId();
+    return BaseResponse.ok(
+        userGetFollowUsecase.getUserFollowers(userId, loginUserId, cursor, size)
+    );

테스트 및 매퍼 구현도 함께 업데이트해야 합니다.

📝 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
var followers = result.contents().stream()
.map(followQueryMapper::toFollowerDto)
.map(dto -> followQueryMapper.toFollowerDto(dto, userId))
.toList();
var followers = result.contents().stream()
.map(dto -> followQueryMapper.toFollowerDto(dto, loginUserId))
.toList();
🤖 Prompt for AI Agents
In
src/main/java/konkuk/thip/user/application/service/following/UserGetFollowService.java
around lines 38–40, the service passes the target userId into
followQueryMapper.toFollowerDto(dto, userId) causing isMyself to always be
false; change the service and related usecase/controller signatures to accept
and forward the currently logged-in user's ID (e.g., loginUserId) from
UserQueryController#showFollowers → UserGetFollowUsecase#getUserFollowers →
UserGetFollowService#getUserFollowers, and update the mapper call to
followQueryMapper.toFollowerDto(dto, loginUserId); also update corresponding
interface signatures, controller invocation, and tests/mapper implementations to
use loginUserId throughout.

Comment on lines 306 to 310
// 자기 자신 글 제외 비공개 제외로 인해 only othersPublic 만 남아야 함
assertThat(feeds.size()).isEqualTo(1);
assertThat(feeds.size()).isEqualTo(2);
assertThat(feeds.get(0).path("creatorId").asLong()).isEqualTo(other.getUserId());
assertThat(feeds.get(0).path("isWriter").asBoolean()).isFalse();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

주석/검증 불일치 및 순서 의존으로 인한 테스트 취약성

  • 주석은 "자기 자신 글 제외"라고 되어 있으나, 현재 요구사항은 "자기 자신 글 포함"입니다.
  • 첫 번째 요소가 다른 사용자의 피드라고 가정하는 검증은 정렬/동률 상황에서 쉽게 깨지는 플래키 테스트를 야기합니다.

아래처럼 순서 비의존적이고 새로운 요구사항에 맞는 검증으로 교체해 주세요.

다음 diff를 적용하세요:

-        // 자기 자신 글 제외 비공개 제외로 인해 only othersPublic 만 남아야 함
-        assertThat(feeds.size()).isEqualTo(2);
-        assertThat(feeds.get(0).path("creatorId").asLong()).isEqualTo(other.getUserId());
-        assertThat(feeds.get(0).path("isWriter").asBoolean()).isFalse();
+        // 비공개 제외 + 자기 자신 글 포함 검증: 공개 글 2개만 반환되어야 함
+        assertThat(feeds.size()).isEqualTo(2);
+
+        boolean hasMyPublic = false;
+        boolean hasOthersPublic = false;
+        for (JsonNode f : feeds) {
+            long creatorId = f.path("creatorId").asLong();
+            boolean isWriter = f.path("isWriter").asBoolean();
+            if (creatorId == requester.getUserId()) {
+                assertThat(isWriter).isTrue();
+                hasMyPublic = true;
+            }
+            if (creatorId == other.getUserId()) {
+                assertThat(isWriter).isFalse();
+                hasOthersPublic = true;
+            }
+        }
+        assertThat(hasMyPublic).isTrue();
+        assertThat(hasOthersPublic).isTrue();
📝 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
// 자기 자신 글 제외 비공개 제외로 인해 only othersPublic 만 남아야 함
assertThat(feeds.size()).isEqualTo(1);
assertThat(feeds.size()).isEqualTo(2);
assertThat(feeds.get(0).path("creatorId").asLong()).isEqualTo(other.getUserId());
assertThat(feeds.get(0).path("isWriter").asBoolean()).isFalse();
}
// 비공개 제외 + 자기 자신 글 포함 검증: 공개 글 2개만 반환되어야 함
assertThat(feeds.size()).isEqualTo(2);
boolean hasMyPublic = false;
boolean hasOthersPublic = false;
for (JsonNode f : feeds) {
long creatorId = f.path("creatorId").asLong();
boolean isWriter = f.path("isWriter").asBoolean();
if (creatorId == requester.getUserId()) {
assertThat(isWriter).isTrue();
hasMyPublic = true;
}
if (creatorId == other.getUserId()) {
assertThat(isWriter).isFalse();
hasOthersPublic = true;
}
}
assertThat(hasMyPublic).isTrue();
assertThat(hasOthersPublic).isTrue();
}
🤖 Prompt for AI Agents
In src/test/java/konkuk/thip/feed/adapter/in/web/FeedRelatedWithBookApiTest.java
around lines 306 to 310, the test comment and assertions assume "self posts
excluded" and rely on feeds.get(0) ordering, but requirement now includes self
posts and the index-based check is brittle; replace with order-independent
assertions: assert the feeds size is 2, collect creatorId values into a set and
assert it equals the set of the current user's ID and the other user's ID, and
for each feed assert isWriter is true when creatorId equals the current user's
ID and false otherwise; also update the comment to reflect "자기 자신 글 포함" (self
posts included).

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[THIP2025-317] [hotfix] 사용자 팔로워 조회시 나인지 여부 반환 플래그 반환

1 participant