[WTH-251] post comment 작성자 타입을 club member로 변경#48
Conversation
📝 WalkthroughWalkthroughPost와 Comment 엔티티가 User 대신 ClubMember와 연결되도록 변경되었습니다. 이에 따라 PostMapper, CommentMapper 등의 매퍼에서 authorMember 매개변수가 제거되었으며, 작성자 정보는 post.clubMember 또는 comment.clubMember에서 직접 파생됩니다. 쿼리 서비스의 memberMap 빌드 로직도 함께 제거되었습니다. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~35 minutes Possibly related PRs
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 docstrings
🧪 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.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/main/kotlin/com/weeth/domain/board/domain/repository/PostRepository.kt (1)
69-83:⚠️ Potential issue | 🟡 Minor
findByIdWithLock에clubMemberEntityGraph가 누락되었습니다.다른 조회 메서드들(
findAllByBoardIds,findByBoardId,findById등)은["clubMember", "clubMember.user"]를 포함하도록 설정되어 있지만,findByIdWithLock은["board", "board.club"]만 포함합니다.현재
TogglePostLikeUseCase에서는post.belongsToClub()과post.board.isAccessibleBy()만 호출하므로 문제가 없습니다. 그러나 향후 코드가post.isOwnedBy()또는post.clubMember에 접근하면LazyInitializationException이 발생할 수 있습니다.🛠️ EntityGraph에 clubMember 추가
- `@EntityGraph`(attributePaths = ["board", "board.club"]) + `@EntityGraph`(attributePaths = ["board", "board.club", "clubMember", "clubMember.user"]) `@Lock`(LockModeType.PESSIMISTIC_WRITE) `@QueryHints`(QueryHint(name = "jakarta.persistence.lock.timeout", value = "2000"))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/kotlin/com/weeth/domain/board/domain/repository/PostRepository.kt` around lines 69 - 83, The EntityGraph on findByIdWithLock currently only loads ["board", "board.club"] which can cause LazyInitializationException if callers later access post.clubMember or call post.isOwnedBy(); update the EntityGraph attributePaths of findByIdWithLock to include "clubMember" and "clubMember.user" (so it matches other methods like findAllByBoardIds/findByBoardId/findById) while keeping the existing pessimistic lock and query hints intact.src/test/kotlin/com/weeth/domain/comment/application/usecase/command/CommentConcurrencyTest.kt (1)
301-305:⚠️ Potential issue | 🟠 MajorAtomic 경로가
userId를 무시해 벤치마크 비교가 왜곡됩니다.Line 313에서 모든 요청의 작성자를
post.clubMember로 고정하면,pessimistic경로(요청 사용자 기준)와 동등 비교가 깨집니다. 성능 수치가 과대/과소 측정될 수 있고 권한·작성자 경로 회귀도 가려집니다.제안 패치
transactionTemplate.executeWithoutResult { val post = entityManager.getReference(Post::class.java, postId) - // 벤치마크 전용: commentCount 동시성 측정이 목적이므로 userId 대신 post 작성자의 ClubMember를 재사용 - val clubMember = post.clubMember + val clubMember = + entityManager + .createQuery( + "select cm from ClubMember cm where cm.club.id = :clubId and cm.user.id = :userId", + ClubMember::class.java, + ) + .setParameter("clubId", post.board.club.id) + .setParameter("userId", userId) + .resultList + .firstOrNull() + ?: throw IllegalArgumentException("clubMember not found for userId=$userId")Also applies to: 313-326
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/kotlin/com/weeth/domain/comment/application/usecase/command/CommentConcurrencyTest.kt` around lines 301 - 305, The atomic path in savePostCommentWithAtomicIncrement currently hardcodes the author to post.clubMember (lines around 313-326), which ignores the userId parameter and skews benchmark comparison with the pessimistic path; change the atomic-path code in savePostCommentWithAtomicIncrement to use the incoming userId (and any derived user-related lookups) as the requester/author instead of post.clubMember so both atomic and pessimistic flows run with the same request user; update any variables or calls within that block that set the creator/author or perform permission checks to derive from userId to keep test conditions equivalent.
🧹 Nitpick comments (3)
src/test/kotlin/com/weeth/domain/board/application/mapper/PostMapperTest.kt (1)
49-56: 작성자 매핑 단언을 추가해 회귀를 막아주세요.이번 변경의 핵심이 작성자 소스를
clubMember로 바꾼 것인데, 현재 테스트는response.author를 검증하지 않아 해당 경로 회귀를 놓칠 수 있습니다.제안 패치
response.id shouldBe 1L + response.author.id shouldBe 1L + response.author.name shouldBe "테스터" + response.author.role shouldBe MemberRole.USER response.hasFile shouldBe true response.isNew shouldBe true @@ response.id shouldBe 1L + response.author.id shouldBe 1L + response.author.name shouldBe "테스터" + response.author.role shouldBe MemberRole.USER response.commentCount shouldBe 2 response.comments.size shouldBe 1 response.fileUrls.size shouldBe 1Also applies to: 59-91
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/kotlin/com/weeth/domain/board/application/mapper/PostMapperTest.kt` around lines 49 - 56, The test in PostMapperTest for toListResponse currently omits asserting the mapped author, risking regressions when the source was changed to clubMember; update the spec block(s) (the it() cases invoking mapper.toListResponse) to assert response.author matches the expected author info derived from the post/clubMember fixture (e.g., compare expected name/id/clubMember-related fields), ensuring the mapping from clubMember -> response.author is validated alongside id, hasFile, and isNew.src/test/kotlin/com/weeth/domain/comment/application/usecase/query/CommentQueryPerformanceTest.kt (1)
88-90: 사용하지 않는SetupResult래퍼는 제거해도 됩니다.현재
runComparison에서setupData(...)반환값을 사용하지 않아 타입/반환 객체가 노이즈가 됩니다.제안 패치
- data class SetupResult( - val commentIds: List<Long>, - ) - fun setupData( rootCount: Int, childrenPerRoot: Int, filesPerComment: Int, - ): SetupResult { + ) { @@ - return SetupResult(commentIds) + // no-op }Also applies to: 144-145, 154-159
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/kotlin/com/weeth/domain/comment/application/usecase/query/CommentQueryPerformanceTest.kt` around lines 88 - 90, The SetupResult data class is unused noise—remove the SetupResult declaration and update any references so setupData(...) returns the raw value(s) needed directly; specifically delete the data class SetupResult and change runComparison calls (and any other usages around setupData, e.g., in CommentQueryPerformanceTest's setupData invocation) to accept/handle the direct returned type instead of wrapping/unwrapping SetupResult. Ensure tests compile by adjusting function signatures (setupData) and any destructuring or assignments that expected SetupResult.src/test/kotlin/com/weeth/domain/comment/application/usecase/command/ManageCommentUseCaseTest.kt (1)
37-38:ClubMemberPolicy를 relaxed로 두면 권한 검증 경로 회귀를 놓치기 쉽습니다.Line 37/Line 53 기준으로 현재는
getActiveMember(...)호출 누락·인자 오류가 있어도 테스트가 통과할 수 있습니다. 이 의존성은 명시적으로 stubbing/verify 해서 테스트 의도를 고정하는 편이 안전합니다.Also applies to: 53-58
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/kotlin/com/weeth/domain/comment/application/usecase/command/ManageCommentUseCaseTest.kt` around lines 37 - 38, 현재 테스트에서 mockk<ClubMemberPolicy>(relaxed = true) 사용으로 getActiveMember(...) 호출 누락이나 인자 오류가 무시될 수 있으므로 relaxed 플래그를 제거하고 ClubMemberPolicy의 getActiveMember 메서드를 명시적으로 stub 및 검증하세요: mock 인스턴스 생성 시 relaxed = true 를 빼고 every { clubMemberPolicy.getActiveMember(expectedMemberId, any()) } returns expectedMember (또는 적절한 값) 처럼 필요한 입력에 대해 명시적 반환을 설정한 뒤, 테스트 끝에 verify { clubMemberPolicy.getActiveMember(expectedMemberId, any()) } 를 추가해 실제 호출과 인자를 검사하도록 수정하고 동일한 패턴으로 다른 테스트용 relaxed mock들(파일 내 다른 relaxed mock 생성 지점)도 동일하게 명시적 stubbing 및 verify로 교체하세요.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/main/kotlin/com/weeth/domain/board/domain/repository/PostRepository.kt`:
- Around line 69-83: The EntityGraph on findByIdWithLock currently only loads
["board", "board.club"] which can cause LazyInitializationException if callers
later access post.clubMember or call post.isOwnedBy(); update the EntityGraph
attributePaths of findByIdWithLock to include "clubMember" and "clubMember.user"
(so it matches other methods like findAllByBoardIds/findByBoardId/findById)
while keeping the existing pessimistic lock and query hints intact.
In
`@src/test/kotlin/com/weeth/domain/comment/application/usecase/command/CommentConcurrencyTest.kt`:
- Around line 301-305: The atomic path in savePostCommentWithAtomicIncrement
currently hardcodes the author to post.clubMember (lines around 313-326), which
ignores the userId parameter and skews benchmark comparison with the pessimistic
path; change the atomic-path code in savePostCommentWithAtomicIncrement to use
the incoming userId (and any derived user-related lookups) as the
requester/author instead of post.clubMember so both atomic and pessimistic flows
run with the same request user; update any variables or calls within that block
that set the creator/author or perform permission checks to derive from userId
to keep test conditions equivalent.
---
Nitpick comments:
In `@src/test/kotlin/com/weeth/domain/board/application/mapper/PostMapperTest.kt`:
- Around line 49-56: The test in PostMapperTest for toListResponse currently
omits asserting the mapped author, risking regressions when the source was
changed to clubMember; update the spec block(s) (the it() cases invoking
mapper.toListResponse) to assert response.author matches the expected author
info derived from the post/clubMember fixture (e.g., compare expected
name/id/clubMember-related fields), ensuring the mapping from clubMember ->
response.author is validated alongside id, hasFile, and isNew.
In
`@src/test/kotlin/com/weeth/domain/comment/application/usecase/command/ManageCommentUseCaseTest.kt`:
- Around line 37-38: 현재 테스트에서 mockk<ClubMemberPolicy>(relaxed = true) 사용으로
getActiveMember(...) 호출 누락이나 인자 오류가 무시될 수 있으므로 relaxed 플래그를 제거하고
ClubMemberPolicy의 getActiveMember 메서드를 명시적으로 stub 및 검증하세요: mock 인스턴스 생성 시
relaxed = true 를 빼고 every { clubMemberPolicy.getActiveMember(expectedMemberId,
any()) } returns expectedMember (또는 적절한 값) 처럼 필요한 입력에 대해 명시적 반환을 설정한 뒤, 테스트 끝에
verify { clubMemberPolicy.getActiveMember(expectedMemberId, any()) } 를 추가해 실제
호출과 인자를 검사하도록 수정하고 동일한 패턴으로 다른 테스트용 relaxed mock들(파일 내 다른 relaxed mock 생성 지점)도
동일하게 명시적 stubbing 및 verify로 교체하세요.
In
`@src/test/kotlin/com/weeth/domain/comment/application/usecase/query/CommentQueryPerformanceTest.kt`:
- Around line 88-90: The SetupResult data class is unused noise—remove the
SetupResult declaration and update any references so setupData(...) returns the
raw value(s) needed directly; specifically delete the data class SetupResult and
change runComparison calls (and any other usages around setupData, e.g., in
CommentQueryPerformanceTest's setupData invocation) to accept/handle the direct
returned type instead of wrapping/unwrapping SetupResult. Ensure tests compile
by adjusting function signatures (setupData) and any destructuring or
assignments that expected SetupResult.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a9a18a85-ba72-442f-aae3-dde3f59a658c
📒 Files selected for processing (23)
src/main/kotlin/com/weeth/domain/board/application/mapper/PostMapper.ktsrc/main/kotlin/com/weeth/domain/board/application/usecase/command/ManagePostUseCase.ktsrc/main/kotlin/com/weeth/domain/board/application/usecase/query/GetPostQueryService.ktsrc/main/kotlin/com/weeth/domain/board/domain/entity/Post.ktsrc/main/kotlin/com/weeth/domain/board/domain/repository/PostRepository.ktsrc/main/kotlin/com/weeth/domain/comment/application/mapper/CommentMapper.ktsrc/main/kotlin/com/weeth/domain/comment/application/usecase/command/ManageCommentUseCase.ktsrc/main/kotlin/com/weeth/domain/comment/application/usecase/query/GetCommentQueryService.ktsrc/main/kotlin/com/weeth/domain/comment/domain/entity/Comment.ktsrc/main/kotlin/com/weeth/domain/comment/domain/repository/CommentRepository.ktsrc/main/kotlin/com/weeth/domain/dashboard/application/mapper/DashboardMapper.ktsrc/main/kotlin/com/weeth/domain/dashboard/application/usecase/query/GetDashboardQueryService.ktsrc/test/kotlin/com/weeth/domain/board/application/mapper/PostMapperTest.ktsrc/test/kotlin/com/weeth/domain/board/application/usecase/command/ManagePostUseCaseTest.ktsrc/test/kotlin/com/weeth/domain/board/application/usecase/query/GetPostQueryServiceTest.ktsrc/test/kotlin/com/weeth/domain/board/fixture/PostTestFixture.ktsrc/test/kotlin/com/weeth/domain/comment/application/usecase/command/CommentConcurrencyTest.ktsrc/test/kotlin/com/weeth/domain/comment/application/usecase/command/ManageCommentUseCaseTest.ktsrc/test/kotlin/com/weeth/domain/comment/application/usecase/query/CommentQueryPerformanceTest.ktsrc/test/kotlin/com/weeth/domain/comment/application/usecase/query/GetCommentQueryServiceTest.ktsrc/test/kotlin/com/weeth/domain/comment/domain/entity/CommentEntityTest.ktsrc/test/kotlin/com/weeth/domain/comment/fixture/CommentTestFixture.ktsrc/test/kotlin/com/weeth/domain/dashboard/application/usecase/query/GetDashboardQueryServiceTest.kt
💤 Files with no reviewable changes (1)
- src/main/kotlin/com/weeth/domain/dashboard/application/usecase/query/GetDashboardQueryService.kt
hyxklee
left a comment
There was a problem hiding this comment.
고생하셨습니다! 머지하면서 디비 마이그레이션까지 부탁드릴게요!
📌 Summary
post/comment 작성자 타입을 clubMember로 변경했습니다.
📝 Changes
What
post/comment user 필드 -> clubMember 필드로 수정
Why
user가 club을 탈퇴/삭제할 시 필터링이 안되는 문제 발생
How
user -> clubMember 필드 수정
useReader 제거 -> clubMember 참조
memberMap 제거 -> clubMember 참조
관련 테스트 수정
📸 Screenshots / Logs
💡 Reviewer 참고사항
로컬 스웨거에서 post/comment 확인했습니다.
머지 전에 마이그레이션이 필요합니다.
✅ Checklist
Summary by CodeRabbit
릴리스 노트
참고: 이번 업데이트는 주로 내부 기술 개선으로, 사용자 인터페이스나 기능에는 변화가 없습니다.