Skip to content

[Feat] 댓글 삭제 api 개발#134

Merged
hd0rable merged 53 commits into
developfrom
feat/#103-comment-delete
Aug 5, 2025
Merged

[Feat] 댓글 삭제 api 개발#134
hd0rable merged 53 commits into
developfrom
feat/#103-comment-delete

Conversation

@hd0rable
Copy link
Copy Markdown
Member

@hd0rable hd0rable commented Aug 2, 2025

#️⃣ 연관된 이슈

closes #103

📝 작업 내용

  • 댓글 삭제 api를 개발했습니다.
  • 댓글 삭제 api 의 흐름은 다음과 같습니다.
  1. Controller에서 서비스로 요청이들어옴
  2. 댓글 조회 및 검증, 댓글의 게시물 타입별로 댓글 접근 관련 권한 검증
  3. 댓글 소프트 딜리트 처리
  4. 변경된 댓글엔티티 업데이트
  5. 게시글 도메인, jpa 엔티티 댓글 수 감소
  6. 댓글에 달린 좋아요 일괄 삭제( 댓글이 soft delete이기 때문에 굳이 댓글의 likecount는 초기화 안하고 그대로 상태만 INACTIVE로 변경)
  • thip의 요구사항에 따라 루트 댓글일 시, 댓글의 대댓글은 연쇄적으로 삭제되지않고 삭제된 댓글만 소프트 딜리트 처리됩니다.
  • 댓글 삭제시에 도메인에서 댓글을 작성한 작성자가 댓글을 삭제하려고 하는지에 대한 검증이 이루어집니다.
  • 기존에 댓글 좋아요 상태 변경 시에 사용되었던, commentLikeJpaRepository.existsByUserIdAndCommentId(userId, commentId)의 반환값을Object로 수정하였습니다. 또한 어댑터에서 반환값에 따른 분기처리도 진행했습니다. 변경한 이유는 다음과 같습니다.
  • commentLikeJpaRepository.existsByUserIdAndCommentId(userId, commentId)의 반환값이 DB 환경마다 다른것을 확인했습니다. mysql에서 EXISTS쿼리의 반환값은 0/1로 숫자이지만 H2에서의 반환값은 boolean입니다. 하지만 jpa가 내부적으로 mysql의 반환값을 boolean으로 캐스팅해주지만 저희의 jpa엔티티의 구조상 필드로 엔티티id가 아닌 엔티티를 가지고있기때문에 불필요한 조인을 줄이기위해 nativeQuery를 사용하면서 충돌 문제가 발생한 것습니다.
  • 또한 피드 관련 스웨거 설명시에 누락된 코드들이나 설명들이 있어서 추가했습니다.(제가 구현한건데도 잘적어주신 현준띠니에게 쌰라웃)
  • 관련 통합,단위 테스트도 같이 작성하였습니다.
  • @SQLDelete 어노테이션을 사용하려고 했는데 어차피 저희가 엔티티의 변경시 update함수를 엔티티별로 하나만 뚫어놓은상태이고 굳이 delete함수를 어댑터에 추가하는 것은 똑같은 기능을 하는 update와 중복 코드가 겹쳐 어댑터의 update함수를 사용하는 식으로 구현했습니다.(이거와 별개로 댓글을 delete처리하고 댓글의 좋아요들을 삭제하기위해서 불러오는과정에서 영속성 자체에서 에러가 나는것도 있길래..? 그렇습니다)

📸 스크린샷

💬 리뷰 요구사항

댓글 삭제 시, soft delete를 수행하는데 updateSatus가 아닌 softDelete로 soft delete하는 도메인임을 명시하고 싶어서 메서드명을 이런식으로 작성했는데 괜찮은지 의견부탁드립니다!

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

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

Summary by CodeRabbit

  • 신규 기능

    • 댓글 삭제 API가 추가되어 사용자가 댓글을 삭제할 수 있습니다.
    • 댓글 삭제 시 댓글이 소프트 삭제 처리되고, 연관된 좋아요가 모두 삭제됩니다.
    • 댓글 삭제 시 게시글의 댓글 수가 감소하며, 0 이하로 감소할 경우 오류가 발생합니다.
  • 버그 수정

    • 댓글, 피드, 기록, 투표의 댓글 수 감소 시 0 미만으로 내려갈 수 없도록 예외 처리가 추가되었습니다.
  • 문서화

    • 댓글 삭제 및 피드 수정, 피드 업데이트 요청 필드에 대한 Swagger 문서가 보강되었습니다.
  • 테스트

    • 댓글 삭제 기능 및 댓글 수 증감에 대한 단위/통합 테스트가 추가되었습니다.
  • 리팩터링

    • 게시글 관련 공통 처리를 PostHandler로 통합하여 코드 구조가 개선되었습니다.

hd0rable added 30 commits August 3, 2025 02:44
Copy link
Copy Markdown
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.

수고하셨습니다!! 그 현재 헬퍼 서비스를 잘 활용하신 것 같은데 헬퍼 서비스에 한하여 제가 이전 pr에서 만들어둔 @Component 대신 @HelperService를 붙여주시면 감사하겠습니다!!


// 2. 댓글 Soft Delete 처리
comment.softDelete(userId);
commentCommandPort.update(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.

오호 극동입니다. 위 리뷰와 일맥상통하는 이야기일 것 같은데 성준님이 말씀하신 대로 delete 흐름을 구성하면 CommentJpaEntity의 updateFrom에서 굳이 status에 접근할 필요가 없어질 것 같습니다!!

Comment thread src/main/java/konkuk/thip/common/entity/BaseDomainEntity.java Outdated
Copy link
Copy Markdown

@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

♻️ Duplicate comments (1)
src/test/java/konkuk/thip/comment/adapter/in/web/CommentDeleteAPITest.java (1)

150-151: CommentLike 존재 여부 확인 로직을 재검토해주세요.

과거 리뷰에서 지적된 commentLikeJpaRepository.existsByUserIdAndCommentId()의 Object 반환 타입 문제가 여전히 존재합니다. MySQL과 H2 간의 차이점으로 인한 캐스팅 오류가 발생할 수 있습니다.

다음 스크립트로 현재 구현을 확인해보겠습니다:

#!/bin/bash
# Description: CommentLikeJpaRepository의 existsByUserIdAndCommentId 메서드 현재 구현 확인

# 메서드 구현 찾기
ast-grep --pattern 'existsByUserIdAndCommentId($_, $_)'

# 테스트에서 사용하는 부분 확인
rg -A 3 -B 3 "existsByUserIdAndCommentId" src/test/
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b7ccf95 and 2d8ed70.

📒 Files selected for processing (18)
  • src/main/java/konkuk/thip/comment/adapter/in/web/CommentCommandController.java (3 hunks)
  • src/main/java/konkuk/thip/comment/adapter/in/web/response/CommentDeleteResponse.java (1 hunks)
  • src/main/java/konkuk/thip/comment/adapter/out/jpa/CommentJpaEntity.java (2 hunks)
  • src/main/java/konkuk/thip/comment/adapter/out/jpa/CommentLikeJpaEntity.java (1 hunks)
  • src/main/java/konkuk/thip/comment/adapter/out/persistence/CommentCommandPersistenceAdapter.java (2 hunks)
  • src/main/java/konkuk/thip/comment/adapter/out/persistence/repository/CommentLikeJpaRepository.java (1 hunks)
  • src/main/java/konkuk/thip/comment/application/port/in/CommentDeleteUseCase.java (1 hunks)
  • src/main/java/konkuk/thip/comment/application/port/out/CommentCommandPort.java (1 hunks)
  • src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java (4 hunks)
  • src/main/java/konkuk/thip/comment/application/service/CommentDeleteService.java (1 hunks)
  • src/main/java/konkuk/thip/comment/application/service/CommentLikeService.java (3 hunks)
  • src/main/java/konkuk/thip/comment/domain/Comment.java (1 hunks)
  • src/main/java/konkuk/thip/common/exception/code/ErrorCode.java (1 hunks)
  • src/main/java/konkuk/thip/common/post/CommentCountUpdatable.java (1 hunks)
  • src/main/java/konkuk/thip/common/post/service/PostHandler.java (2 hunks)
  • src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java (1 hunks)
  • src/test/java/konkuk/thip/comment/adapter/in/web/CommentDeleteAPITest.java (1 hunks)
  • src/test/java/konkuk/thip/comment/domain/CommentTest.java (3 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/main/java/konkuk/thip/comment/application/service/CommentLikeService.java
  • src/main/java/konkuk/thip/comment/adapter/in/web/response/CommentDeleteResponse.java
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/main/java/konkuk/thip/comment/application/service/CommentCreateService.java
  • src/main/java/konkuk/thip/comment/adapter/out/persistence/CommentCommandPersistenceAdapter.java
  • src/main/java/konkuk/thip/comment/application/service/CommentDeleteService.java
  • src/main/java/konkuk/thip/comment/domain/Comment.java
  • src/main/java/konkuk/thip/comment/adapter/in/web/CommentCommandController.java
  • src/main/java/konkuk/thip/comment/adapter/out/jpa/CommentJpaEntity.java
  • src/main/java/konkuk/thip/common/post/CommentCountUpdatable.java
  • src/test/java/konkuk/thip/comment/domain/CommentTest.java
  • src/main/java/konkuk/thip/common/exception/code/ErrorCode.java
  • src/main/java/konkuk/thip/comment/application/port/in/CommentDeleteUseCase.java
  • src/main/java/konkuk/thip/comment/adapter/out/persistence/repository/CommentLikeJpaRepository.java
  • src/main/java/konkuk/thip/common/swagger/SwaggerResponseDescription.java
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
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)에서 다룬다.
📚 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/port/out/CommentCommandPort.java
  • src/main/java/konkuk/thip/common/post/service/PostHandler.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/common/post/service/PostHandler.java
  • src/test/java/konkuk/thip/comment/adapter/in/web/CommentDeleteAPITest.java
📚 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/test/java/konkuk/thip/comment/adapter/in/web/CommentDeleteAPITest.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 (7)
src/main/java/konkuk/thip/comment/application/port/out/CommentCommandPort.java (1)

24-25: LGTM! 댓글 삭제 기능을 위한 포트 메서드 추가

소프트 딜리트 메커니즘 구현을 위한 delete(Comment comment) 메서드가 적절하게 추가되었습니다. Comment 도메인 객체를 파라미터로 받는 시그니처가 CQRS CommandPort 패턴에 잘 부합합니다.

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

3-3: 클래스 명명과 어노테이션 변경이 적절합니다.

PostQueryService에서 PostHandler로의 이름 변경과 @HelperService 어노테이션 사용이 클래스의 역할을 더 명확히 표현합니다. 단순 조회뿐만 아니라 업데이트 기능도 포함하므로 Handler라는 명명이 더 적절합니다.

Also applies to: 14-16


7-11: 도메인 클래스 import 추가가 필요합니다.

새로운 updatePost 메서드에서 타입 캐스팅을 위해 도메인 클래스들의 import가 필요하므로 적절한 변경입니다.

src/test/java/konkuk/thip/comment/adapter/in/web/CommentDeleteAPITest.java (4)

40-44: 통합 테스트 설정이 적절합니다.

@SpringBootTest, @ActiveProfiles("test"), @AutoConfigureMockMvc(addFilters = false) 설정이 댓글 삭제 API 통합 테스트에 적합합니다.


73-84: 테스트 데이터 설정이 포괄적입니다.

댓글 삭제 테스트에 필요한 모든 도메인 엔티티들(User, Feed, Room, Book 등)을 적절히 생성하고 있어 실제 운영 환경과 유사한 테스트 환경을 제공합니다.


87-103: 루트댓글 삭제 테스트가 적절합니다.

soft delete 동작을 findById().isEmpty()로 검증하는 것이 적절합니다. @SQLDelete 어노테이션으로 인해 INACTIVE 상태의 댓글은 조회되지 않으므로 올바른 검증 방법입니다.


105-123: 대댓글 삭제 테스트가 적절합니다.

부모 댓글과 대댓글을 생성한 후 대댓글만 삭제하는 시나리오를 적절히 테스트하고 있습니다.

Comment thread src/main/java/konkuk/thip/comment/adapter/out/jpa/CommentLikeJpaEntity.java Outdated
Comment thread src/main/java/konkuk/thip/common/post/service/PostHandler.java
Copy link
Copy Markdown
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.

수고하셨습니다!! PR에 관련 이슈 번호 빠져있네여~ 채워넣고 머지 부탁드려용

@hd0rable hd0rable merged commit 7a6948f into develop Aug 5, 2025
1 of 2 checks passed
@hd0rable hd0rable deleted the feat/#103-comment-delete branch August 5, 2025 11:31
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-150] [feat] 댓글 삭제 api 개발 및 Comment 도메인 soft delete 전략 도임

3 participants