Skip to content

[Feat] 게시물 좋아요 상태변경 api 개발#164

Merged
hd0rable merged 47 commits intodevelopfrom
feat/#159-feed-like
Aug 7, 2025
Merged

[Feat] 게시물 좋아요 상태변경 api 개발#164
hd0rable merged 47 commits intodevelopfrom
feat/#159-feed-like

Conversation

@hd0rable
Copy link
Member

@hd0rable hd0rable commented Aug 6, 2025

#️⃣ 연관된 이슈

closes #159
closes #163

📝 작업 내용

  • 게시물 좋아요 상태변경 api를 개발하였습니다. Feed,Room(record,vote) 엔드포인트만 분리되었고 내부에서 postLikeService의 로직은 같습니다.
  • CommentCountUpdatable의 이름을 CountUpdatable으로 변경하여 게시물의 공통 인터페이스의 역할을 명확히했습니다.
  • 댓글 접근 정책 이외에 게시글 좋아요 접근 정책을 새로 정의했습니다. (사실상 같은 정책이지만 후의 확장성을 고려해 따로 정의했습니다.)
  • 게시글 좋아요 상태 변경 api의 흐름은 다음과 같습니다.
  1. feed의 경우 request에서 postType을 FEED로 주입한 후, command로 변환되어 postLikeService진입
  2. room의 경우 request에서 받은 roomPostType을 실제 존재하는 RECORD,VOTE인지 검증 뒤, 해당 postType으로 주입한 후, command로 변환되어 postLikeService진입
  3. postLikeService: 게시물 타입에 맞게 검증 및 조회 -> 좋아요 권한 검증 -> 사용자가 해당 게시물에 좋아요 했는지 조회 -> 좋아요 상태 변경( 중복 좋아요 예외처리) -> 게시글 좋아요 수 업데이트 -> result 반환
  4. feed의 경우 feedId, room의 경우 postId 반환
  • 서비스 내부 로직은 완전히 동일하지만 컨트롤러 단에서 로직이 상이합니다. 해당 노션 api 명세서 확인해주시면 감사하겠습니다.
  • 관련 통합, 도메인, 단위 테스트 작성했습니다.

📸 스크린샷

image image

💬 리뷰 요구사항

사용자가 게시물 좋아요 중복 좋아요 검증에 대해서 검증을 책임지는 PostLikeAuthorizationValidator이 검증하도록했는데, 해당 클래스가 게시물 좋아요에대한 권한 검증을 하는 정책 클래스이기도하고, 각 도메인에서 한다면 똑같은 중복 코드가 3개의 클래스에 생성되는 것같아 위와같이 구현했습니다. 좋은 의견있으면 부탁드립니다. (여기서 의문이 드는게 CountUpdatable의 같은 경우에도 단순히 숫자만 증가/감소 하는 역할을 하다보니 각 도메인에대해 중복되는 코드가 생성되는 감이있는데.. 후에 리펙해보도록하겠습니다)

방 게시물의 경우 현재 방아이디를 받지않고 바로 게시글 조회한 후 좋아요 권한 검증을 진행하는데, 어차피 방 게시글에 대한 좋아요를 누르려면 사용자가 해당 방에 참여중인지 권한 검증도 진행하고, 해당 방이 만료되거나 삭제된 방이라면 방과 관련된 정보들이 삭제 될것이기때문에 이측에서 필터링이 될것같아 방을 따로 조회하지않았는데 이와관련해서 더 좋은 방안이 있다면 리뷰 부탁드립니다

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

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

Summary by CodeRabbit

  • 신규 기능

    • 피드 및 방 게시물(레코드, 투표)에 대한 좋아요/좋아요 취소 API 엔드포인트가 추가되었습니다.
    • 피드와 방 게시물의 좋아요 상태 변경 요청 및 응답 DTO가 추가되었습니다.
    • 게시물의 좋아요 상태 변경을 위한 서비스, 정책, 권한 검증 로직이 도입되었습니다.
    • 게시물 타입별 좋아요 접근 정책 및 예외 코드가 추가되었습니다.
  • 버그 수정

    • 피드, 레코드, 투표의 좋아요/댓글 수 감소 시 0 미만으로 내려갈 수 없도록 예외 처리가 강화되었습니다.
  • 리팩터링

    • 게시물 카운트 관리 인터페이스가 일반화되어 좋아요와 댓글 수를 함께 관리하도록 변경되었습니다.
    • 기존 댓글 카운트 관련 인터페이스 및 메서드가 통합 및 정리되었습니다.
  • 테스트

    • 피드 및 방 게시물 좋아요/취소 API에 대한 통합 테스트와 도메인 단위 테스트가 추가되어, 정상 동작 및 예외 상황을 검증합니다.
  • 문서화

    • Swagger 문서에 피드 및 방 게시물 좋아요 상태 변경 관련 응답 및 예외 코드가 추가되었습니다.

hd0rable added 30 commits August 7, 2025 00:13
@hd0rable hd0rable self-assigned this Aug 6, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 6, 2025

Walkthrough

피드 및 방 게시물(기록, 투표)의 좋아요 상태 변경 API가 도입되었습니다. 기존의 댓글 수 관리 인터페이스를 일반적인 카운트 관리 인터페이스로 확장하고, 도메인, 서비스, 정책, 예외, 컨트롤러, 테스트 전반에 걸쳐 좋아요 상태 변경 및 관련 검증 로직이 추가되었습니다.

Changes

Cohort / File(s) Change Summary
CountUpdatable 인터페이스 및 적용
src/main/java/konkuk/thip/common/post/CountUpdatable.java, .../Feed.java, .../Record.java, .../Vote.java, .../RoomPost.java, .../Comment...Service.java, .../PostHandler.java, .../CommentAccessPolicy.java, .../FeedCommentAccessPolicy.java, .../RoomPostCommentAccessPolicy.java, .../CommentAuthorizationValidator.java
기존 CommentCountUpdatable을 삭제하고, 댓글/좋아요 카운트 관리가 가능한 CountUpdatable로 대체. 관련 도메인 및 서비스, 정책, 핸들러, 검증자 등에서 타입 및 메서드 시그니처 변경 및 좋아요 카운트 관련 메서드 추가.
좋아요 상태 변경 도메인/서비스/정책/포트
src/main/java/konkuk/thip/post/application/port/in/PostLikeUseCase.java, .../dto/PostIsLikeCommand.java, .../dto/PostIsLikeResult.java, .../service/PostLikeService.java, .../service/validator/PostLikeAuthorizationValidator.java, .../service/policy/PostLikeAccessPolicy.java, .../service/policy/FeedLikeAccessPolicy.java, .../service/policy/RoomPostLikeAccessPolicy.java, .../application/port/out/PostLikeCommandPort.java, .../application/port/out/PostLikeQueryPort.java, .../adapter/out/persistence/PostLikeCommandPersistenceAdapter.java, .../adapter/out/persistence/PostLikeQueryPersistenceAdapter.java, .../adapter/out/persistence/PostLikeJpaRepository.java
좋아요 상태 변경을 위한 유스케이스, 커맨드/리절트 DTO, 서비스, 검증자, 정책, 포트, 어댑터, JPA 리포지토리 등 신규 도입. 좋아요 저장/삭제/조회, 사용자 검증, 정책 위임 등 구현.
피드/방 게시물 좋아요 API 및 요청/응답 DTO
src/main/java/konkuk/thip/feed/adapter/in/web/FeedCommandController.java, .../feed/adapter/in/web/request/FeedIsLikeRequest.java, .../feed/adapter/in/web/response/FeedIsLikeResponse.java, .../room/adapter/in/web/RoomCommandController.java, .../room/adapter/in/web/request/RoomPostIsLikeRequest.java, .../room/adapter/in/web/response/RoomPostIsLikeResponse.java
피드 및 방 게시물(기록, 투표) 좋아요 상태 변경 API 엔드포인트 추가. 요청/응답 DTO 신설 및 컨트롤러에서 서비스 호출, Swagger 문서화.
예외 및 Swagger 응답
src/main/java/konkuk/thip/common/exception/code/ErrorCode.java, .../common/swagger/SwaggerResponseDescription.java
좋아요 관련 예외 코드(중복 좋아요, 미선호 취소, 카운트 언더플로우 등) 및 방 게시물 타입 불일치 예외 추가. Swagger 응답 설명 enum에 관련 항목 추가.
RoomPostType enum 도입
src/main/java/konkuk/thip/room/domain/RoomPostType.java
방 게시물 타입(RECORD/VOTE) 문자열 매핑 및 PostType 변환 enum 신설.
JPA 엔티티에 좋아요 카운트 setter 추가
src/main/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntity.java, .../record/adapter/out/jpa/RecordJpaEntity.java, .../vote/adapter/out/jpa/VoteJpaEntity.java
테스트 편의를 위한 좋아요 카운트 setter 메서드 추가.
설정 클래스/정책 맵 추가
src/main/java/konkuk/thip/config/PostAccessPolicyConfig.java
기존 설정 클래스명 변경 및 PostLikeAccessPolicy 맵 빈 추가.
테스트: 도메인/컨트롤러/통합
src/test/java/konkuk/thip/feed/domain/FeedTest.java, .../record/domain/RecordTest.java, .../vote/domain/VoteTest.java, .../common/util/TestEntityFactory.java, .../feed/adapter/in/web/FeedChangeLikeStatusAPITest.java, .../room/adapter/in/web/RoomPostChangeLikeStatusAPITest.java, .../room/adapter/in/web/RoomPostChangeLikeStatusControllerTest.java
도메인 단위 테스트(좋아요 카운트/예외), 통합 테스트(피드/방 게시물 좋아요 API), 테스트 엔티티 팩토리 확장 등 신규 테스트 추가 및 보강.
기타
src/main/java/konkuk/thip/common/post/PostType.java
PostType enum의 isFeed/isRecord/isVote 메서드 제거(미사용).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Controller
    participant Service
    participant Validator
    participant PostHandler
    participant CommandPort
    participant QueryPort

    User->>Controller: 좋아요 상태 변경 요청(POST)
    Controller->>Service: changeLikeStatusPost(command)
    Service->>PostHandler: findPost(type, postId)
    PostHandler-->>Service: post
    Service->>Validator: validateUserCanAccessPostLike(type, post, userId)
    Service->>QueryPort: isLikedPostByUser(userId, postId)
    QueryPort-->>Service: alreadyLiked
    alt like 요청
        Service->>Validator: validateUserCanLike(alreadyLiked)
        Service->>CommandPort: save(userId, postId, postType)
    else unlike 요청
        Service->>Validator: validateUserCanUnLike(alreadyLiked)
        Service->>CommandPort: delete(userId, postId)
    end
    Service->>post: updateLikeCount(like)
    Service->>PostHandler: updatePost(type, post)
    Service-->>Controller: PostIsLikeResult
    Controller-->>User: 응답 반환
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Assessment against linked issues

Objective Addressed Explanation
피드 좋아요 상태 변경 API 개발 (#159)
방 게시물(기록, 투표) 좋아요 상태변경 API 개발 (#163)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
PostType enum의 isFeed/isRecord/isVote 메서드 제거 (src/main/java/konkuk/thip/common/post/PostType.java) 해당 메서드 제거는 좋아요 상태 변경 API와 직접적인 연관이 없으며, 리팩토링 성격의 변경입니다.

Suggested labels

🧸 현준

Suggested reviewers

  • seongjunnoh
  • buzz0331

Poem

🐇
좋아요 한 번, 귀가 쫑긋
피드와 방도 이제는 찡긋
카운트 업, 카운트 다운
토끼 마음도 두근두근
새 API와 테스트, 모두 굿!

(코드밭에 당근 한 아름 🎶)

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#159-feed-like

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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
  • 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 src/utils.ts and explain its main purpose.
    • @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 comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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

Documentation and Community

  • 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.

Copy link

@coderabbitai coderabbitai bot left a comment

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 (11)
src/main/java/konkuk/thip/common/post/CountUpdatable.java (2)

3-3: TODO 주석을 해결해야 합니다.

패키지 구조 충돌 문제를 해결하기 위한 리팩토링 작업이 필요합니다. 이후 PR에서 패키지 구조를 정리할 계획을 수립하는 것을 권장합니다.

이 TODO 항목을 추적할 수 있도록 별도 이슈를 생성하시겠습니까?


4-7: 인터페이스 통합이 잘 이루어졌으나 메서드 명명 일관성을 개선할 수 있습니다.

댓글과 좋아요 카운트 관리를 통합한 설계가 좋습니다. 다만 increaseCommentCount/decreaseCommentCountupdateLikeCount의 명명 패턴이 다릅니다.

더 일관된 명명을 위해 다음 중 하나를 고려해보세요:

// Option 1: update 패턴으로 통일
-void increaseCommentCount();
-void decreaseCommentCount();
+void updateCommentCount(boolean increase);
 void updateLikeCount(boolean like);

// Option 2: increase/decrease 패턴으로 통일
 void increaseCommentCount();
 void decreaseCommentCount();
-void updateLikeCount(boolean like);
+void increaseLikeCount();
+void decreaseLikeCount();
src/main/java/konkuk/thip/post/application/port/in/dto/PostIsLikeResult.java (1)

8-10: 불필요한 정적 팩토리 메서드를 제거하세요.

레코드는 이미 동일한 시그니처의 생성자를 제공하므로 정적 팩토리 메서드 of가 불필요합니다. 레코드의 기본 생성자를 직접 사용하는 것이 더 간결합니다.

-    public static PostIsLikeResult of(Long postId, boolean isLiked) {
-        return new PostIsLikeResult(postId, isLiked);
-    }
src/main/java/konkuk/thip/room/domain/RoomPostType.java (1)

21-28: 구현이 올바르지만 성능 최적화 고려

enum 값이 적을 때는 스트림 대신 직접 비교가 더 효율적일 수 있습니다.

성능 최적화를 위해 다음과 같이 변경할 수 있습니다:

 public static RoomPostType from(String type) {
-    return Arrays.stream(RoomPostType.values())
-            .filter(p -> p.getType().equalsIgnoreCase(type))
-            .findFirst()
-            .orElseThrow(() ->
-                    new InvalidStateException(ROOM_POST_TYPE_NOT_MATCH)
-            );
+    for (RoomPostType roomPostType : values()) {
+        if (roomPostType.getType().equalsIgnoreCase(type)) {
+            return roomPostType;
+        }
+    }
+    throw new InvalidStateException(ROOM_POST_TYPE_NOT_MATCH);
 }
src/main/java/konkuk/thip/config/PostAccessPolicyConfig.java (1)

35-42: 메서드명 개선 제안

roomPostAccessPolicyMap 메서드명이 Room 게시물만 다루는 것처럼 보이지만 실제로는 FEED도 포함하고 있습니다.

더 명확한 네이밍을 제안합니다:

 @Bean
-public Map<PostType, PostLikeAccessPolicy> roomPostAccessPolicyMap() {
+public Map<PostType, PostLikeAccessPolicy> postLikeAccessPolicyMap() {
src/main/java/konkuk/thip/feed/adapter/in/web/request/FeedIsLikeRequest.java (1)

10-14: 필드명 개선을 고려해보세요.

Boolean type 필드명이 다소 모호합니다. isLike, like, 또는 likeStatus 같은 더 명확한 이름을 고려해보세요.

public record FeedIsLikeRequest(
-       @Schema(description = "좋아요 여부 type (true -> 좋아요, false -> 좋아요 취소)", example = "true")
+       @Schema(description = "좋아요 여부 (true -> 좋아요, false -> 좋아요 취소)", example = "true")
        @NotNull(message = "좋아요 여부는 필수입니다.")
-       Boolean type
+       Boolean isLike
) {
src/main/java/konkuk/thip/room/adapter/in/web/request/RoomPostIsLikeRequest.java (1)

19-21: toCommand 메서드의 매개변수명이 혼동될 수 있습니다.

toCommand(Long userId, Long feedId) 메서드에서 두 번째 매개변수명이 feedId인데, 실제로는 방 게시물의 postId를 받습니다. 매개변수명을 postId로 변경하는 것이 더 명확할 것 같습니다.

-    public PostIsLikeCommand toCommand(Long userId, Long feedId) {
-        return new PostIsLikeCommand(userId, feedId, RoomPostType.from(roomPostType).toPostType(), type);
+    public PostIsLikeCommand toCommand(Long userId, Long postId) {
+        return new PostIsLikeCommand(userId, postId, RoomPostType.from(roomPostType).toPostType(), type);
     }
src/main/java/konkuk/thip/feed/domain/Feed.java (1)

117-121: validateLike 메서드의 중복 코드를 고려해보세요.

validateLikevalidateCreateComment 메서드가 동일한 로직을 가지고 있습니다. 공통 검증 로직을 추출하여 중복을 제거하는 것을 고려해보세요.

+    private void validatePrivateAccessPermission(Long userId, String action) {
+        if (!this.isPublic && !this.creatorId.equals(userId)) {
+            throw new InvalidStateException(FEED_ACCESS_FORBIDDEN, 
+                new IllegalArgumentException("비공개 글은 작성자만 " + action + " 할 수 있습니다."));
+        }
+    }
+
     public void validateCreateComment(Long userId){
-        if (!this.isPublic && !this.creatorId.equals(userId)) {
-            throw new InvalidStateException(FEED_ACCESS_FORBIDDEN, new IllegalArgumentException("비공개 글은 작성자만 댓글을 쓸 수 있습니다."));
-        }
+        validatePrivateAccessPermission(userId, "댓글을 쓸");
     }

     public void validateLike(Long userId){
-        if (!this.isPublic && !this.creatorId.equals(userId)) {
-            throw new InvalidStateException(FEED_ACCESS_FORBIDDEN, new IllegalArgumentException("비공개 글은 작성자만 좋아요 할 수 있습니다."));
-        }
+        validatePrivateAccessPermission(userId, "좋아요");
     }
src/test/java/konkuk/thip/feed/adapter/in/web/FeedChangeLikeStatusAPITest.java (1)

115-116: 테스트에서 도메인 로직을 우회하고 있습니다.

feed.updateLikeCount(1)을 직접 호출하는 것은 도메인 검증 로직을 우회합니다. 실제 서비스를 통해 좋아요를 추가하거나, 테스트 헬퍼 메서드를 만들어 사용하는 것이 더 안전합니다.

-        feed.updateLikeCount(1); // 좋아요 1개로 세팅
-        feedJpaRepository.save(feed);
+        // 좋아요 카운트는 PostLike 저장 시 자동으로 반영되도록 하거나
+        // 별도의 테스트 헬퍼 메서드 사용
+        feed = feedJpaRepository.findById(feed.getPostId()).orElseThrow();
+        feed.setLikeCount(1); // setter가 있다면
+        feedJpaRepository.save(feed);
src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusAPITest.java (1)

138-139: 테스트에서 도메인 로직을 우회하고 있습니다.

Feed 테스트와 동일하게 updateLikeCount(1)을 직접 호출하는 부분이 있습니다. 일관성을 위해 동일한 방식으로 개선하시기 바랍니다.

Also applies to: 220-221

src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusControllerTest.java (1)

44-44: 테스트 타입 표기가 부정확합니다.

DisplayName에서 "[단위]"로 표기했지만, 이 테스트는 @SpringBootTestMockMvc를 사용하는 통합 테스트입니다.

-@DisplayName("[단위] 방 게시물(기록,투표) 좋아요 api controller 단위 테스트")
+@DisplayName("[통합] 방 게시물(기록,투표) 좋아요 api controller 통합 테스트")
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d96ec46 and 9f46344.

📒 Files selected for processing (48)
  • src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java (2 hunks)
  • src/main/java/konkuk/thip/comment/application/service/CommentDeleteService.java (2 hunks)
  • src/main/java/konkuk/thip/comment/application/service/CommentLikeService.java (2 hunks)
  • src/main/java/konkuk/thip/comment/application/service/policy/CommentAccessPolicy.java (1 hunks)
  • src/main/java/konkuk/thip/comment/application/service/policy/FeedCommentAccessPolicy.java (1 hunks)
  • src/main/java/konkuk/thip/comment/application/service/policy/RoomPostCommentAccessPolicy.java (2 hunks)
  • src/main/java/konkuk/thip/comment/application/service/validator/CommentAuthorizationValidator.java (2 hunks)
  • src/main/java/konkuk/thip/common/exception/code/ErrorCode.java (2 hunks)
  • src/main/java/konkuk/thip/common/post/CommentCountUpdatable.java (0 hunks)
  • src/main/java/konkuk/thip/common/post/CountUpdatable.java (1 hunks)
  • src/main/java/konkuk/thip/common/post/PostType.java (0 hunks)
  • src/main/java/konkuk/thip/common/post/service/PostHandler.java (2 hunks)
  • src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java (2 hunks)
  • src/main/java/konkuk/thip/config/PostAccessPolicyConfig.java (3 hunks)
  • src/main/java/konkuk/thip/feed/adapter/in/web/FeedCommandController.java (3 hunks)
  • src/main/java/konkuk/thip/feed/adapter/in/web/request/FeedIsLikeRequest.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/in/web/response/FeedIsLikeResponse.java (1 hunks)
  • src/main/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntity.java (1 hunks)
  • src/main/java/konkuk/thip/feed/domain/Feed.java (4 hunks)
  • src/main/java/konkuk/thip/post/adapter/out/persistence/PostLikeCommandPersistenceAdapter.java (1 hunks)
  • src/main/java/konkuk/thip/post/adapter/out/persistence/PostLikeJpaRepository.java (2 hunks)
  • src/main/java/konkuk/thip/post/adapter/out/persistence/PostLikeQueryPersistenceAdapter.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/port/in/PostLikeUseCase.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/port/in/dto/PostIsLikeCommand.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/port/in/dto/PostIsLikeResult.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/port/out/PostLikeCommandPort.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/port/out/PostLikeQueryPort.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/service/PostLikeService.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/service/policy/FeedLikeAccessPolicy.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/service/policy/PostLikeAccessPolicy.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/service/policy/RoomPostLikeAccessPolicy.java (1 hunks)
  • src/main/java/konkuk/thip/post/application/service/validator/PostLikeAuthorizationValidator.java (1 hunks)
  • src/main/java/konkuk/thip/record/adapter/out/jpa/RecordJpaEntity.java (2 hunks)
  • src/main/java/konkuk/thip/record/domain/Record.java (3 hunks)
  • src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java (3 hunks)
  • src/main/java/konkuk/thip/room/adapter/in/web/request/RoomPostIsLikeRequest.java (1 hunks)
  • src/main/java/konkuk/thip/room/adapter/in/web/response/RoomPostIsLikeResponse.java (1 hunks)
  • src/main/java/konkuk/thip/room/domain/RoomPost.java (1 hunks)
  • src/main/java/konkuk/thip/room/domain/RoomPostType.java (1 hunks)
  • src/main/java/konkuk/thip/vote/adapter/out/jpa/VoteJpaEntity.java (2 hunks)
  • src/main/java/konkuk/thip/vote/domain/Vote.java (3 hunks)
  • src/test/java/konkuk/thip/common/util/TestEntityFactory.java (2 hunks)
  • src/test/java/konkuk/thip/feed/adapter/in/web/FeedChangeLikeStatusAPITest.java (1 hunks)
  • src/test/java/konkuk/thip/feed/domain/FeedTest.java (2 hunks)
  • src/test/java/konkuk/thip/record/domain/RecordTest.java (2 hunks)
  • src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusAPITest.java (1 hunks)
  • src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusControllerTest.java (1 hunks)
  • src/test/java/konkuk/thip/vote/domain/VoteTest.java (2 hunks)
💤 Files with no reviewable changes (2)
  • src/main/java/konkuk/thip/common/post/PostType.java
  • src/main/java/konkuk/thip/common/post/CommentCountUpdatable.java
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서 Record와 Vote는 Room에 속하지만 Feed는 Room에 속하지 않는 구조이며, 댓글 작성 시 Record/Vote에 대해서만 사용자가 해당 Room의 참가자인지 검증이 필요하다.
📚 Learning: commentcontrollertest는 댓글 생성 api의 검증 로직과 예외 상황만을 테스트하는 단위 테스트이며, 성공 케이스는 별도의 통합 테스트(commentcreateapi...
Learnt from: hd0rable
PR: THIP-TextHip/THIP-Server#101
File: src/test/java/konkuk/thip/comment/adapter/in/web/CommentControllerTest.java:118-265
Timestamp: 2025-07-23T17:41:55.507Z
Learning: CommentControllerTest는 댓글 생성 API의 검증 로직과 예외 상황만을 테스트하는 단위 테스트이며, 성공 케이스는 별도의 통합 테스트(CommentCreateAPITest)에서 다룬다.

Applied to files:

  • src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java
  • src/main/java/konkuk/thip/comment/application/service/CommentLikeService.java
  • src/main/java/konkuk/thip/comment/application/service/CommentDeleteService.java
  • src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusControllerTest.java
  • src/test/java/konkuk/thip/record/domain/RecordTest.java
  • src/test/java/konkuk/thip/vote/domain/VoteTest.java
  • src/test/java/konkuk/thip/feed/domain/FeedTest.java
  • src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusAPITest.java
  • src/test/java/konkuk/thip/feed/adapter/in/web/FeedChangeLikeStatusAPITest.java
📚 Learning: thip 프로젝트에서는 cqrs port 분리 시 다음 컨벤션을 따름: commandport에는 findbyxxx를 통해 도메인 엔티티를 찾아오는 메서드를 추가하고, querypo...
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#43
File: src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java:0-0
Timestamp: 2025-07-03T03:05:05.031Z
Learning: THIP 프로젝트에서는 CQRS Port 분리 시 다음 컨벤션을 따름: CommandPort에는 findByXXX를 통해 도메인 엔티티를 찾아오는 메서드를 추가하고, QueryPort에는 조회 API의 response에 해당하는 데이터들을 DB로부터 조회하는 메서드를 추가함.

Applied to files:

  • src/main/java/konkuk/thip/comment/application/service/CommentLikeService.java
  • src/main/java/konkuk/thip/post/application/port/in/PostLikeUseCase.java
  • src/main/java/konkuk/thip/post/application/port/in/dto/PostIsLikeCommand.java
  • src/main/java/konkuk/thip/common/post/service/PostHandler.java
  • src/main/java/konkuk/thip/post/application/port/out/PostLikeCommandPort.java
  • src/main/java/konkuk/thip/post/application/service/PostLikeService.java
  • src/main/java/konkuk/thip/post/application/port/out/PostLikeQueryPort.java
📚 Learning: thip 프로젝트에서 record와 vote는 room에 속하지만 feed는 room에 속하지 않는 구조이며, 댓글 작성 시 record/vote에 대해서만 사용자가 해당 room...
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서 Record와 Vote는 Room에 속하지만 Feed는 Room에 속하지 않는 구조이며, 댓글 작성 시 Record/Vote에 대해서만 사용자가 해당 Room의 참가자인지 검증이 필요하다.

Applied to files:

  • src/main/java/konkuk/thip/comment/application/service/policy/FeedCommentAccessPolicy.java
  • src/main/java/konkuk/thip/room/adapter/in/web/request/RoomPostIsLikeRequest.java
  • src/main/java/konkuk/thip/comment/application/service/policy/RoomPostCommentAccessPolicy.java
  • src/main/java/konkuk/thip/record/domain/Record.java
  • src/main/java/konkuk/thip/room/domain/RoomPostType.java
  • src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusControllerTest.java
  • src/main/java/konkuk/thip/config/PostAccessPolicyConfig.java
  • src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java
  • src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java
  • src/main/java/konkuk/thip/common/exception/code/ErrorCode.java
  • src/main/java/konkuk/thip/room/domain/RoomPost.java
  • src/main/java/konkuk/thip/feed/domain/Feed.java
  • src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusAPITest.java
📚 Learning: thip 프로젝트에서는 "사용자가 방에 속하는지 검증" 로직을 roomparticipantpolicy 도메인 서비스로 캡슐화하여 재사용성을 높이고 비즈니스 로직의 중복을 방지하는 ...
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서는 "사용자가 방에 속하는지 검증" 로직을 RoomParticipantPolicy 도메인 서비스로 캡슐화하여 재사용성을 높이고 비즈니스 로직의 중복을 방지하는 방식을 선호한다.

Applied to files:

  • src/main/java/konkuk/thip/comment/application/service/policy/RoomPostCommentAccessPolicy.java
  • src/main/java/konkuk/thip/post/application/service/policy/RoomPostLikeAccessPolicy.java
📚 Learning: room 도메인에서 startdate는 현재 날짜 이후여야 하는 도메인 규칙이 있어서, 테스트에서 만료된 상태를 시뮬레이션하려면 reflection을 사용해야 한다....
Learnt from: hd0rable
PR: THIP-TextHip/THIP-Server#57
File: src/test/java/konkuk/thip/room/domain/RoomTest.java:0-0
Timestamp: 2025-07-08T16:30:33.771Z
Learning: Room 도메인에서 startDate는 현재 날짜 이후여야 하는 도메인 규칙이 있어서, 테스트에서 만료된 상태를 시뮬레이션하려면 reflection을 사용해야 한다.

Applied to files:

  • src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusControllerTest.java
📚 Learning: vote와 voteitem 엔티티는 자주 함께 사용되므로, n+1 문제를 방지하기 위해 양방향 매핑과 fetch join을 고려하는 것이 좋습니다. 특히 기록장 조회 api 등에서...
Learnt from: buzz0331
PR: THIP-TextHip/THIP-Server#75
File: src/main/java/konkuk/thip/vote/adapter/out/persistence/VoteQueryRepositoryImpl.java:50-83
Timestamp: 2025-07-14T14:19:38.796Z
Learning: Vote와 VoteItem 엔티티는 자주 함께 사용되므로, N+1 문제를 방지하기 위해 양방향 매핑과 fetch join을 고려하는 것이 좋습니다. 특히 기록장 조회 API 등에서도 함께 사용될 가능성이 높습니다.

Applied to files:

  • src/main/java/konkuk/thip/vote/domain/Vote.java
🧬 Code Graph Analysis (4)
src/main/java/konkuk/thip/comment/application/service/policy/FeedCommentAccessPolicy.java (1)
src/main/java/konkuk/thip/comment/application/service/policy/RoomPostCommentAccessPolicy.java (1)
  • Component (9-21)
src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusControllerTest.java (1)
src/test/java/konkuk/thip/common/util/TestEntityFactory.java (1)
  • TestEntityFactory (34-324)
src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusAPITest.java (1)
src/test/java/konkuk/thip/common/util/TestEntityFactory.java (1)
  • TestEntityFactory (34-324)
src/test/java/konkuk/thip/feed/adapter/in/web/FeedChangeLikeStatusAPITest.java (1)
src/test/java/konkuk/thip/common/util/TestEntityFactory.java (1)
  • TestEntityFactory (34-324)
⏰ 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 (72)
src/main/java/konkuk/thip/comment/application/service/CommentLikeService.java (1)

12-12: 인터페이스 리팩토링이 적절히 적용되었습니다.

CommentCountUpdatable에서 CountUpdatable로의 변경은 댓글과 좋아요 수를 통합적으로 관리할 수 있도록 하는 좋은 추상화입니다. 기존 로직은 그대로 유지되면서 확장성이 향상되었습니다.

Also applies to: 35-35

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

9-9: 일관된 인터페이스 리팩토링 적용 확인.

댓글 생성 서비스에서도 CountUpdatable 인터페이스로의 변경이 올바르게 적용되었습니다. 전체 댓글 관련 서비스들에 걸쳐 일관성 있는 리팩토링이 이루어졌습니다.

Also applies to: 37-37

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

9-9: 리팩토링 일관성 유지 확인.

댓글 삭제 서비스에서도 동일한 인터페이스 변경이 적용되어, 전체 댓글 관련 서비스들의 일관성이 유지되고 있습니다.

Also applies to: 31-31

src/main/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntity.java (1)

59-62: 테스트용 메서드 추가가 적절합니다.

updateLikeCount 메서드가 기존의 updateCommentCount와 동일한 패턴으로 구현되었으며, @VisibleForTesting 어노테이션도 적절히 사용되었습니다.

src/main/java/konkuk/thip/post/application/port/out/PostLikeQueryPort.java (1)

9-9: CQRS 패턴에 맞는 쿼리 메서드 추가 확인.

isLikedPostByUser 메서드가 QueryPort에 적절히 추가되었으며, 사용자의 게시물 좋아요 상태를 확인하는 기능을 제공합니다. CQRS 컨벤션을 올바르게 따르고 있습니다.

src/main/java/konkuk/thip/vote/adapter/out/jpa/VoteJpaEntity.java (2)

3-3: LGTM! 테스트 지원을 위한 적절한 import 추가

@VisibleForTesting 어노테이션 사용을 위한 import가 적절히 추가되었습니다.


47-50: LGTM! 테스트 목적의 메서드가 적절히 구현됨

@VisibleForTesting 어노테이션을 통해 이 메서드가 테스트 목적임을 명확히 하고 있으며, 다른 JPA 엔티티들과 일관된 패턴을 따르고 있습니다.

src/main/java/konkuk/thip/record/adapter/out/jpa/RecordJpaEntity.java (2)

3-3: LGTM! 테스트 지원을 위한 적절한 import 추가

@VisibleForTesting 어노테이션 사용을 위한 import가 적절히 추가되었습니다.


47-50: LGTM! 테스트 목적의 메서드가 일관되게 구현됨

다른 JPA 엔티티들과 동일한 패턴으로 테스트 목적의 updateLikeCount 메서드가 구현되었습니다. @VisibleForTesting 어노테이션을 통해 의도가 명확합니다.

src/main/java/konkuk/thip/post/adapter/out/persistence/PostLikeQueryPersistenceAdapter.java (1)

20-23: LGTM! 적절한 좋아요 상태 조회 메서드 구현

사용자가 특정 게시물에 좋아요를 눌렀는지 확인하는 메서드가 적절히 구현되었습니다. JPA 레포지토리에 위임하는 간단한 구조로, 인터페이스 계약을 정확히 따르고 있습니다.

src/test/java/konkuk/thip/common/util/TestEntityFactory.java (2)

12-12: LGTM! 테스트 팩토리 확장을 위한 적절한 import 추가

PostLike 엔티티 생성을 위한 import가 적절히 추가되었습니다.


318-323: LGTM! 일관된 패턴의 테스트 팩토리 메서드 추가

다른 팩토리 메서드들과 일관된 패턴으로 createPostLike 메서드가 구현되었습니다. 사용자와 게시물 연관관계를 적절히 설정하여 좋아요 기능 테스트를 지원합니다.

src/main/java/konkuk/thip/post/application/port/in/PostLikeUseCase.java (1)

1-8: LGTM! 헥사고날 아키텍처 패턴에 맞는 적절한 유스케이스 인터페이스

좋아요 상태 변경을 위한 유스케이스 인터페이스가 적절히 정의되었습니다. 단일 책임 원칙을 따르고 있으며, Command-Result 패턴을 통해 관심사의 분리가 잘 되어 있습니다. THIP 프로젝트의 기존 포트 분리 컨벤션과도 일치합니다.

src/main/java/konkuk/thip/post/application/service/policy/PostLikeAccessPolicy.java (1)

5-7: 좋아요 접근 정책 인터페이스 설계가 적절합니다.

인터페이스가 단일 책임 원칙을 잘 따르고 있으며, CountUpdatableLong userId 매개변수 타입이 적절합니다. 클린 아키텍처의 정책 패턴을 잘 구현하고 있습니다.

src/main/java/konkuk/thip/comment/application/service/policy/CommentAccessPolicy.java (2)

3-3: 인터페이스 통합이 적절하게 이루어졌습니다.

CommentCountUpdatable에서 CountUpdatable로의 변경이 댓글과 좋아요 카운트 관리를 통합하는 아키텍처 개선과 일치합니다.


6-6: 매개변수 타입 변경이 통합된 인터페이스와 일관성을 유지합니다.

CountUpdatable 매개변수 타입으로 변경하여 댓글과 좋아요 기능 모두에서 재사용 가능한 정책 인터페이스가 되었습니다.

src/main/java/konkuk/thip/post/application/port/in/dto/PostIsLikeCommand.java (1)

5-16: Command DTO 설계가 우수합니다.

Java record를 사용한 불변 객체 설계가 적절하며, PostType enum을 통한 타입 안전성과 boolean isLike를 통한 명확한 의도 표현이 좋습니다. CQRS 패턴의 Command 객체로서 적합합니다.

src/main/java/konkuk/thip/post/application/port/out/PostLikeCommandPort.java (1)

5-8: CommandPort 인터페이스 설계가 적절합니다.

CQRS 패턴을 잘 따르고 있으며, save 메서드에 PostType 매개변수를 포함하여 다양한 게시물 타입을 지원하고, delete 메서드는 필요한 최소 정보만 요구하는 적절한 설계입니다.

src/main/java/konkuk/thip/room/domain/RoomPost.java (1)

3-5: LGTM! 인터페이스 일반화가 잘 되었습니다.

CommentCountUpdatable에서 CountUpdatable로의 변경은 댓글과 좋아요 카운트 관리를 통합하는 아키텍처 개선입니다. 이는 전체 코드베이스에서 일관되게 적용된 리팩토링의 일부로 적절합니다.

src/main/java/konkuk/thip/comment/application/service/policy/FeedCommentAccessPolicy.java (2)

3-3: LGTM! 인터페이스 일반화에 맞춘 변경입니다.

CountUpdatable 인터페이스 사용으로 통일한 변경이 적절합니다.


11-11: LGTM! 메서드 시그니처 변경이 일관됩니다.

CountUpdatable 타입으로 변경하면서도 기존 로직은 그대로 유지된 점이 좋습니다.

src/main/java/konkuk/thip/post/application/service/policy/RoomPostLikeAccessPolicy.java (1)

9-20: LGTM! 좋아요 접근 정책이 잘 구현되었습니다.

기존 댓글 접근 정책과 일관된 패턴을 따르며, RoomParticipantValidator를 재사용하여 코드 중복을 방지한 점이 좋습니다. 방 참여자만 게시물에 좋아요를 할 수 있도록 하는 접근 제어가 적절하게 구현되었습니다.

src/main/java/konkuk/thip/comment/application/service/policy/RoomPostCommentAccessPolicy.java (2)

3-3: LGTM! 인터페이스 통일을 위한 적절한 변경입니다.

CountUpdatable 인터페이스로 통일된 변경이 일관됩니다.


16-16: LGTM! 메서드 시그니처가 일관되게 변경되었습니다.

기존 검증 로직을 유지하면서 새로운 인터페이스를 사용하도록 변경한 점이 적절합니다.

src/main/java/konkuk/thip/room/domain/RoomPostType.java (1)

30-32: PostType.from 구현 검증 완료

PostType.from(String)은 내부적으로 equalsIgnoreCase로 모든 PostType.values()를 순회하며 타입 문자열을 대소문자 구분 없이 매칭하고, 일치하는 값이 없을 경우 InvalidStateException(POST_TYPE_NOT_MATCH)를 던지도록 구현되어 있습니다.
따라서 RoomPostType.toPostType()에서 호출하는 PostType.from(this.type)는 의도한 대로 올바르게 작동합니다.

src/test/java/konkuk/thip/vote/domain/VoteTest.java (4)

8-8: 새로운 에러 코드 import 추가 확인

POST_LIKE_COUNT_UNDERFLOW 에러 코드가 올바르게 추가되었습니다.


128-138: 좋아요 증가 테스트 구현 양호

like가 true일 때 likeCount가 올바르게 증가하는 것을 검증하는 테스트가 잘 구현되었습니다.


140-155: 좋아요 감소 테스트 구현 양호

like가 false일 때 likeCount가 올바르게 감소하는 것을 검증하는 테스트가 잘 구현되었습니다. 셋업 과정도 명확합니다.


157-168: 언더플로우 예외 테스트 구현 양호

좋아요 수가 0 이하로 내려갈 때 적절한 예외가 발생하는지 검증하는 테스트가 올바르게 구현되었습니다.

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

5-12: 깔끔한 응답 DTO 구현

Record를 사용한 응답 DTO가 잘 구현되었습니다. 정적 팩토리 메서드를 통한 변환 로직도 명확합니다.

src/main/java/konkuk/thip/config/PostAccessPolicyConfig.java (1)

23-24: 새로운 의존성 주입 확인

좋아요 접근 정책을 위한 새로운 의존성들이 올바르게 추가되었습니다.

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

5-5: 리팩토링이 올바르게 적용되었습니다.

CommentCountUpdatable에서 CountUpdatable로의 인터페이스 일반화와 필드명 변경이 일관성 있게 적용되어 좋습니다. 댓글과 좋아요 수 관리를 통합하는 구조 변경에 맞춰 적절히 수정되었습니다.

Also applies to: 18-18, 20-20, 25-25

src/main/java/konkuk/thip/post/adapter/out/persistence/PostLikeJpaRepository.java (2)

19-22: 존재 여부 확인 쿼리가 올바르게 구현되었습니다.

CASE WHEN COUNT > 0 패턴을 사용한 존재 여부 확인 로직이 적절하며, 파라미터 바인딩도 올바르게 처리되어 있습니다.


24-26: 삭제 쿼리에 @Modifying 어노테이션이 적절히 적용되었습니다.

JPA에서 DELETE 쿼리 실행을 위해 @Modifying 어노테이션을 올바르게 사용했습니다. 파라미터 바인딩도 정확합니다.

src/main/java/konkuk/thip/room/adapter/in/web/response/RoomPostIsLikeResponse.java (1)

5-11: 깔끔하게 구현된 응답 DTO입니다.

Record 구조가 적절하고, static factory method를 통한 변환 로직도 명확합니다. 필드명도 의미가 명확해 좋습니다.

src/test/java/konkuk/thip/record/domain/RecordTest.java (3)

128-138: 좋아요 증가 테스트가 적절히 작성되었습니다.

like=true일 때 likeCount가 단계별로 증가하는 것을 잘 검증하고 있습니다. 기존 댓글 수 테스트와 일관된 패턴을 따라 좋습니다.


140-155: 좋아요 감소 테스트의 셋업이 명확합니다.

감소 테스트를 위해 먼저 좋아요 수를 증가시키는 셋업 과정이 명확하고, 단계별 감소 검증도 적절합니다.


157-168: 언더플로우 예외 처리 테스트가 정확합니다.

likeCount가 0일 때 감소 시도 시 올바른 예외와 에러 코드를 검증하고 있습니다. 경계값 테스트가 잘 구현되었습니다.

src/main/java/konkuk/thip/feed/adapter/in/web/request/FeedIsLikeRequest.java (1)

15-17: 변환 메서드가 깔끔하게 구현되었습니다.

toCommand 메서드의 파라미터와 변환 로직이 명확하며, static import 사용도 적절합니다.

src/main/java/konkuk/thip/record/domain/Record.java (2)

88-96: 좋아요 수 업데이트 로직이 올바르게 구현되었습니다.

기존 댓글 수 관리 패턴을 일관성 있게 따르고 있으며, underflow 방지를 위한 검증 로직도 적절히 구현되어 있습니다.


104-108: 언더플로우 검증 로직이 적절합니다.

기존 댓글 수 언더플로우 검증과 동일한 패턴으로 구현되어 일관성이 유지되고 있습니다.

src/main/java/konkuk/thip/vote/domain/Vote.java (2)

82-90: 좋아요 수 업데이트 로직이 Record와 동일한 패턴으로 구현되어 일관성이 유지됩니다.

boolean 파라미터를 통한 증가/감소 로직과 언더플로우 검증이 적절히 구현되어 있습니다.


98-102: 언더플로우 검증 로직이 다른 도메인 엔티티와 일관성을 유지합니다.

POST_LIKE_COUNT_UNDERFLOW 에러 코드 사용이 적절합니다.

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

81-92: 피드 좋아요 API 엔드포인트가 올바르게 구현되었습니다.

기존 컨트롤러 패턴을 일관성 있게 따르고 있으며, 유효성 검증, 의존성 주입, Swagger 문서화가 적절히 적용되어 있습니다.

src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java (2)

107-116: 방 게시물 좋아요 상태 변경에 대한 포괄적인 에러 시나리오가 문서화되었습니다.

사용자/게시물 존재 여부, 좋아요 상태 충돌, 언더플로우, 접근 권한, 게시물 타입 불일치 등 모든 주요 에러 케이스가 적절히 포함되어 있습니다.


187-194: 피드 좋아요 상태 변경에 대한 에러 문서화가 적절합니다.

방 게시물과 유사한 에러 시나리오를 다루면서도 피드 특성에 맞는 에러 코드들이 포함되어 있습니다.

src/main/java/konkuk/thip/common/post/service/PostHandler.java (2)

22-28: PostHandler의 findPost 메서드가 CountUpdatable 인터페이스로 올바르게 업데이트되었습니다.

기존 로직을 유지하면서 새로운 인터페이스를 지원하도록 적절히 변경되었습니다.


30-36: updatePost 메서드의 인터페이스 변경이 적절합니다.

CountUpdatable 인터페이스를 사용하면서도 타입 캐스팅을 통해 기존 기능을 안전하게 유지하고 있습니다.

src/main/java/konkuk/thip/room/adapter/in/web/request/RoomPostIsLikeRequest.java (1)

9-18: DTO 설계가 적절하게 구현되었습니다.

요청 DTO의 필드 검증과 Swagger 문서화가 잘 구현되어 있습니다. Boolean과 String 타입 사용도 적절합니다.

src/main/java/konkuk/thip/feed/domain/Feed.java (3)

21-21: 인터페이스 변경이 적절합니다.

CommentCountUpdatable에서 CountUpdatable로 변경하여 댓글과 좋아요 카운트를 통합 관리하는 것이 좋은 설계입니다.


176-184: 좋아요 카운트 업데이트 로직이 잘 구현되었습니다.

증감 로직과 언더플로우 검증이 적절히 구현되어 있습니다.


192-196: 언더플로우 검증이 적절합니다.

좋아요 카운트가 0 이하로 내려가지 않도록 하는 검증 로직이 잘 구현되어 있습니다.

src/test/java/konkuk/thip/feed/domain/FeedTest.java (4)

113-113: 테스트 assertion이 개선되었습니다.

메시지 검증이 더 정확하게 수정되어 테스트의 신뢰성이 향상되었습니다.


271-297: 좋아요 카운트 업데이트 테스트가 잘 구현되었습니다.

증가/감소 로직에 대한 테스트가 적절히 작성되어 있으며, 여러 번 호출하는 케이스도 검증하고 있습니다.


299-310: 언더플로우 예외 처리 테스트가 적절합니다.

좋아요 카운트가 0일 때 추가로 감소시키는 경우의 예외 처리가 올바르게 테스트되고 있습니다.


312-339: 좋아요 접근 권한 테스트가 체계적으로 구현되었습니다.

공개 피드, 비공개 피드의 작성자/비작성자별 접근 권한이 모두 테스트되어 있어 완전한 테스트 커버리지를 제공합니다.

src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java (2)

10-10: 의존성 추가가 적절합니다.

좋아요 기능을 위한 PostLikeUseCase 의존성과 관련 DTO들의 import가 올바르게 추가되었습니다.

Also applies to: 13-14, 37-37


93-104: 방 게시물 좋아요 API가 잘 구현되었습니다.

Swagger 문서화, 유효성 검증, 매개변수 처리가 모두 적절히 구현되어 있습니다. 기존 엔드포인트들과 일관된 패턴을 따르고 있습니다.

src/main/java/konkuk/thip/post/adapter/out/persistence/PostLikeCommandPersistenceAdapter.java (4)

24-29: 의존성 주입이 적절합니다.

필요한 모든 Repository와 Mapper가 올바르게 주입되어 있습니다.


32-40: 좋아요 저장 로직이 잘 구현되었습니다.

사용자와 포스트의 존재를 검증한 후 저장하는 로직이 적절합니다. 예외 처리도 올바르게 구현되어 있습니다.


42-45: 삭제 메서드가 간결하게 구현되었습니다.

좋아요 삭제 로직이 명확하고 간단하게 구현되어 있습니다.


48-57: PostType별 엔티티 조회 로직이 우수합니다.

switch expression을 사용하여 각 포스트 타입별로 적절한 Repository에서 엔티티를 조회하고, 적절한 예외를 던지는 로직이 잘 구현되어 있습니다.

src/main/java/konkuk/thip/common/exception/code/ErrorCode.java (1)

94-94: 에러 코드 추가가 적절합니다.

새로 추가된 에러 코드들이 기존 컨벤션을 잘 따르고 있으며, 메시지가 명확합니다.

Also applies to: 175-177

src/main/java/konkuk/thip/post/application/service/validator/PostLikeAuthorizationValidator.java (1)

14-43: PostLikeAuthorizationValidator 구현이 깔끔합니다.

Strategy 패턴을 활용한 정책 위임 구조가 잘 설계되어 있으며, 중복 좋아요 검증 로직을 중앙화한 것이 좋은 선택입니다.

src/test/java/konkuk/thip/feed/adapter/in/web/FeedChangeLikeStatusAPITest.java (1)

66-152: 통합 테스트가 체계적으로 작성되었습니다.

성공 케이스와 실패 케이스를 모두 다루고 있으며, API 응답과 데이터베이스 상태를 모두 검증하는 점이 좋습니다.

src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusAPITest.java (1)

91-253: Room 게시물 타입별 테스트가 충실합니다.

RECORD와 VOTE 타입 모두에 대해 동일한 시나리오를 테스트하고 있으며, Room 참가자 설정도 적절히 포함되어 있습니다.

src/test/java/konkuk/thip/room/adapter/in/web/RoomPostChangeLikeStatusControllerTest.java (6)

1-38: 임포트 구성이 적절합니다.

통합 테스트에 필요한 모든 의존성이 올바르게 임포트되어 있고, 정적 임포트도 적절히 사용되었습니다.


47-66: 필드 선언이 적절합니다.

테스트에 필요한 모든 리포지토리와 엔티티가 적절히 선언되어 있고, API 경로를 상수로 관리하는 것도 좋은 방식입니다.


68-79: 테스트 설정이 적절합니다.

TestEntityFactory를 사용한 엔티티 생성과 방 참여자 설정이 테스트 시나리오를 잘 지원합니다. user1은 호스트로, user2는 비참여자로 설정하여 양쪽 케이스를 모두 테스트할 수 있도록 구성되었습니다.


81-97: 헬퍼 메서드가 잘 구현되었습니다.

요청 생성과 공통 검증 로직을 헬퍼 메서드로 분리하여 코드 중복을 줄이고 가독성을 향상시켰습니다.


99-104: 잘못된 RoomPostType 검증 테스트가 적절합니다.

방 게시물은 RECORD 또는 VOTE 타입만 허용해야 하므로, FEED 타입으로 요청했을 때 적절한 에러 응답을 확인하는 테스트가 올바릅니다.


106-119: 비참여자 접근 제어 테스트가 올바릅니다.

방에 참여하지 않은 사용자(user2)의 좋아요 시도를 403 Forbidden으로 처리하는 것이 적절하며, 도메인 학습 내용과 일치합니다. Record와 Vote는 Room에 속하므로 참여자만 접근할 수 있어야 합니다.

Copy link
Contributor

@buzz0331 buzz0331 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다~!! 전략 패턴 + 헬퍼 서비스를 자유자재로 사용하시는 것이 역시 고수시네요 🥇

void increaseCommentCount();
void decreaseCommentCount();
void updateLikeCount(boolean like);
Long getId();
Copy link
Contributor

Choose a reason for hiding this comment

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

p3: getId는 어차피 공통으로 getter를 사용하는 것 같아서 굳이 없어도 될 것 같습니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

앗 이거 공통로직시에 updatable에서 뽑아올때 필요합니닷!!

Copy link
Contributor

Choose a reason for hiding this comment

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

아하 흐음 이건 어쩔수 없이 열어둬야 될 것 같네여 🤔

Comment on lines +9 to +18
@Schema(description = "피드 좋아요 상태 변경 요청 DTO")
public record FeedIsLikeRequest(
@Schema(description = "좋아요 여부 type (true -> 좋아요, false -> 좋아요 취소)", example = "true")
@NotNull(message = "좋아요 여부는 필수입니다.")
Boolean type
) {
public PostIsLikeCommand toCommand(Long userId, Long feedId) {
return new PostIsLikeCommand(userId, feedId, FEED ,type);
}
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

오호 이렇게 상수로 넣어주었군요!! 굿굿 좋습니다!

Comment on lines 25 to 49
@Override
@Transactional
public PostIsLikeResult changeLikeStatusPost(PostIsLikeCommand command) {

// 1. 게시물 타입에 맞게 검증 및 조회
CountUpdatable post = postHandler.findPost(command.postType(), command.postId());
// 1-1. 게시글 타입에 따른 게시물 좋아요 권한 검증
postLikeAuthorizationValidator.validateUserCanAccessPostLike(command.postType(), post, command.userId());

// 2. 유저가 해당 게시물에 대해 좋아요 했는지 조회
boolean alreadyLiked = postLikeQueryPort.isLikedPostByUser(command.userId(), command.postId());

// 3. 좋아요 상태변경
//TODO 게시물의 좋아요 수 증가/감소 동시성 제어 로직 추가해야됨
if (command.isLike()) {
postLikeAuthorizationValidator.validateUserCanLike(alreadyLiked); // 좋아요 가능 여부 검증
postLikeCommandPort.save(command.userId(), command.postId(),command.postType());
} else {
postLikeAuthorizationValidator.validateUserCanUnLike(alreadyLiked); // 좋아요 취소 가능 여부 검증
postLikeCommandPort.delete(command.userId(), command.postId());
}

// 4. 게시물 좋아요 수 업데이트
post.updateLikeCount(command.isLike());
postHandler.updatePost(command.postType(), post);
Copy link
Contributor

Choose a reason for hiding this comment

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

LG™

Comment on lines 88 to 97
@Override
public void updateLikeCount(boolean like) {
if (like) {
likeCount++;
} else {
checkLikeCountNotUnderflow();
likeCount--;
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

pr을 확인해보니 Feed, Record, Vote 모두 여기서 중복 로직을 사용하는 것 같아서 의문이 들었다고 하셔서 리팩토링에 대해 고민을 해봤습니다. 마침 저희가 읽었던 책의 내용을 적용해볼 수 있는 기회라고 생각되어, 조심스럽게 제안을 드려봅니다.!
책에서 언급되었던 것처럼, 여러 도메인에서 공통적으로 사용되는 도메인 로직이 있는 경우에 도메인 객체에서 도메인 서비스를 파라미터로 주입받아 사용하는 방식을 생각해보았습니다. 물론 현재 저희가 사용중인 PostHandler는 헬퍼 서비스이긴 하지만 내부적으로 외부 port를 호출하지 않는 메서드라면 결국 도메인 서비스로 간주해도 무방하다고 생각했습니다.

제가 생각한 리팩토링 예시 코드입니다! 실제로 구현하고 postman으로 테스트까지 완료했습니다!

public interface CountUpdatable { 
    void updateLikeCount(PostHandler postHandler, boolean isLike);
}

public class PostHandler {
    public int updatePostLikeCount(boolean isLike, int likeCount) {
        if (isLike) {
            return ++likeCount;

        } else {
            checkLikeCountNotUnderflow(likeCount);
            return --likeCount;
        }
    }

    private void checkLikeCountNotUnderflow(int likeCount) {
        if (likeCount <= 0) {
            throw new InvalidStateException(POST_LIKE_COUNT_UNDERFLOW);
        }
    }
}
public class Feed {
    @Override
    public void updateLikeCount(PostHandler postHandler, boolean isLike) {
        likeCount = postHandler.updatePostLikeCount(isLike, likeCount);
    }
}

public class PostLikeService {
       // 4. 게시물 좋아요 수 업데이트
        post.updateLikeCount(postHandler, command.isLike());
        postHandler.updatePost(command.postType(), post);
}

물론, 도메인에서 헬퍼 서비스를 호출하는 구조에 대해 의존성 역전이 발생할 수 있다는 우려도 있을 수 있지만, 말씀드린 것처럼 포트를 호출하고 있지는 않으므로 큰 문제는 없다고 판단했습니다. 혹시나 의존성 역전이 우려되신다면 PostLikeHandler와 같이 도메인 계층 내에서 책임을 갖는 별도 클래스를 따로 정의하는 것도 괜찮다고 생각합니다. 이렇게 도메인 계층이 하나 생긴다면 CommentCount를 업데이트 하는 쪽도 마찬가지로 리팩토링이 가능하다고 봅니다..!

Copy link
Member Author

Choose a reason for hiding this comment

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

오호 좋은 방법인것 같습니다 다만 제가 처음 구현했을때 PostHandler의 의도는 게시물을 타입별로 조회,업데이트할때 사용하는 헬퍼서비스라고 생각하고 구현했기때문에 게시물의 공통 인터페이스도 CountUpdatable로 변경되었으니 PostCountHandler를 따로 정의해서 사용하는 것이 더 나을것같네요!!

Copy link
Contributor

Choose a reason for hiding this comment

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

엇 그렇다면 PostCountHandler는 정말 어떤 컴포넌트도 의존하지 않게 될 것 같아서 완전한 도메인 서비스가 될 것 같네요! 그렇다면, PostDomainService 또는 PostCountService라고 하고 도메인 계층에 넣는 것도 좋을 것 같아요~

Copy link
Collaborator

Choose a reason for hiding this comment

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

Feed, Vote, Record 가 공통으로 담당하는 도메인 로직을 도메인 서비스를 정의하여 얘한테 책임을 미루고, 이 도메인 서비스를 의존하는 의견 너무 좋습니다!!

seongjunnoh
seongjunnoh previously approved these changes Aug 7, 2025
Copy link
Collaborator

@seongjunnoh seongjunnoh left a comment

Choose a reason for hiding this comment

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

고생하셨습니다! 공통 유스케이스로 묶으니 좋네요

pr 리뷰 요구사항에 언급해주신 내용에 대해서는

  1. 현준띠 의견 적극 동의
  2. roomId 와 관련해서도 현재처럼 postId로 게시글 조회한 후, 이게 RoomPost 이라면 유저가 해당 방에 속하는지의 유효성 검증을 통해 풀어가므로 굳이 roomId를 명시적으로 안 받아도 될 것 같습니다!

Comment on lines +6 to +8
public interface PostLikeUseCase {
PostIsLikeResult changeLikeStatusPost(PostIsLikeCommand PostIsLikeCommand);
} No newline at end of file
Copy link
Collaborator

Choose a reason for hiding this comment

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

게시글 좋아요 공통 유스케이스 좋습니다

boolean alreadyLiked = postLikeQueryPort.isLikedPostByUser(command.userId(), command.postId());

// 3. 좋아요 상태변경
//TODO 게시물의 좋아요 수 증가/감소 동시성 제어 로직 추가해야됨
Copy link
Collaborator

Choose a reason for hiding this comment

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

ㅋㅋ

Copy link
Member Author

Choose a reason for hiding this comment

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

ㅎㅎ

Comment on lines +35 to 43
@Bean
public Map<PostType, PostLikeAccessPolicy> postLikeAccessPolicyMap() {
return Map.of(
PostType.FEED, feedLikePolicy,
PostType.RECORD, roomPostLikePolicy,
PostType.VOTE, roomPostLikePolicy
);
}
} No newline at end of file
Copy link
Collaborator

Choose a reason for hiding this comment

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

LGTM

Comment on lines +119 to +127
// 댓글 작성 권한 검증
public void validateCreateComment(Long userId){
validatePrivateAccessPermission(userId, "댓글을 쓸 수");
}

// 좋아요 권한 검증
public void validateLike(Long userId){
validatePrivateAccessPermission(userId, "좋아요 할 수");
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

ㅋㅋㅋㅋㅋㅋ 신기한 방식의 에러 메시지 만드는 방식이네요

Copy link
Member Author

Choose a reason for hiding this comment

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

사실 공통 검증인데 예외메세지를 다르게 만들고싶어서,,ㅎ 해봣습니닷

@GetMapping("/rooms/{roomId}/playing")
public BaseResponse<RoomPlayingDetailViewResponse> getPlayingRoomDetailView(
@UserId final Long userId,
@Parameter(hidden = true) @UserId final Long userId,
Copy link
Collaborator

Choose a reason for hiding this comment

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

@buzz0331 감사합니다

Copy link
Member Author

Choose a reason for hiding this comment

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

@buzz0331 감사합니다

Comment on lines +15 to +17
@Schema(description = "게시물 타입 (RECORD, VOTE)", example = "RECORD")
@NotBlank(message = "게시물 타입은 필수입니다.")
String roomPostType
Copy link
Collaborator

Choose a reason for hiding this comment

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

굳굳

Comment on lines +10 to +15
@Getter
@RequiredArgsConstructor
public enum RoomPostType {

RECORD("RECORD"),
VOTE("VOTE");
Copy link
Collaborator

Choose a reason for hiding this comment

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

이게 생겼군요

Comment on lines +35 to +40
@SpringBootTest
@ActiveProfiles("test")
@AutoConfigureMockMvc(addFilters = false)
@Transactional
@DisplayName("[통합] 피드 좋아요 api 통합 테스트")
class FeedChangeLikeStatusAPITest {
Copy link
Collaborator

Choose a reason for hiding this comment

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

LGTM

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/main/java/konkuk/thip/record/domain/Record.java (1)

89-92: 도메인 서비스 패턴 적용이 우수합니다.

이전 리뷰에서 논의된 도메인 서비스 패턴이 잘 적용되었습니다. PostCountService를 파라미터로 받아 좋아요 수 업데이트 로직을 위임하는 방식은 코드 중복을 방지하고 도메인 로직을 중앙화하는 좋은 접근입니다.

src/main/java/konkuk/thip/post/domain/service/PostCountService.java (1)

8-9: 서비스 구조가 명확합니다.

PostCountService는 게시물 수 관리 책임을 명확하게 분리한 좋은 도메인 서비스입니다. 이전 리뷰에서 제안된 대로 공통 로직을 중앙화하여 Feed, Record, Vote 간의 코드 중복을 해결했습니다.

🧹 Nitpick comments (1)
src/main/java/konkuk/thip/post/domain/service/PostCountService.java (1)

11-19: 전위 증감 연산자 사용을 재고해보세요.

현재 ++likeCount, --likeCount를 사용하고 있는데, 매개변수는 값으로 전달되므로 원본에 영향을 주지 않습니다. 의도는 명확하지만 가독성을 위해 다음과 같이 변경하는 것이 좋겠습니다:

 public int updatePostLikeCount(boolean isLike, int likeCount) {
     if (isLike) {
-        return ++likeCount;
+        return likeCount + 1;
     } else {
         checkLikeCountNotUnderflow(likeCount);
-        return --likeCount;
+        return likeCount - 1;
     }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 96e7bb2 and 1daf813.

📒 Files selected for processing (9)
  • src/main/java/konkuk/thip/common/post/CountUpdatable.java (1 hunks)
  • src/main/java/konkuk/thip/feed/domain/Feed.java (4 hunks)
  • src/main/java/konkuk/thip/post/application/service/PostLikeService.java (1 hunks)
  • src/main/java/konkuk/thip/post/domain/service/PostCountService.java (1 hunks)
  • src/main/java/konkuk/thip/record/domain/Record.java (3 hunks)
  • src/main/java/konkuk/thip/vote/domain/Vote.java (3 hunks)
  • src/test/java/konkuk/thip/feed/domain/FeedTest.java (4 hunks)
  • src/test/java/konkuk/thip/record/domain/RecordTest.java (2 hunks)
  • src/test/java/konkuk/thip/vote/domain/VoteTest.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/test/java/konkuk/thip/vote/domain/VoteTest.java
  • src/main/java/konkuk/thip/common/post/CountUpdatable.java
  • src/main/java/konkuk/thip/vote/domain/Vote.java
  • src/test/java/konkuk/thip/record/domain/RecordTest.java
  • src/test/java/konkuk/thip/feed/domain/FeedTest.java
  • src/main/java/konkuk/thip/feed/domain/Feed.java
  • src/main/java/konkuk/thip/post/application/service/PostLikeService.java
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서 Record와 Vote는 Room에 속하지만 Feed는 Room에 속하지 않는 구조이며, 댓글 작성 시 Record/Vote에 대해서만 사용자가 해당 Room의 참가자인지 검증이 필요하다.
📚 Learning: seongjunnoh는 코드 중복 문제에 대한 리팩토링 제안을 적극적으로 수용하고 함수형 인터페이스를 활용한 해결책을 선호한다....
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#93
File: src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java:49-114
Timestamp: 2025-07-28T16:44:31.224Z
Learning: seongjunnoh는 코드 중복 문제에 대한 리팩토링 제안을 적극적으로 수용하고 함수형 인터페이스를 활용한 해결책을 선호한다.

Applied to files:

  • src/main/java/konkuk/thip/record/domain/Record.java
📚 Learning: thip 프로젝트에서 record와 vote는 room에 속하지만 feed는 room에 속하지 않는 구조이며, 댓글 작성 시 record/vote에 대해서만 사용자가 해당 room...
Learnt from: seongjunnoh
PR: THIP-TextHip/THIP-Server#101
File: src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java:36-39
Timestamp: 2025-07-26T06:09:00.850Z
Learning: THIP 프로젝트에서 Record와 Vote는 Room에 속하지만 Feed는 Room에 속하지 않는 구조이며, 댓글 작성 시 Record/Vote에 대해서만 사용자가 해당 Room의 참가자인지 검증이 필요하다.

Applied to files:

  • src/main/java/konkuk/thip/record/domain/Record.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 (2)
src/main/java/konkuk/thip/record/domain/Record.java (1)

5-6: 인터페이스 변경이 적절합니다.

CommentCountUpdatable에서 CountUpdatable로 변경한 것은 좋아요와 댓글 수 관리를 통합하는 좋은 설계 결정입니다. 인터페이스명도 더 범용적이고 명확해졌습니다.

Also applies to: 16-16

src/main/java/konkuk/thip/post/domain/service/PostCountService.java (1)

21-25: 언더플로우 검증 로직이 적절합니다.

좋아요 수가 0 이하일 때 감소를 방지하는 검증 로직이 올바르게 구현되었습니다. 예외 타입과 에러 코드도 적절하며, private 메서드로 캡슐화된 것도 좋습니다.

buzz0331
buzz0331 previously approved these changes Aug 7, 2025
Copy link
Contributor

@buzz0331 buzz0331 left a comment

Choose a reason for hiding this comment

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

굿굿~!!


import static konkuk.thip.common.exception.code.ErrorCode.POST_LIKE_COUNT_UNDERFLOW;

@Service
Copy link
Contributor

Choose a reason for hiding this comment

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

오호 이것도 DomainService하나 만드는게 좋아보이네여 나중에 만들죠.!

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-221] [feat] 방 게시물(기록, 투표) 좋아요 상태변경 api 개발 [THIP2025-217] [feat] 피드 좋아요 상태 변경 api 개발

3 participants