Skip to content

[hotfix] 조회 시 isWriter response 전체 추가#223

Merged
seongjunnoh merged 12 commits into
developfrom
hotfix/#220-iswriter
Aug 14, 2025
Merged

[hotfix] 조회 시 isWriter response 전체 추가#223
seongjunnoh merged 12 commits into
developfrom
hotfix/#220-iswriter

Conversation

@hd0rable

@hd0rable hd0rable commented Aug 14, 2025

Copy link
Copy Markdown
Member

#️⃣ 연관된 이슈

closes #220

📝 작업 내용

  • PE분들의 요청에따라 피드조회,댓글조회시 작성자인지 나타내는 isWriter필드를 추가했습니다.
  • 내피드 조회,전체 피드 조회,특정 유저 피드 조회,댓글 조회 시 추가했습니다.
  • postman으로 정상응답 받아오는것 모든 api에서 확인했습니다

📸 스크린샷

image

💬 리뷰 요구사항

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

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

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

Summary by CodeRabbit

  • 신기능
    • 피드 응답(전체, 팔로잉 우선, 내 피드, 특정 사용자 피드, 단일 피드)에 작성자 여부(isWriter) 필드를 추가했습니다. 현재 로그인한 사용자가 작성한 피드인지 식별할 수 있습니다.
    • 단일 게시물의 댓글 응답(루트 댓글 및 대댓글)에 작성자 여부(isWriter) 필드를 추가했습니다. 각 댓글이 본인 작성인지 확인할 수 있어 목록과 상세 화면에서 일관된 표시가 가능합니다.

@coderabbitai

coderabbitai Bot commented Aug 14, 2025

Copy link
Copy Markdown

Walkthrough

댓글과 피드 조회 전반에 isWriter 필드를 응답에 추가. 이를 위해 댓글/피드 응답 DTO에 필드 추가, MapStruct 매퍼에 @context userId 전파 및 isWriter 매핑 로직 도입, 각 서비스에서 매퍼 호출부 인자 확장. 일부 피드 조회 관련 persistence 계층 메서드의 파라미터명(userId→feedOwnerId) 변경.

Changes

Cohort / File(s) Summary
Comment response DTOs
src/main/java/konkuk/thip/comment/adapter/in/web/response/CommentForSinglePostResponse.java
RootCommentDto, ReplyDto에 boolean isWriter 필드 추가. 생성자/팩토리 메서드 시그니처 갱신 및 파라미터 명 오타 수정(replyLis→replyList).
Comment mapping & service
src/main/java/konkuk/thip/comment/application/mapper/CommentQueryMapper.java, src/main/java/konkuk/thip/comment/application/service/CommentShowAllService.java
매퍼 메서드들에 @context Long userId 추가, @nAmed("isWriter")로 작성자 여부 매핑 도입. 서비스에서 매퍼 호출 시 userId 전파.
Feed response DTOs
src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowAllResponse.java, .../FeedShowByUserResponse.java, .../FeedShowMineResponse.java, .../FeedShowSingleResponse.java
각 Feed 응답 레코드/중첩 레코드에 boolean isWriter 필드 추가(위치 파일별 상이).
Feed mapper
src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java
다수 매퍼 시그니처에 @context Long userId 추가. @nAmed("isWriter") 추가 및 dto.creatorId/feedCreator.id로 isWriter 매핑.
Feed services
src/main/java/konkuk/thip/feed/application/service/BasicFeedShowAllService.java, .../FollowingPriorityFeedShowAllService.java, .../FeedShowAllOfUserService.java, .../FeedShowSingleService.java
매퍼 호출부에 userId 추가 전달로 시그니처 변경 반영.
Feed persistence (naming)
src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java, .../repository/FeedQueryRepository.java, .../repository/FeedQueryRepositoryImpl.java, .../repository/FeedJpaRepository.java, src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java
findSpecificUserFeedsByCreatedAt 첫 파라미터명 userId→feedOwnerId로 변경. 기능/흐름 변경 없음.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant Controller as Feed Controller
  participant Service as Feed Show Services
  participant Mapper as FeedQueryMapper
  participant Repo as FeedQueryPort/Repositories

  User->>Controller: GET /feeds
  Controller->>Service: showAllFeeds(userId, cursor)
  Service->>Repo: find... (cursor)
  Repo-->>Service: List<FeedQueryDto>
  Service->>Mapper: toFeedShowAllResponse(dto, savedIds, likedIds, userId)
  Mapper-->>Service: FeedDto (isWriter computed)
  Service-->>Controller: Response DTOs
  Controller-->>User: 200 OK (isWriter 포함)
Loading
sequenceDiagram
  actor User
  participant Controller as Comment Controller
  participant Service as CommentShowAllService
  participant Mapper as CommentQueryMapper
  participant Repo as CommentQueryPort

  User->>Controller: GET /posts/{id}/comments
  Controller->>Service: showAllCommentsOfPost(query with userId)
  Service->>Repo: load root/child comments + likedIds
  Repo-->>Service: CommentQueryDtos, likedIds
  Service->>Mapper: toRootCommentResponseWithChildren(root, children, likedIds, userId)
  Mapper-->>Service: RootCommentDto/ReplyDto (isWriter 포함)
  Service-->>Controller: Response
  Controller-->>User: 200 OK (isWriter 포함)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
조회 응답 전반에 isWriter 필드 추가 및 전파 (#220)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
findSpecificUserFeedsByCreatedAt 첫 파라미터명 userId→feedOwnerId로 변경 (src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java) 이슈 #220의 isWriter 응답 추가와 직접적인 관련 없음. 네이밍 변경은 범위를 벗어남.
동일 메서드 파라미터명 변경 (src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepository.java) 기능 변화 없는 네이밍 변경으로, 이슈 목적과 무관.
동일 메서드 파라미터명/전파 변경 (src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java) 이슈 목적과 무관한 리팩터링 성격.
동일 메서드 파라미터명 변경 (src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedJpaRepository.java) 이슈 범위를 벗어남.
동일 메서드 파라미터명 변경 (src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java) 이슈와 직접 관련 없음.

Possibly related PRs

Suggested labels

👻 성준

Suggested reviewers

  • buzz0331

Poem

솜털 귀 쫑긋, 깡충깡충 코드밭 누비네
isWriter 한 알, 응답에 톡— 심었네
피드도 댓글도, 주인공 표시 완료!
사용자는 웃고, 토끼는 꿀떡 당근 한 입 🥕
오늘도 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/#220-iswriter

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
🪧 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

github-actions Bot commented Aug 14, 2025

Copy link
Copy Markdown

Test Results

393 tests   393 ✅  31s ⏱️
118 suites    0 💤
118 files      0 ❌

Results for commit 0b134e2.

♻️ This comment has been updated with latest results.

@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: 5

🔭 Outside diff range comments (5)
src/main/java/konkuk/thip/comment/application/service/CommentShowAllService.java (1)

42-45: 좋아요 집계 누락 버그: 자식이 없는 루트 댓글의 ID가 allCommentIds에서 빠질 수 있음

현재 parseAllCommentIds(childrenMap)childrenMap.keySet()으로 루트 댓글 ID를 수집합니다. 구현체가 “자식이 없는 루트”에 대해 빈 리스트 엔트리를 넣지 않는 경우, 해당 루트 댓글의 ID가 allCommentIds에 포함되지 않아, 그 루트 댓글의 좋아요 상태가 항상 false로 처리될 위험이 있습니다.

루트 댓글 리스트(rootsInOrder) 기반으로 모든 루트 ID를 먼저 포함시키고, 이후 모든 자식 댓글 ID를 추가하도록 수정해 주세요.

적용 diff:

-        Set<Long> allCommentIds = parseAllCommentIds(childrenMap);
+        Set<Long> allCommentIds = parseAllCommentIds(rootsInOrder, childrenMap);

그리고 메서드 구현 수정:

-    private Set<Long> parseAllCommentIds(Map<Long, List<CommentQueryDto>> childrenMap) {
-        Set<Long> allCommentIds = new HashSet<>(childrenMap.keySet());  // 루트 댓글들
-        for (Long rootCommentId : childrenMap.keySet()) {
-            childrenMap.get(rootCommentId).stream()
-                    .map(CommentQueryDto::commentId)
-                    .forEach(allCommentIds::add);
-        }
-        return allCommentIds;
-    }
+    private Set<Long> parseAllCommentIds(List<CommentQueryDto> roots,
+                                         Map<Long, List<CommentQueryDto>> childrenMap) {
+        // 1) 모든 루트 댓글 ID 선반영
+        Set<Long> allCommentIds = roots.stream()
+                .map(CommentQueryDto::commentId)
+                .collect(HashSet::new, Set::add, Set::addAll);
+        // 2) 모든 자식 댓글 ID 추가
+        for (List<CommentQueryDto> children : childrenMap.values()) {
+            for (CommentQueryDto child : children) {
+                allCommentIds.add(child.commentId());
+            }
+        }
+        return allCommentIds;
+    }

Also applies to: 56-64

src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java (1)

200-215: 특정 유저 피드 조회 시 본인 요청일 경우 비공개까지 포함하도록 분기 필요

현재 findSpecificUserFeedsByCreatedAt는 항상 공개글만 조회합니다. 요청자(userId)와 대상(feedOwnerId)이 동일한 경우, 비공개 글까지 포함되어야 UX가 자연스럽습니다. 간단히 기존의 "내 피드" 쿼리를 재사용하는 분기로 해결 가능합니다.

적용 제안:

-    public List<FeedQueryDto> findSpecificUserFeedsByCreatedAt(Long userId, Long feedOwnerId, LocalDateTime lastCreatedAt, int size) {
-        // 1. 특정 유저 피드 ID 목록만 최신순 페이징 조회
-        List<Long> feedIds = fetchSpecificUserFeedIdsByCreatedAt(feedOwnerId, lastCreatedAt, size);
+    public List<FeedQueryDto> findSpecificUserFeedsByCreatedAt(Long userId, Long feedOwnerId, LocalDateTime lastCreatedAt, int size) {
+        // 1. 특정 유저 피드 ID 목록만 최신순 페이징 조회
+        List<Long> feedIds =
+                (userId != null && userId.equals(feedOwnerId))
+                        ? fetchMyFeedIdsByCreatedAt(feedOwnerId, lastCreatedAt, size)       // 본인 요청: 비공개 포함
+                        : fetchSpecificUserFeedIdsByCreatedAt(feedOwnerId, lastCreatedAt, size); // 타인 요청: 공개만
src/main/java/konkuk/thip/comment/adapter/out/persistence/repository/CommentQueryRepositoryImpl.java (3)

32-47: userId null 시 QueryDSL Projection에 null Expression 전달 위험 (런타임 오류 가능성)

commentCreator.userId.eq(userId)userId == null일 때 null Expression을 생성하여 .select(proj)에서 런타임 오류가 날 수 있습니다. null이면 항상 false로 간주하도록 안전 가드를 넣어주세요.

-        QCommentQueryDto proj = new QCommentQueryDto(
+        QCommentQueryDto proj = new QCommentQueryDto(
                 comment.commentId,
                 commentCreator.userId,
                 aliasOfCommentCreator.imageUrl,
                 commentCreator.nickname,
                 aliasOfCommentCreator.value,
                 aliasOfCommentCreator.color,
                 comment.createdAt,
                 comment.content,
                 comment.likeCount,
-                comment.status.eq(StatusType.INACTIVE),      // 루트 댓글이 삭제된 상태인지 아닌지,
-                commentCreator.userId.eq(userId)
+                comment.status.eq(StatusType.INACTIVE),      // 루트 댓글이 삭제된 상태인지 아닌지,
+                (userId != null) ? commentCreator.userId.eq(userId) : Expressions.FALSE
         );

70-93: userId null 가드 + 파라미터 공백 컨벤션

자식 댓글 프로젝션도 동일 이슈입니다. 또한 메서드 시그니처의 공백 컨벤션을 정리하면 좋습니다.

-    public List<CommentQueryDto> findAllActiveChildCommentsByCreatedAtAsc(Long rootCommentId,Long userId) {
+    public List<CommentQueryDto> findAllActiveChildCommentsByCreatedAtAsc(Long rootCommentId, Long userId) {
-        QCommentQueryDto childProj = new QCommentQueryDto(
+        QCommentQueryDto childProj = new QCommentQueryDto(
                 comment.commentId,
                 comment.parent.commentId,
                 parentCommentCreator.nickname,
                 commentCreator.userId,
                 aliasOfCommentCreator.imageUrl,
                 commentCreator.nickname,
                 aliasOfCommentCreator.value,
                 aliasOfCommentCreator.color,
                 comment.createdAt,
                 comment.content,
                 comment.likeCount,
-                comment.status.eq(StatusType.INACTIVE),
-                commentCreator.userId.eq(userId)
+                comment.status.eq(StatusType.INACTIVE),
+                (userId != null) ? commentCreator.userId.eq(userId) : Expressions.FALSE
         );

124-156: 여러 루트 ID 대상 자식 댓글 프로젝션도 동일한 null 가드 필요 + 공백 컨벤션

다중 루트 조회용 프로젝션에서도 동일한 null 전달 위험이 있습니다. 시그니처 공백도 함께 정리하세요.

-    public Map<Long, List<CommentQueryDto>> findAllActiveChildCommentsByCreatedAtAsc(Set<Long> rootCommentIds,Long userId) {
+    public Map<Long, List<CommentQueryDto>> findAllActiveChildCommentsByCreatedAtAsc(Set<Long> rootCommentIds, Long userId) {
-        QCommentQueryDto childProj = new QCommentQueryDto(
+        QCommentQueryDto childProj = new QCommentQueryDto(
                 comment.commentId,
                 comment.parent.commentId,
                 parentCommentCreator.nickname,
                 commentCreator.userId,
                 aliasOfCommentCreator.imageUrl,
                 commentCreator.nickname,
                 aliasOfCommentCreator.value,
                 aliasOfCommentCreator.color,
                 comment.createdAt,
                 comment.content,
                 comment.likeCount,
-                comment.status.eq(StatusType.INACTIVE),
-                commentCreator.userId.eq(userId)
+                comment.status.eq(StatusType.INACTIVE),
+                (userId != null) ? commentCreator.userId.eq(userId) : Expressions.FALSE
         );
🧹 Nitpick comments (8)
src/main/java/konkuk/thip/feed/application/port/out/dto/FeedQueryDto.java (1)

24-26: 비로그인(anonymous) 또는 userId 미전달 시 isWriter 의미를 명시하세요

현재 타입이 primitive boolean이라 null 표현이 불가합니다. 미인증/미전달 시 false로 일괄 설정하는 정책이라면, 주석/Javadoc 혹은 API 스펙(Swagger)에 이를 명시해 클라이언트 혼선을 줄이는 것을 권장합니다.

src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowByUserResponse.java (1)

31-33: OpenAPI 문서 보강(선택): isWriter 의미를 스키마에 명시하세요

Swagger 스키마에 isWriter 의미를 넣어두면 클라이언트 혼선을 줄일 수 있습니다. 아래처럼 컴포넌트에 주석을 추가하는 것을 고려해 주세요.

             boolean isLiked,
-            boolean isWriter
+            @Schema(description = "요청자와 작성자가 동일한 경우 true")
+            boolean isWriter
src/main/java/konkuk/thip/comment/application/port/out/dto/CommentQueryDto.java (1)

20-22: isWriter Boolean 사용에 따른 null-안전성 점검 필요

record 컴포넌트가 Boolean(wrapper)로 선언되어 있어, DB/프로젝션에서 null이 들어오면 이후 계층에서 unboxing 시 NPE가 발생할 수 있습니다. FE 요구사항상 항상 boolean 응답이 필요하다면, 최소한 API 응답 DTO에서는 primitive boolean으로 보장되도록 매핑하거나, 여기서도 primitive로 통일하는 방안을 검토해 주세요. 현재 isDeleted도 Boolean이므로 일관된 처리가 필요합니다.

다음 사항을 확인해 주세요:

  • 레포지토리/프로젝션에서 isWriter가 항상 non-null로 계산/리턴되는지
  • API 응답 DTO에서 isWriter가 primitive boolean으로 보장되는지 (null -> false 기본값)

필요하다면, 매퍼에서 null-safe 기본값 처리를 추가하도록 도와드릴 수 있습니다.

src/main/java/konkuk/thip/feed/application/service/FeedShowAllOfUserService.java (1)

52-53: 호출부 시그니처 반영 — LGTM. 다만 계산 위치 단순화 가능

특정 유저의 공개 피드 목록에서는 모든 아이템의 작성자가 feedOwnerId이므로 isWriteruserId.equals(feedOwnerId)로 상수값(전부 true/false)입니다. 성능/복잡도 관점에서 이 케이스만큼은 DB/포트 계층으로 전달하지 않고 서비스/매퍼에서 계산하는 방안도 고려해볼 수 있습니다. 현재는 핫픽스 목적이므로 추후 리팩터로 제안드립니다.

src/main/java/konkuk/thip/comment/application/port/out/CommentQueryPort.java (1)

13-17: userId null 계약 명시 필요 + 파라미터 스타일 정리

  • 현재 하위 레이어에서 userId가 null일 때 eq(userId) 평가 중 NPE/Invalid expression 위험이 있습니다(아래 Repository 구현 코멘트 참조). 포트 시그니처에서 null 불허를 계약으로 못 박거나, null 허용 시의 동작(예: isWriter 항상 false)을 명확히 해 주세요.
  • 사소하지만, 쉼표 뒤 공백(Long rootCommentId, Long userId) 유지로 일관성 개선 권장.
src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java (1)

82-82: 사소: 공백 컨벤션 정리

쉼표 뒤 공백 누락으로 코드 스타일 일관성이 깨집니다.

-                .map(e -> toDto(e, priorityMap.get(e.getPostId()),userId))
+                .map(e -> toDto(e, priorityMap.get(e.getPostId()), userId))
-                .map(e -> toDto(e, null, userId))
+                .map(e -> toDto(e, null, userId))
-                .map(e -> toDto(e, null, userId))
+                .map(e -> toDto(e, null, userId))
-                .map(e -> toDto(e, null, userId))
+                .map(e -> toDto(e, null, userId))

Also applies to: 104-104, 195-195, 214-214

src/main/java/konkuk/thip/comment/adapter/out/persistence/CommentQueryPersistenceAdapter.java (1)

38-45: 사소: 파라미터 서식 정리(Long rootCommentId, Long userId / Set rootCommentIds, Long userId)

쉼표 뒤 공백 누락을 정리하면 가독성이 좋아집니다.

-    public List<CommentQueryDto> findAllActiveChildCommentsOldestFirst(Long rootCommentId,Long userId) {
+    public List<CommentQueryDto> findAllActiveChildCommentsOldestFirst(Long rootCommentId, Long userId) {
-    public Map<Long, List<CommentQueryDto>> findAllActiveChildCommentsOldestFirst(Set<Long> rootCommentIds,Long userId) {
+    public Map<Long, List<CommentQueryDto>> findAllActiveChildCommentsOldestFirst(Set<Long> rootCommentIds, Long userId) {
src/main/java/konkuk/thip/comment/adapter/out/persistence/repository/CommentQueryRepositoryImpl.java (1)

94-121: 계층 자식 조회 반복 루프의 성능 고려

깊은 트리나 팬아웃이 큰 경우 while 루프의 단계별 조회가 다수의 쿼리를 유발합니다. 현재 요구사항상 기능적으로 문제없지만, 성능 이슈가 관측되면 다음을 검토해 주세요:

  • 동일 루프 내에서 parentIds를 가능한 한 크게 묶어 배치 질의 유지(이미 그렇게 되어 있음).
  • 필요 시 한 번의 쿼리로 전체 서브트리를 가져와 메모리에서 그룹핑/정렬(데이터 규모에 따라 trade-off).
  • 페이징 요구가 생기면 BFS/DFS 순회 기준으로 커서 도입.

Also applies to: 157-191

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4a095b4 and f093c0c.

📒 Files selected for processing (19)
  • src/main/java/konkuk/thip/comment/adapter/in/web/response/CommentForSinglePostResponse.java (3 hunks)
  • src/main/java/konkuk/thip/comment/adapter/out/persistence/CommentQueryPersistenceAdapter.java (2 hunks)
  • src/main/java/konkuk/thip/comment/adapter/out/persistence/repository/CommentQueryRepository.java (1 hunks)
  • src/main/java/konkuk/thip/comment/adapter/out/persistence/repository/CommentQueryRepositoryImpl.java (6 hunks)
  • src/main/java/konkuk/thip/comment/application/port/out/CommentQueryPort.java (1 hunks)
  • src/main/java/konkuk/thip/comment/application/port/out/dto/CommentQueryDto.java (2 hunks)
  • src/main/java/konkuk/thip/comment/application/service/CommentShowAllService.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowAllResponse.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowByUserResponse.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowMineResponse.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowSingleResponse.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepository.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java (6 hunks)
  • src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java (1 hunks)
  • src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java (1 hunks)
  • src/main/java/konkuk/thip/feed/application/port/out/dto/FeedQueryDto.java (1 hunks)
  • src/main/java/konkuk/thip/feed/application/service/FeedShowAllOfUserService.java (1 hunks)
  • src/main/java/konkuk/thip/feed/application/service/FeedShowSingleService.java (1 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
🔇 Additional comments (21)
src/main/java/konkuk/thip/feed/application/port/out/dto/FeedQueryDto.java (2)

24-26: isWriter 필드 추가 방향 적합

요구사항(조회 응답 전반에 isWriter 추가)에 정확히 부합합니다. 기존 boolean 계열(isPublic 등)과의 네이밍/타입/위치 일관성도 좋습니다.


24-26: 검증 결과 — FeedQueryDto 호출부 점검 완료(빌더 사용만 존재)

간단히 요약하면: 직접 new FeedQueryDto(...) 호출과 JPQL/QueryDSL의 select new 프로젝션은 발견되지 않았고, FeedQueryDto를 사용하는 곳은 빌더 호출 한 곳뿐입니다.

  • 확인된 위치
    • src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java (약 269–286행)
      • FeedQueryDto.builder() 호출, .isWriter(isWriter), .isPriorityFeed(isPriorityFeed) 사용 후 .build() 호출 확인

권고: 변경 후 로컬 또는 CI에서 한 번 컴파일하여 빌더/생성자 시그니처 불일치로 인한 컴파일 에러가 없는지 최종 확인해주세요.

src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowMineResponse.java (2)

20-22: 내 피드 응답에 isWriter 추가 OK

내 피드의 성격상 isWriter는 항상 true가 되어야 하므로 프런트 요구와도 부합합니다.


20-22: 검증 완료 — isPublic / isWriter 순서 문제 없음 (매퍼가 이름 기준으로 매핑함)

결론: 직접적인 위치 기반 생성(new FeedShowMineResponse.FeedDto(...)) 호출은 발견되지 않았고, 매핑 파이프라인이 이름 기반으로 올바르게 매핑하므로 현재 코드상 문제 없습니다.

확인한 위치:

  • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowMineResponse.java — FeedDto에 boolean isPublic, boolean isWriter 정의
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java — toDto(...)에서 FeedQueryDto.builder().isPublic(...).isWriter(isWriter).build()
  • src/main/java/konkuk/thip/feed/application/port/out/dto/FeedQueryDto.java — record에 isPublic / isWriter 포함
  • src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java — toFeedShowMineDto(FeedQueryDto dto) (postDate는 expression으로 매핑, 나머지는 이름 기준 매핑 → isPublic/isWriter 정상 전달)

권고: 즉시 수정 불필요. (원하면 가독성·안전성 향상을 위해 정적 팩토리나 빌더 도입 고려 가능)

src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowAllResponse.java (2)

26-28: 피드 목록 응답에 isWriter 추가 OK

isSaved/isLiked와 함께 isWriter를 인접 배치해 응답 구조가 직관적입니다. 프런트에서의 사용성도 좋아 보입니다.


26-28: FeedDto 생성자 인자 순서 변경 영향 검증 — 확인 필요

요약: FeedShowAllResponse.FeedDto의 boolean 순서는 (isSaved, isLiked, isWriter)로 되어 있고, 코드 내에 직접 new FeedShowAllResponse.FeedDto(...) 호출은 없습니다. 대신 FeedQueryMapper.toFeedShowAllResponse(...)가 매핑을 담당하며, isSaved/isLiked는 expression으로 매핑되고 isWriter는 FeedQueryDto의 프로퍼티로 매핑됩니다. 생성된 MapStruct 코드(또는 빌드 테스트)로 최종적으로 매핑 인자 순서/이름 매칭이 올바른지 검증해 주세요.

검토 위치:

  • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowAllResponse.java — FeedDto 정의 (boolean 순서)
  • src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java — toFeedShowAllResponse(FeedQueryDto, Set savedFeedIds, Set likedFeedIds) 및
    • @mapping(target = "isSaved", expression = "java(savedFeedIds.contains(dto.feedId()))")
    • @mapping(target = "isLiked", expression = "java(likedFeedIds.contains(dto.feedId()))")
  • src/main/java/konkuk/thip/feed/application/port/out/dto/FeedQueryDto.java — dto에 isWriter 프로퍼티 존재
  • src/main/java/konkuk/thip/feed/application/service/BasicFeedShowAllService.java, FollowingPriorityFeedShowAllService.java — 매퍼 호출 지점 (.map(dto -> feedQueryMapper.toFeedShowAllResponse(...)))

권장 조치:

  • 생성된 MapStruct 소스(target/generated-sources/annotations 또는 빌드 로그)에서 toFeedShowAllResponse 구현이 기대대로 isSaved/isLiked/isWriter를 올바르게 전달하는지 확인해 주세요(또는 프로젝트 빌드/테스트 실행).
  • 확실히 하려면 toFeedShowAllResponse에 명시적 매핑(@mapping(target="isWriter", source="dto.isWriter"))을 추가하는 것을 고려하세요.
src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowByUserResponse.java (1)

31-33: 특정 유저 피드 응답에 isWriter 추가 OK

조회 주체(userId)와 피드 작성자 동일 여부를 명확히 전달할 수 있어 요구사항에 부합합니다.

src/main/java/konkuk/thip/comment/adapter/in/web/response/CommentForSinglePostResponse.java (2)

22-24: 루트 댓글 DTO에 isWriter 추가 OK

삭제 여부(isDeleted)와 함께 작성자 일치 여부를 내려주도록 확장된 점 적절합니다. 응답 구조 변화가 명확합니다.


36-38: 대댓글 ReplyDto(isWriter) 추가 — 매핑 호출부 점검 완료 (수정 불필요)

검증 결과: ReplyDto는 MapStruct 매퍼(CommentQueryMapper.toReply)에 의해 생성되며, isWriter 값은 CommentQueryRepositoryImpl의 Q 프로젝션에서 제공됩니다. 명시적 new ReplyDto 호출은 없습니다.

점검한 위치:

  • src/main/java/konkuk/thip/comment/adapter/in/web/response/CommentForSinglePostResponse.java — ReplyDto / RootCommentDto 정의
  • src/main/java/konkuk/thip/comment/application/mapper/CommentQueryMapper.java — toReply / toRoot 매핑
  • src/main/java/konkuk/thip/comment/adapter/out/persistence/repository/CommentQueryRepositoryImpl.java — QCommentQueryDto 프로젝션(마지막 인자: commentCreator.userId.eq(userId))
  • src/main/java/konkuk/thip/comment/adapter/out/persistence/CommentQueryPersistenceAdapter.java — repository 호출부
  • src/main/java/konkuk/thip/comment/application/service/CommentShowAllService.java — 매퍼 호출부

간단 주의: Boolean → boolean 언박싱 관련 NPE 가능성은 있지만, 현재 프로젝션이 boolean 값을 제공하므로 실무상 문제 없음. 빌드 시 MapStruct가 생성한 코드 컴파일 확인 권장.

src/main/java/konkuk/thip/comment/application/port/out/dto/CommentQueryDto.java (1)

43-47: Querydsl 프로젝션 시그니처 변경 전파 확인 — 완료

루트 생성자에 추가된 isWriter 인자는 레포지토리의 모든 Querydsl 프로젝션 호출부에 반영되어 있습니다.

  • src/main/java/konkuk/thip/comment/adapter/out/persistence/repository/CommentQueryRepositoryImpl.java
    • 최상위 댓글 프로젝션: new QCommentQueryDto(...) — 호출부 범위: 34–46 (마지막 인자 commentCreator.userId.eq(userId) 전달 → isWriter)
    • 자손 댓글 프로젝션: new QCommentQueryDto(...) — 호출부 범위: 78–92, 141–155 (각각 13개 인자, 마지막 인자 commentCreator.userId.eq(userId) 포함)

결론: 모든 QCommentQueryDto 호출부가 새 시그니처를 따르고 있어 추가 수정 불필요합니다.

src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowSingleResponse.java (1)

19-20: 단일 피드 응답에 isWriter 추가 — LGTM

FE 요구사항에 맞춘 boolean 필드 추가가 일관되며, 매퍼/서비스 변경과도 정합적입니다.

src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java (2)

86-89: 확인 완료 — 호출부와 매퍼 시그니처가 일치합니다 (LGTM)

rg 결과 서비스 호출부에서 isWriter를 포함해 6개 인자를 전달하고 있어 매핑이 정상입니다.

확인된 위치:

  • src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java — lines 86–88: 매핑 및 메서드 시그니처(toFeedShowSingleResponse(..., boolean isWriter))
  • src/main/java/konkuk/thip/feed/application/service/FeedShowSingleService.java — line 49: return feedQueryMapper.toFeedShowSingleResponse(feed, feedCreator, book, isSaved, isLiked,isWriter);

86-89: 확인 필요 — Feed 목록 응답의 isWriter 자동 매핑 여부

검사 결과: FeedShowAllResponse.FeedDto, FeedShowByUserResponse.FeedDto, FeedShowMineResponse.FeedDto에 boolean isWriter 필드가 존재합니다. 다만 생성된 MapStruct 구현(FeedQueryMapperImpl.java)을 리포지토리에서 찾지 못해 by-name 자동 매핑이 실제로 적용되는지는 확정할 수 없습니다.

  • 확인된 파일:
    • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowAllResponse.java (FeedDto에 isWriter 포함)
    • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowByUserResponse.java (FeedDto에 isWriter 포함)
    • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedShowMineResponse.java (FeedDto에 isWriter 포함)
  • 검토가 필요한 매퍼 메서드:
    • toFeedShowAllResponse(...)
    • toFeedShowByUserResponse(...)
    • toFeedShowMineDto(...)

권고: 생성된 구현(FeedQueryMapperImpl.java)을 확인하거나, 다중 소스 파라미터가 있는 메서드의 암묵 매핑이 깨질 위험을 없애기 위해 명시 매핑을 추가하세요. 예:
@mapping(target = "isWriter", source = "dto.isWriter") // 'dto'를 실제 파라미터명으로 교체

src/main/java/konkuk/thip/feed/application/service/FeedShowSingleService.java (1)

49-49: 검증 완료 — Mapper 시그니처 일치

선언부와 호출부가 동일한 시그니처를 사용하고 있어 추가 수정 불필요합니다.

  • src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java:88 — 선언부: FeedShowSingleResponse toFeedShowSingleResponse(Feed feed, User feedCreator, Book book, boolean isSaved, boolean isLiked, boolean isWriter);
  • src/main/java/konkuk/thip/feed/application/service/FeedShowSingleService.java:49 — 호출부: return feedQueryMapper.toFeedShowSingleResponse(feed, feedCreator, book, isSaved, isLiked,isWriter);
src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java (1)

92-97: 확인 완료 — 포트/어댑터 시그니처 일치

rg 검사 결과, FeedQueryPort와 어댑터/호출부의 시그니처가 일치하며(어댑터가 Cursor를 LocalDateTime+size로 변환해 레포지토리를 호출하는 구조) 문제 없음이 확인되었습니다.

  • src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java
    • findSpecificUserFeedsByCreatedAt(Long userId, Long feedOwnerId, Cursor cursor)
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java
    • public CursorBasedList findSpecificUserFeedsByCreatedAt(Long userId, Long feedOwnerId, Cursor cursor)
  • src/main/java/konkuk/thip/feed/application/service/FeedShowAllOfUserService.java
    • 호출부: feedQueryPort.findSpecificUserFeedsByCreatedAt(userId, feedOwnerId, nextCursor)
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepository.java
    • 레포지토리 메서드: findSpecificUserFeedsByCreatedAt(Long, Long, LocalDateTime, int) — 어댑터에서 Cursor → lastCreatedAt, size로 매핑

따라서 원래 코멘트대로 승인합니다.

src/main/java/konkuk/thip/comment/application/service/CommentShowAllService.java (3)

32-32: 루트 댓글 조회 시 userId 전달 변경 LGTM

findLatestRootCommentsWithDeleted(..., query.userId(), ...) 전달 변경은 isWriter 계산을 위한 문맥 제공 측면에서 타당합니다.


40-41: 자식 댓글 일괄 조회에 userId 전달 변경 LGTM

findAllActiveChildCommentsOldestFirst(rootCommentIds, query.userId()) 수정이 일관되게 적용되었습니다.


32-41: userId가 null인 비로그인 요청 처리 확인 요청

조회자가 비로그인일 수 있다면(query.userId()가 null), 레포지토리/쿼리단에서 = null 비교나 NPE가 발생하지 않도록 방어 로직이 필요합니다. QueryDSL을 사용한다면 eq(userId)에 null이 들어가도 안전하게 무시되도록 조건식을 분기하거나 Objects.equals 기반으로 서버 단에서 계산하는 방식을 고려해 주세요.

src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java (2)

55-84: limit(size + 1) 사용 시 상위 레이어에서 페이지 슬라이싱 확인 필요

내부 ID 조회는 limit(size + 1)을 사용하지만, 본 메서드는 그대로 toList()로 모두 DTO 변환해 반환합니다. 상위 계층(어댑터/서비스)에서 size 초과분을 제거하고 hasNext 계산을 하고 있다면 OK입니다. 아니라면 여기서 슬라이싱이 필요합니다.

예시(옵션):

-        return ordered.stream()
-                .map(e -> toDto(e, priorityMap.get(e.getPostId()), userId))
-                .toList();
+        return ordered.stream()
+                .limit(size) // size + 1 로 조회한 경우 상위 hasNext 계산을 위해 한 개 초과분은 제거
+                .map(e -> toDto(e, priorityMap.get(e.getPostId()), userId))
+                .toList();

동일 패턴의 다른 경로들(findLatestFeedsByCreatedAt, findMyFeedsByCreatedAt)도 점검 부탁드립니다.

Also applies to: 86-106, 180-197


262-286: toDto에서 isWriter 계산 로직 적절

e.getUserJpaEntity().getUserId().equals(userId)는 요청자 null 시에도 안전하게 false를 반환합니다. isWriter 채움 로직은 요구사항과 부합합니다.

src/main/java/konkuk/thip/comment/adapter/out/persistence/CommentQueryPersistenceAdapter.java (1)

25-35: userId null 입력에 대한 정책 명확화 필요

여기서 userId가 null로 전달될 수 있는지(비로그인 사용자 조회 지원 여부)를 결정해 주세요. 현재 Repository 구현은 eq(userId)를 직접 사용 중이라 null이면 런타임 오류 가능성이 있습니다. 아래 Repository 제안처럼 null 시 Expressions.FALSE로 대체하여 항상 isWriter=false가 되도록 처리하는 것이 안전합니다.

Comment thread src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java Outdated
Comment thread src/main/java/konkuk/thip/feed/application/service/FeedShowSingleService.java Outdated

@seongjunnoh seongjunnoh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

빠른 수정 감사합니다!! 수정방식 관련해서 리뷰달았는데 @hd0rable @buzz0331 두분 모두 확인부탁드립니다!!

0,
false,
true, // true
false,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

굳굳
굳이 Boolean 으로 감싸서 null 값을 넣지 않고 이렇게 쓰레기값을 줘도 어차피 FE에서는 isDelete 값이 true이면 다른 값들 전부 무시하니 괜찮을 것 같습니다!

int likeCount,
int commentCount,
boolean isPublic,
boolean isWriter,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

p3 : 전 다른 코드는 건드리지 않고 마지막 response 구성할때 isWriter 필드의 값을 access token에서 파싱한 userId.equals(creatorId) 값으로 세팅해주는 방식을 생각했긴 했는데,
여러분들 생각은 어떠신가요?? @hd0rable @buzz0331

이러면 영속성 계층에서는 코드 수정이 발생하지 않고, QueryDto 에서도 필드 추가가 없긴 합니다

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.

저도 같은 생각입니다! 현재 creatorId는 반환되고 있으니 해당 id와 현재 로그인된 유저의 id를 비교해서 isWriter를 구성해주는게 좋을 것 같아욥

@buzz0331 buzz0331 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.

수정 감사합니다! 성준님 말대로 서비스 레벨에서 isWriter를 파싱하는 방식을 고려해보면 좋을 것 같습니다~

int likeCount,
int commentCount,
boolean isPublic,
boolean isWriter,

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.

저도 같은 생각입니다! 현재 creatorId는 반환되고 있으니 해당 id와 현재 로그인된 유저의 id를 비교해서 isWriter를 구성해주는게 좋을 것 같아욥

@buzz0331 buzz0331 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 +64 to +67
@Named("isWriter")
default boolean isWriter(Long creatorId, @Context Long userId) {
return creatorId != null && creatorId.equals(userId);
}

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.

오호 굿굿입니다!!

@seongjunnoh seongjunnoh merged commit 5af8cf4 into develop Aug 14, 2025
3 of 4 checks passed
@seongjunnoh seongjunnoh deleted the hotfix/#220-iswriter branch August 14, 2025 15:35

@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: 0

🔭 Outside diff range comments (1)
src/main/java/konkuk/thip/comment/application/service/CommentShowAllService.java (1)

56-64: 긴급: childrenMap 접근 NPE 및 루트 댓글 누락 위험 — 수정 필요

childrenMap.get(rootCommentId).stream()에서 get(...)가 null일 경우 NPE가 발생할 수 있으며, childrenMap.keySet()만으로는 자식이 없는 루트 댓글이 map에 키로 존재하지 않을 때 루트 댓글 ID가 누락되어 조회 누락이 발생할 수 있습니다.

  • 대상 파일
    • src/main/java/konkuk/thip/comment/application/service/CommentShowAllService.java (parseAllCommentIds, 약 라인 56–64)

즉시 적용 가능한 최소 수정(널-안전):

-    private Set<Long> parseAllCommentIds(Map<Long, List<CommentQueryDto>> childrenMap) {
-        Set<Long> allCommentIds = new HashSet<>(childrenMap.keySet());  // 루트 댓글들
-        for (Long rootCommentId : childrenMap.keySet()) {
-            childrenMap.get(rootCommentId).stream()
-                    .map(CommentQueryDto::commentId)
-                    .forEach(allCommentIds::add);
-        }
-        return allCommentIds;
-    }
+    private Set<Long> parseAllCommentIds(Map<Long, List<CommentQueryDto>> childrenMap) {
+        Set<Long> allCommentIds = new HashSet<>(childrenMap.keySet());  // 루트 댓글들
+        for (Long rootCommentId : childrenMap.keySet()) {
+            childrenMap.getOrDefault(rootCommentId, Collections.emptyList()).stream()
+                    .map(CommentQueryDto::commentId)
+                    .forEach(allCommentIds::add);
+        }
+        return allCommentIds;
+    }

권장 리팩터(루트 댓글 누락 방지 — 호출부 변경 필요):

// 제안: 시그니처 변경
private Set<Long> parseAllCommentIds(Map<Long, List<CommentQueryDto>> childrenMap, Set<Long> rootCommentIds) {
    Set<Long> allCommentIds = new HashSet<>(rootCommentIds); // 루트 댓글 전부 포함 보장
    for (Long rootCommentId : rootCommentIds) {
        childrenMap.getOrDefault(rootCommentId, Collections.emptyList()).stream()
                .map(CommentQueryDto::commentId)
                .forEach(allCommentIds::add);
    }
    return allCommentIds;
}

// 호출부 예시 변경
Set<Long> rootCommentIds = rootsInOrder.stream()
        .map(CommentQueryDto::commentId)
        .collect(Collectors.toUnmodifiableSet());
Map<Long, List<CommentQueryDto>> childrenMap = commentQueryPort.findAllActiveChildCommentsOldestFirst(rootCommentIds);
Set<Long> allCommentIds = parseAllCommentIds(childrenMap, rootCommentIds);

참고: Collections.emptyList() 사용 시 java.util.Collections import 필요. 위 즉시 수정은 NPE를 방지하지만, 루트 댓글 전부 포함 보장을 위해 권장 리팩터를 적용해 주세요.

🧹 Nitpick comments (2)
src/main/java/konkuk/thip/comment/application/mapper/CommentQueryMapper.java (1)

64-67: isWriter 내부 비교를 Objects.equals로 단순화 제안

가독성을 위해 Objects.equals(creatorId, userId) 사용을 권장합니다. 또한 동일한 isWriter 로직이 feed/댓글 매퍼에 중복될 가능성이 높으므로, 공용 유틸(예: WriterMappingUtils)로 분리하여 @Named 메서드를 재사용하면 유지보수성이 좋아집니다.

적용 예시(diff):

 @Named("isWriter")
 default boolean isWriter(Long creatorId, @Context Long userId) {
-    return creatorId != null && creatorId.equals(userId);
+    return java.util.Objects.equals(creatorId, userId);
 }
src/main/java/konkuk/thip/feed/application/service/FeedShowAllOfUserService.java (1)

52-52: 사소한 스타일: 쉼표 앞 불필요한 공백 제거 권장

메서드 인자 사이에 쉼표 앞 공백이 들어갔습니다. 코드 컨벤션 일관성을 위해 공백 제거를 제안합니다.

적용 diff:

-        CursorBasedList<FeedQueryDto> result = feedQueryPort.findSpecificUserFeedsByCreatedAt(feedOwnerId ,nextCursor);
+        CursorBasedList<FeedQueryDto> result = feedQueryPort.findSpecificUserFeedsByCreatedAt(feedOwnerId, nextCursor);
📜 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 settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f093c0c and 0b134e2.

📒 Files selected for processing (11)
  • src/main/java/konkuk/thip/comment/application/mapper/CommentQueryMapper.java (1 hunks)
  • src/main/java/konkuk/thip/comment/application/service/CommentShowAllService.java (2 hunks)
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepository.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java (1 hunks)
  • src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java (4 hunks)
  • src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java (1 hunks)
  • src/main/java/konkuk/thip/feed/application/service/BasicFeedShowAllService.java (1 hunks)
  • src/main/java/konkuk/thip/feed/application/service/FeedShowAllOfUserService.java (3 hunks)
  • src/main/java/konkuk/thip/feed/application/service/FeedShowSingleService.java (1 hunks)
  • src/main/java/konkuk/thip/feed/application/service/FollowingPriorityFeedShowAllService.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/konkuk/thip/feed/application/port/out/FeedQueryPort.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepositoryImpl.java
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/FeedQueryPersistenceAdapter.java
  • src/main/java/konkuk/thip/feed/adapter/out/persistence/repository/FeedQueryRepository.java
⏰ 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
🔇 Additional comments (15)
src/main/java/konkuk/thip/comment/application/mapper/CommentQueryMapper.java (2)

27-28: isWriter 매핑 추가 LGTM

MapStruct @Named 활용으로 creatorId 대비 현재 사용자 userId를 비교해 isWriter를 산출하는 접근이 명확하고, null-safe 비교로 방어 코드도 적절합니다.

Also applies to: 36-37


42-48: @context userId 전파와 중첩 매핑 체인 구성 적절

mapRepliestoReply, toRootCommentResponseWithChildrentoRoot@Context Long userId를 일관되게 전달해 writer 판정을 보존하는 구조가 깔끔합니다. replyList 초기화 후 addAll 하는 패턴도 안전합니다.

Also applies to: 51-54, 59-59

src/main/java/konkuk/thip/comment/application/service/CommentShowAllService.java (1)

47-47: userId 컨텍스트 전파 LGTM

매퍼 호출부(buildRootCommentResponses, toRootCommentResponseWithChildren)까지 userId를 넘겨 isWriter 산출이 가능해졌습니다. 의도와 구현이 일치합니다.

Also applies to: 69-71, 78-78

src/main/java/konkuk/thip/feed/application/service/BasicFeedShowAllService.java (1)

56-56: toFeedShowAllResponse에 userId 전달 LGTM

writer 판정을 위한 컨텍스트 전달이 반영되어 일관성이 확보되었습니다.

src/main/java/konkuk/thip/feed/application/service/FollowingPriorityFeedShowAllService.java (1)

55-55: toFeedShowAllResponse에 userId 전달 LGTM

팔로잉 우선 조회 경로에서도 동일하게 컨텍스트가 전파되어 일관됩니다.

src/main/java/konkuk/thip/feed/application/service/FeedShowSingleService.java (2)

48-48: 단일 피드 응답 매핑 시 userId 전달 LGTM

isWriter 산출을 위한 맥락 전달로, 이전 커밋에서 지적되던 서비스 레벨 비교 로직이 매퍼로 일원화된 점도 긍정적입니다.


37-37: 결론: feedCreator가 null일 가능성 없음 — UserCommandPort.findById는 존재하지 않으면 예외를 던집니다

간단히 확인 결과, UserCommandPort.findById(Long)는 Optional이 아닌 User를 반환하도록 정의되어 있고, 구현체에서 없을 경우 예외를 던지도록 구현되어 있습니다. 따라서 NPE 우려는 불필요합니다.

확인한 위치:

  • src/main/java/konkuk/thip/feed/application/service/FeedShowSingleService.java — User feedCreator = userCommandPort.findById(feed.getCreatorId());
  • src/main/java/konkuk/thip/user/application/port/out/UserCommandPort.java — User findById(Long userId);
  • src/main/java/konkuk/thip/user/adapter/out/persistence/UserCommandPersistenceAdapter.java — findById 구현에서 userJpaRepository.findById(...).orElseThrow(...) 사용

조치: 원래 리뷰 코멘트는 부정확하므로 무시해 주세요.

Likely an incorrect or invalid review comment.

src/main/java/konkuk/thip/feed/application/service/FeedShowAllOfUserService.java (2)

39-39: isWriter 컨텍스트 전파 적용 — 좋습니다

toFeedShowMineResponse 호출부에 userId를 전달하여 isWriter 계산 맥락을 정확히 반영했습니다.


57-64: 비로그인(userId==null) 및 빈 feedIds 처리 가드 추가 권장

userId가 null이거나 feedIds가 비어있을 때 포트 호출로 NPE 또는 불필요한 DB 쿼리가 발생할 수 있으므로 가드 추가를 권장합니다.

  • 파일: src/main/java/konkuk/thip/feed/application/service/FeedShowAllOfUserService.java (라인 57-64)

적용 제안 diff:

-        // 3. 유저가 저장한 피드들, 좋아한 피드들 조회
-        Set<Long> savedFeedIdsByUser = feedQueryPort.findSavedFeedIdsByUserIdAndFeedIds(feedIds, userId);
-        Set<Long> likedFeedIdsByUser = postLikeQueryPort.findPostIdsLikedByUser(feedIds, userId);
+        // 3. 유저가 저장한 피드들, 좋아한 피드들 조회 (비로그인/빈 결과 가드)
+        Set<Long> savedFeedIdsByUser = Set.of();
+        Set<Long> likedFeedIdsByUser = Set.of();
+        if (!feedIds.isEmpty() && userId != null) {
+            savedFeedIdsByUser = feedQueryPort.findSavedFeedIdsByUserIdAndFeedIds(feedIds, userId);
+            likedFeedIdsByUser = postLikeQueryPort.findPostIdsLikedByUser(feedIds, userId);
+        }

검증 요청:

  • 이 엔드포인트가 비로그인 접근을 허용하는지 확인해 주세요. 허용한다면 위 가드 적용이 필요합니다.
  • 허용하지 않는다면 컨트롤러/인터셉터 레벨에서 userId가 항상 비null인지 보장되는지 확인해 주세요.
src/main/java/konkuk/thip/feed/application/mapper/FeedQueryMapper.java (6)

34-40: toFeedShowAllResponse에 isWriter 매핑과 @context 전달 — 적절합니다

작성자 판별을 @Named("isWriter")로 위임하고 @Context Long userId를 통해 컨텍스트를 주입한 접근이 명확하고 테스트 용이합니다.


43-47: 내 피드 DTO 매핑에 isWriter 추가 — 일관성 있게 반영됨

toFeedShowMineDto와 리스트 매핑에 @Context userId를 연결해 isWriter가 정확히 채워지도록 했습니다.


54-60: 사용자별 공개 피드 DTO 매핑에 isWriter 추가 — OK

저장/좋아요 플래그 계산과 함께 isWriter가 동일 컨텍스트로 계산되도록 한 점 좋습니다.


88-92: 단건 조회 매핑에 isWriter 추가 — OK

feedCreator.id를 소스로 사용하여 컨텍스트 사용자와 일치 여부를 판단하는 로직이 명확합니다.


120-123: isWriter 매핑 함수의 null-세이프 처리 확인 — LGTM

creatorId != null && creatorId.equals(userId)로 null 안전하게 비교되어, 익명 사용자 시 false가 반환됩니다.


34-40: 확인 완료 — 모든 호출부가 @context Long userId 시그니처로 업데이트되어 있습니다

아래 호출부들이 모두 userId 인자를 전달하고 있어 변경이 반영된 것으로 확인됩니다:

  • src/main/java/konkuk/thip/feed/application/service/FollowingPriorityFeedShowAllService.java:55
    • .map(dto -> feedQueryMapper.toFeedShowAllResponse(dto, savedFeedIdsByUser, likedFeedIdsByUser, userId))
  • src/main/java/konkuk/thip/feed/application/service/BasicFeedShowAllService.java:56
    • .map(dto -> feedQueryMapper.toFeedShowAllResponse(dto, savedFeedIdsByUser, likedFeedIdsByUser, userId))
  • src/main/java/konkuk/thip/feed/application/service/FeedShowAllOfUserService.java:39
    • feedQueryMapper.toFeedShowMineResponse(result.contents(), userId)
  • src/main/java/konkuk/thip/feed/application/service/FeedShowAllOfUserService.java:63
    • .map(dto -> feedQueryMapper.toFeedShowByUserResponse(dto, savedFeedIdsByUser, likedFeedIdsByUser, userId))
  • src/main/java/konkuk/thip/feed/application/service/FeedShowSingleService.java:48
    • return feedQueryMapper.toFeedShowSingleResponse(feed, feedCreator, book, isSaved, isLiked, userId);

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-268] [hotfix] 조회 시 isWriter response 전체 추가

3 participants