Conversation
기존에 redis container 띄워서 통과하던 테스트(PostControllerPagingTest)에 redis container 추가
생성, 삭제, 수정 연동
댓글 조회 제약 구현 + 테스트
|
Caution Review failedThe pull request is closed. Walkthrough백엔드에 댓글 기능이 새롭게 도입되어 댓글 엔티티, DTO, 예외, 서비스, 컨트롤러, 저장소, 트리 빌더 등이 추가되었습니다. 게시글 상세 응답에 댓글 트리가 포함되고, 프론트엔드에서는 댓글 UI 및 API 연동 컴포넌트가 도입되었습니다. 테스트 코드와 시간 관련 설정도 보강되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Frontend as "CommentSection (React)"
participant API as "CommentController"
participant Service as "CommentService"
participant Repo as "CommentRepository"
participant DB
User->>Frontend: 댓글 작성/수정/삭제/답글 입력
Frontend->>API: POST/PATCH/DELETE /api/comments (with JWT)
API->>Service: createComment/updateComment/deleteComment
Service->>Repo: 댓글, 유저, 게시글, 부모댓글 조회/검증
Repo->>DB: 쿼리 실행
Service-->>API: 결과 DTO or 예외
API-->>Frontend: 201/204/에러 응답
Frontend-->>User: UI 갱신 (refresh)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested labels
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 16
🔭 Outside diff range comments (2)
frontend/src/pages/posts/PostDetailPage.jsx (1)
26-37: JWT 파싱 로직이 중복되어 있습니다.JWT 토큰 파싱 코드가 두 번 반복되고 있습니다. 하나로 통합하여 코드 중복을 제거해야 합니다.
- // JWT 파싱 (try-catch로 에러 방어 추천) - try { - const payload = JSON.parse(base64.decode(token.split('.')[1])); - setMyUserId(payload.userId); - } catch (error) { - console.error('JWT 파싱 오류:', error); - } - let loginUserId = null; - if (token) { - const payload = JSON.parse(base64.decode(token.split('.')[1])); - loginUserId = payload.userId; - setMyUserId(loginUserId); - } + // JWT 파싱 (try-catch로 에러 방어) + if (token) { + try { + const payload = JSON.parse(base64.decode(token.split('.')[1])); + setMyUserId(payload.userId); + } catch (error) { + console.error('JWT 파싱 오류:', error); + } + }backend/src/main/java/org/juniortown/backend/post/dto/response/PostDetailResponse.java (1)
42-56: from() 메서드에서 comments 필드가 누락됨
from()메서드가comments매개변수 없이 빌더를 호출하여comments필드가 null로 설정됩니다. 이는 런타임 NullPointerException을 발생시킬 수 있습니다.다음 diff를 적용하여 수정하세요:
public static PostDetailResponse from(PostResponse postResponse) { return PostDetailResponse.builder() .id(postResponse.getId()) .title(postResponse.getTitle()) .content(postResponse.getContent()) .userId(postResponse.getUserId()) .userName(postResponse.getUserName()) .likeCount(postResponse.getLikeCount()) .isLiked(postResponse.getIsLiked()) .readCount(postResponse.getReadCount()) + .comments(List.of()) .createdAt(postResponse.getCreatedAt()) .updatedAt(postResponse.getUpdatedAt()) .deletedAt(postResponse.getDeletedAt()) .build(); }
🧹 Nitpick comments (14)
backend/src/main/java/org/juniortown/backend/post/dto/request/PostCreateRequest.java (1)
12-12: @Setter 애노테이션의 필요성을 검토해보세요.
//??코멘트가 있는 것으로 보아 @Setter의 필요성에 대해 의문을 가지고 계신 것 같습니다. PostCreateRequest는 요청 DTO로 다음을 고려해보세요:
- @builder 패턴을 사용하고 있어 setter가 불필요할 수 있습니다
- Request DTO는 일반적으로 불변객체로 설계하는 것이 좋습니다
- Jackson 역직렬화에는 setter 대신 생성자나 필드 접근이면 충분합니다
다음과 같이 @Setter를 제거하는 것을 고려해보세요:
-@Setter //?? +// @Setter 제거 - 불변 DTO로 유지backend/src/main/java/org/juniortown/backend/comment/exception/ParentPostMismatchException.java (1)
14-14: 일관성을 위해 HttpStatus 사용을 권장합니다.하드코딩된 400 대신
HttpStatus.BAD_REQUEST.value()를 사용하여 DepthLimitTwoException과 일관성을 유지하는 것이 좋겠습니다.- return 400; // Bad Request + return HttpStatus.BAD_REQUEST.value();HttpStatus import도 추가해야 합니다:
import org.juniortown.backend.exception.CustomException; +import org.springframework.http.HttpStatus;backend/src/main/java/org/juniortown/backend/post/service/PostService.java (1)
145-147: 댓글 조회 및 트리 구조 변환 로직이 올바르게 구현됨댓글을 생성 시간 순으로 조회하고
CommentTreeBuilder를 통해 계층 구조로 변환하는 로직이 적절합니다. 게시글 상세 조회에 댓글 기능이 잘 통합되었습니다.향후 댓글 수가 많은 게시글의 성능을 고려하여 댓글 페이징이나 지연 로딩을 검토해볼 수 있습니다.
backend/src/test/java/org/juniortown/backend/comment/entity/CommentTest.java (1)
13-14: 테스트 메서드명과 DisplayName이 일치하지 않음테스트 메서드명은
softDelete_setsDeletedAt인데@DisplayName은 "Comment 생성 시 기본 값 설정 확인"으로 되어있습니다. 실제로는 소프트 삭제 기능을 테스트하고 있으므로 DisplayName을 수정해야 합니다.-@DisplayName("Comment 생성 시 기본 값 설정 확인") +@DisplayName("Comment 소프트 삭제 시 deletedAt 설정 확인")backend/src/main/java/org/juniortown/backend/dummyData/DummyDataInit.java (2)
34-35: 더 구체적인 예외 타입 사용 권장일반적인 RuntimeException 대신 더 구체적인 예외 타입을 사용하는 것이 좋습니다.
User user = userRepository.findByEmail(signUpDTO.getEmail()) - .orElseThrow(() -> new RuntimeException("User not found")); + .orElseThrow(() -> new IllegalStateException("생성된 사용자를 찾을 수 없습니다"));
23-51: 트랜잭션 안전성 고려더미 데이터 생성 시 트랜잭션 처리를 고려해보세요.
클래스에
@Transactional어노테이션을 추가하거나, 메서드별로 트랜잭션을 적용할 수 있습니다:+@Transactional @Override public void run(String... args) throws Exception {backend/src/main/java/org/juniortown/backend/comment/dto/request/CommentCreateRequest.java (1)
7-7: 사용하지 않는 import를 제거하세요.
RequiredArgsConstructor가 import되었지만 사용되지 않습니다.-import lombok.RequiredArgsConstructor;backend/src/test/java/org/juniortown/backend/util/TestDataUtil.java (1)
20-20: 매개변수 사이 공백 추가 필요Java 코딩 컨벤션에 따라 매개변수 사이의 쉼표 뒤에 공백을 추가해야 합니다.
-public static Post createPost(Long id,String title,String content, User user) { +public static Post createPost(Long id, String title, String content, User user) {-public static User createUser(Long id, String name,String email) { +public static User createUser(Long id, String name, String email) {Also applies to: 29-29
backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.java (1)
42-43: 인라인 한글 주석 제거 또는 영문 변환 필요코드 내 한글 주석은 팀원 간 협업 시 가독성을 저하시킬 수 있습니다. 정식 문서화가 필요하다면 JavaDoc으로, 그렇지 않다면 제거하는 것이 좋겠습니다.
특히 42-43번 줄의 주석은
userId필드의 필요성에 대한 의문을 제기하고 있는데, 이는 코드 리뷰나 팀 논의를 통해 결정되어야 할 사항입니다.-// 근데 이게 꼭 필요한가? userId 쓰는 경우가 생각이 안나 .userId(comment.getUser().getId()) .parentId(comment.getParent() != null ? comment.getParent().getId() : null) .content(comment.getContent()) -// 이게 원래는 user 테이블을 조회해야하는데 comment에 username이 있으니까 -// 조회를 안해도 되는 사기 스킬 .username(comment.getUsername())Also applies to: 46-48
frontend/src/pages/posts/CommentPage.jsx (1)
19-19: JWT 토큰 관리 개선 필요localStorage에서 직접 JWT를 가져오는 현재 방식은 여러 문제가 있습니다:
- XSS 공격에 취약
- 토큰 만료 체크 없음
- 중앙화된 인증 관리 부재
인증 관련 로직을 별도의 서비스나 커스텀 훅으로 분리하는 것을 고려해보세요:
// useAuth.js export const useAuth = () => { const getAuthHeader = () => { const token = localStorage.getItem('jwt'); // 토큰 유효성 검사 로직 추가 return token ? { Authorization: token } : {}; }; return { getAuthHeader }; };Also applies to: 37-37, 55-55, 70-70
backend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.java (1)
408-410: 댓글 정렬 순서 검증 필요
findByPostIdOrderByCreatedAtAsc메서드를 사용하지만, 실제로 댓글이 생성 시간 순으로 정렬되었는지 검증하지 않습니다.댓글 순서를 명시적으로 검증하는 것이 좋겠습니다:
// 댓글이 생성 시간 순으로 정렬되었는지 확인 for (int i = 1; i < comments.size(); i++) { assertTrue(comments.get(i-1).getCreatedAt() .isBefore(comments.get(i).getCreatedAt()) || comments.get(i-1).getCreatedAt() .isEqual(comments.get(i).getCreatedAt())); }backend/src/main/java/org/juniortown/backend/comment/entity/Comment.java (1)
23-23: 사용하지 않는 import 제거
OneToOne어노테이션이 import되었지만 실제로 사용되지 않습니다.-import jakarta.persistence.OneToOne;backend/src/test/java/org/juniortown/backend/comment/service/CommentServiceTest.java (1)
159-161: 불필요한 주석 제거 필요"예외 터진거 확인은 어떻게 해?" 라는 주석은 제거해야 합니다. 이미
assertThatThrownBy로 예외를 검증하고 있습니다.// when, then verify(commentRepository, never()).save(any(Comment.class)); -// 예외 터진거 확인은 어떻게 해? Assertions.assertThatThrownBy(() -> commentService.createComment(USER_ID, commentCreateRequest))backend/src/main/java/org/juniortown/backend/comment/service/CommentService.java (1)
83-84: 변수명 오타 수정 필요
saveComment는savedComment로 수정하는 것이 일관성 있는 명명 규칙입니다.-Comment saveComment = commentRepository.save(comment); -return CommentCreateResponse.from(saveComment); +Comment savedComment = commentRepository.save(comment); +return CommentCreateResponse.from(savedComment);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
frontend/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (41)
backend/src/main/java/org/juniortown/backend/BackendApplication.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/controller/CommentController.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/dto/request/CommentCreateRequest.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/dto/request/CommentUpdateRequest.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentCreateResponse.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/entity/Comment.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/exception/AlreadyDeletedCommentException.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/exception/CommentNotFoundException.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/exception/DepthLimitTwoException.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/exception/NoRightForCommentDeleteException.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/exception/ParentPostMismatchException.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/repository/CommentRepository.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/service/CommentService.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/service/CommentTreeBuilder.java(1 hunks)backend/src/main/java/org/juniortown/backend/config/AuditingDateTimeProvider.java(1 hunks)backend/src/main/java/org/juniortown/backend/config/TimeConfig.java(1 hunks)backend/src/main/java/org/juniortown/backend/dummyData/DummyDataInit.java(1 hunks)backend/src/main/java/org/juniortown/backend/post/dto/request/PostCreateRequest.java(1 hunks)backend/src/main/java/org/juniortown/backend/post/dto/response/PostDetailResponse.java(3 hunks)backend/src/main/java/org/juniortown/backend/post/exception/PostNotFoundException.java(1 hunks)backend/src/main/java/org/juniortown/backend/post/repository/PostRepository.java(0 hunks)backend/src/main/java/org/juniortown/backend/post/service/PostService.java(4 hunks)backend/src/main/java/org/juniortown/backend/user/exception/UserNotFoundException.java(1 hunks)backend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java(1 hunks)backend/src/test/java/org/juniortown/backend/comment/entity/CommentTest.java(1 hunks)backend/src/test/java/org/juniortown/backend/comment/service/CommentServiceTest.java(1 hunks)backend/src/test/java/org/juniortown/backend/comment/service/CommentTreeBuilderTest.java(1 hunks)backend/src/test/java/org/juniortown/backend/config/TestClockConfig.java(1 hunks)backend/src/test/java/org/juniortown/backend/config/TestClockNotMockConfig.java(1 hunks)backend/src/test/java/org/juniortown/backend/controller/AuthControllerTest.java(2 hunks)backend/src/test/java/org/juniortown/backend/controller/PostControllerPagingTest.java(4 hunks)backend/src/test/java/org/juniortown/backend/controller/PostControllerTest.java(2 hunks)backend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.java(7 hunks)backend/src/test/java/org/juniortown/backend/like/controller/LikeControllerTest.java(2 hunks)backend/src/test/java/org/juniortown/backend/post/entity/PostTest.java(2 hunks)backend/src/test/java/org/juniortown/backend/post/service/PostServiceTest.java(3 hunks)backend/src/test/java/org/juniortown/backend/util/TestDataUtil.java(1 hunks)frontend/package.json(1 hunks)frontend/src/pages/posts/CommentPage.jsx(1 hunks)frontend/src/pages/posts/PostDetailPage.jsx(3 hunks)
💤 Files with no reviewable changes (1)
- backend/src/main/java/org/juniortown/backend/post/repository/PostRepository.java
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 이 프로젝트에서는 jpa 인터페이스 기반 프로젝션(postwithlikecountprojection)을 사용하여 데이터를 조회하므로, 클래스 기반 dto(postwithlikeco...
Learnt from: Doncham
PR: Doncham/JuniorTown#10
File: backend/src/main/java/org/juniortown/backend/post/dto/response/PostWithLikeCount.java:20-28
Timestamp: 2025-07-08T14:49:27.380Z
Learning: 이 프로젝트에서는 JPA 인터페이스 기반 프로젝션(PostWithLikeCountProjection)을 사용하여 데이터를 조회하므로, 클래스 기반 DTO(PostWithLikeCount)는 실제로 사용되지 않는다.
Applied to files:
backend/src/main/java/org/juniortown/backend/post/service/PostService.javabackend/src/test/java/org/juniortown/backend/controller/PostControllerTest.javabackend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.javabackend/src/test/java/org/juniortown/backend/post/entity/PostTest.javabackend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.javabackend/src/test/java/org/juniortown/backend/post/service/PostServiceTest.javabackend/src/test/java/org/juniortown/backend/controller/PostControllerPagingTest.java
📚 Learning: postresponse와 postdetailresponse 클래스에서 readcount 필드는 redis에서 실시간 조회수를 가져와 addreadcount() 메서드로 더해주는 로...
Learnt from: Doncham
PR: Doncham/JuniorTown#12
File: backend/src/main/java/org/juniortown/backend/post/dto/response/PostResponse.java:18-20
Timestamp: 2025-07-26T02:32:29.865Z
Learning: PostResponse와 PostDetailResponse 클래스에서 readCount 필드는 Redis에서 실시간 조회수를 가져와 addReadCount() 메서드로 더해주는 로직 때문에 가변 필드로 유지되어야 한다. 단순한 불변성 일관성보다는 실제 비즈니스 로직의 필요성을 우선 고려해야 한다.
Applied to files:
backend/src/main/java/org/juniortown/backend/post/service/PostService.javabackend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.javabackend/src/main/java/org/juniortown/backend/post/dto/response/PostDetailResponse.javabackend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.java
📚 Learning: postresponse.from() 메서드에 기본값을 설정하면 update 작업에서도 해당 메서드를 사용하기 때문에 likecount가 0으로 초기화되어 문제가 발생한다. 대신 u...
Learnt from: Doncham
PR: Doncham/JuniorTown#12
File: backend/src/main/java/org/juniortown/backend/post/dto/response/PostResponse.java:40-52
Timestamp: 2025-07-26T02:35:05.695Z
Learning: PostResponse.from() 메서드에 기본값을 설정하면 update 작업에서도 해당 메서드를 사용하기 때문에 likeCount가 0으로 초기화되어 문제가 발생한다. 대신 update 작업을 위한 별도의 응답 클래스를 만드는 것이 권장된다.
Applied to files:
backend/src/main/java/org/juniortown/backend/post/service/PostService.javabackend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.javabackend/src/main/java/org/juniortown/backend/post/dto/response/PostDetailResponse.javabackend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.javabackend/src/test/java/org/juniortown/backend/post/service/PostServiceTest.java
📚 Learning: spring boot 통합 테스트(@SpringBootTest)에서는 전체 애플리케이션 컨텍스트가 로드되므로, 특정 컨트롤러가 직접 사용하지 않는 의존성이라도 해당 의존성의 빈 생...
Learnt from: Doncham
PR: Doncham/JuniorTown#12
File: backend/src/test/java/org/juniortown/backend/controller/AuthControllerTest.java:7-8
Timestamp: 2025-07-26T12:44:23.618Z
Learning: Spring Boot 통합 테스트(@SpringBootTest)에서는 전체 애플리케이션 컨텍스트가 로드되므로, 특정 컨트롤러가 직접 사용하지 않는 의존성이라도 해당 의존성의 빈 생성 과정에서 외부 서비스(Redis, DB 등) 연결을 시도할 수 있다. 이런 경우 테스트용 mock 설정이 필요하다.
Applied to files:
backend/src/test/java/org/juniortown/backend/controller/PostControllerTest.javabackend/src/test/java/org/juniortown/backend/like/controller/LikeControllerTest.javabackend/src/main/java/org/juniortown/backend/dummyData/DummyDataInit.javabackend/src/test/java/org/juniortown/backend/controller/AuthControllerTest.javabackend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.javabackend/src/test/java/org/juniortown/backend/post/service/PostServiceTest.javabackend/src/test/java/org/juniortown/backend/controller/PostControllerPagingTest.javabackend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.javabackend/src/test/java/org/juniortown/backend/comment/service/CommentServiceTest.java
🔇 Additional comments (34)
frontend/package.json (1)
11-11: base-64 의존성 추가 검토 필요아래 사항을 확인·보완해주세요:
- 최신 브라우저에서는 내장 함수
btoa()/atob()를 사용할 수 있습니다. 외부 패키지 도입이 필요한지 재검토하세요.npm audit --package base-64 --json실행 시 lockfile 부재로 검사가 실패했습니다.
•npm i --package-lock-only등으로 lockfile 생성 후 재실행하거나
• Snyk·OSV·GitHub Advisory 등 공개 취약점 DB를 조회해 보세요.- 이 패키지를 댓글 기능에서 어떤 목적으로 사용하시는지 코드 내 주석이나 PR 설명에 명확히 기술해 주세요.
backend/src/main/java/org/juniortown/backend/BackendApplication.java (1)
10-10: JPA 감사 날짜/시간 제공자 설정이 적절합니다.
dateTimeProviderRef = "auditingDateTimeProvider"를 추가하여 커스텀 날짜/시간 제공자를 사용하도록 설정한 것이 좋습니다. 이는 다음과 같은 이점을 제공합니다:
- 일관된 시간 처리
- 테스트에서 시간 제어 가능
- 댓글 기능의 타임스탬프 관리 향상
backend/src/main/java/org/juniortown/backend/config/TimeConfig.java (1)
7-7: 테스트 프로필 제외 설정이 적절합니다.
@Profile("!test")애노테이션을 추가하여 테스트 환경에서 이 설정을 제외하는 것이 좋은 접근입니다. 이를 통해:
- 테스트용 Clock 빈이 별도로 설정될 수 있습니다
- 테스트에서 시간을 고정하여 결정적인 테스트가 가능합니다
- 댓글 기능의 타임스탬프 테스트가 일관되게 동작할 수 있습니다
Also applies to: 10-10
backend/src/test/java/org/juniortown/backend/like/controller/LikeControllerTest.java (1)
10-10: TestClockConfig 추가가 적절합니다.
TestClockConfig를@Import에 추가한 것이 좋습니다. 이는 다음과 같은 이점을 제공합니다:
- 테스트에서 일관된 시간 처리
- 시간 의존적인 기능의 결정적 테스트 가능
- 다른 테스트 클래스들과 일관된 설정 패턴 유지
이전에 학습한 내용에 따르면,
@SpringBootTest에서는 전체 애플리케이션 컨텍스트가 로드되므로 이러한 테스트용 설정이 필요합니다.Also applies to: 41-41
backend/src/main/java/org/juniortown/backend/post/exception/PostNotFoundException.java (1)
6-6: 일관된 예외 메시지 접근을 위한 변경 승인다른 예외 클래스들과 일관성을 위해 MESSAGE 상수를 public으로 변경한 것은 적절합니다. 다만 public static final 상수는 API의 일부가 되므로, 향후 메시지 내용을 변경할 때 하위 호환성을 고려해야 합니다.
backend/src/main/java/org/juniortown/backend/user/exception/UserNotFoundException.java (1)
7-7: 일관된 예외 메시지 접근을 위한 변경 승인PostNotFoundException과 동일한 패턴으로 MESSAGE 상수를 public으로 변경한 것은 좋습니다. 댓글 서비스에서 사용자 검증 시 일관된 메시지를 사용할 수 있게 됩니다.
backend/src/test/java/org/juniortown/backend/controller/PostControllerTest.java (1)
17-17: 테스트 시간 일관성을 위한 TestClockConfig 추가 승인TestClockConfig를 추가하여 시간 의존적인 테스트의 일관성을 보장하는 것은 좋은 개선입니다. @transactional 어노테이션으로 각 테스트 후 자동 롤백되므로 별도의 cleanup 메소드 없이도 깨끗한 테스트 환경을 유지할 수 있습니다.
Also applies to: 60-60
backend/src/test/java/org/juniortown/backend/post/entity/PostTest.java (2)
16-16: 테스트 설명의 정확성 개선 승인DisplayName을 "Post 삭제 시 기본 값 설정 확인"으로 변경하여 테스트가 실제로 수행하는 동작(softDelete)과 더 정확히 일치하도록 개선했습니다.
27-28: assertion 단순화 승인LocalDateTime.now(fixedClock)를 직접 비교하도록 단순화하여 테스트 코드의 가독성과 명확성이 향상되었습니다.
backend/src/main/java/org/juniortown/backend/comment/exception/NoRightForCommentDeleteException.java (1)
1-17: 권한 관련 예외 클래스 구현 승인댓글 삭제 권한 부족 시 사용할 예외 클래스가 잘 구현되었습니다. CustomException을 상속하고 HTTP 403 상태 코드를 반환하는 것이 적절하며, 다른 예외 클래스들과 일관된 패턴을 따르고 있습니다.
backend/src/main/java/org/juniortown/backend/comment/exception/CommentNotFoundException.java (1)
1-16: LGTM! 예외 클래스가 잘 구현되었습니다.댓글을 찾을 수 없을 때 적절한 HTTP 404 상태 코드를 반환하고, 한국어 오류 메시지가 명확합니다. CustomException을 상속받아 일관된 예외 처리 패턴을 따르고 있습니다.
backend/src/main/java/org/juniortown/backend/comment/exception/DepthLimitTwoException.java (1)
1-17: LGTM! HttpStatus 사용이 좋습니다.댓글 깊이 제한을 위한 예외 클래스가 잘 구현되었습니다. 하드코딩된 숫자 대신
HttpStatus.BAD_REQUEST.value()를 사용한 것이 좋은 실천 방법입니다. 한국어 오류 메시지도 명확하게 2단계 제한을 설명하고 있습니다.backend/src/main/java/org/juniortown/backend/comment/repository/CommentRepository.java (1)
1-10: LGTM! 저장소 인터페이스가 잘 설계되었습니다.Spring Data JPA 네이밍 컨벤션을 잘 따르고 있고,
findByPostIdOrderByCreatedAtAsc메서드명이 기능을 명확하게 표현합니다. 댓글을 생성 시간 순으로 정렬하여 가져오는 것이 댓글 트리 구조 생성에 적합합니다.frontend/src/pages/posts/PostDetailPage.jsx (1)
124-134: 댓글 기능 통합이 잘 되었습니다.CommentSection 컴포넌트가 적절한 props(postId, comments, myUserId, refreshPost)와 함께 잘 통합되었습니다. 백엔드 API와의 연동을 위한 필수 데이터들이 모두 전달되고 있습니다.
backend/src/test/java/org/juniortown/backend/config/TestClockNotMockConfig.java (1)
1-13: 실제 시스템 시간이 필요한 테스트를 위한 간단하고 명확한 설정실제 시스템 UTC 시계를 제공하는 테스트 설정이 올바르게 구현되었습니다.
TestClockConfig의 고정된 시계와 보완적으로 사용되어 실시간 동작이 필요한 테스트 시나리오를 지원합니다.backend/src/test/java/org/juniortown/backend/config/TestClockConfig.java (1)
1-19: 결정론적 테스트를 위한 고정 시계 설정이 올바르게 구현됨고정된 시간(
2025-06-20T10:15:30Z)을 제공하는 테스트 설정이 적절하게 구현되었습니다.@Primary어노테이션을 통해 테스트 환경에서 기본 시계 빈으로 동작하여 시간에 의존하는 테스트의 일관성을 보장합니다.backend/src/main/java/org/juniortown/backend/post/service/PostService.java (2)
9-12: 댓글 기능 통합을 위한 의존성 추가가 적절함댓글 기능을 게시글 상세 조회에 통합하기 위한 필요한 의존성들이 올바르게 추가되었습니다.
CommentRepository와CommentTreeBuilder를 통해 댓글 조회 및 트리 구조 변환을 지원합니다.
158-158: PostDetailResponse에 댓글 트리 추가가 적절함게시글 상세 응답에 댓글 트리가 올바르게 포함되어 프론트엔드에서 계층적 댓글 구조를 활용할 수 있습니다.
backend/src/test/java/org/juniortown/backend/comment/entity/CommentTest.java (1)
15-27: 소프트 삭제 테스트 로직이 올바르게 구현됨고정된 시계를 사용하여
softDelete메서드의 동작을 정확하게 검증하고 있습니다.deletedAt필드가 예상된 시간으로 설정되는지 확인하는 테스트가 적절합니다.backend/src/main/java/org/juniortown/backend/config/AuditingDateTimeProvider.java (1)
1-22: JPA 감사를 위한 날짜/시간 제공자가 올바르게 구현됨
DateTimeProvider인터페이스를 적절히 구현하여 JPA 감사 기능에 일관된 시간 관리를 제공합니다.Clock의존성 주입을 통해 테스트와 프로덕션 환경에서 시간 제어가 가능하며, 컴포넌트명"auditingDateTimeProvider"가@EnableJpaAuditing설정과 정확히 일치합니다.backend/src/main/java/org/juniortown/backend/comment/exception/AlreadyDeletedCommentException.java (1)
6-17: 예외 클래스 구현이 적절함소프트 삭제된 댓글에 대한 404 상태 코드 반환이 의미적으로 올바르며, CustomException 패턴을 일관성 있게 따르고 있습니다.
backend/src/test/java/org/juniortown/backend/controller/AuthControllerTest.java (1)
36-37: 테스트 설정 개선TestClockConfig 추가와 @transactional 어노테이션으로 테스트 격리성과 시간 일관성이 향상되었습니다.
backend/src/main/java/org/juniortown/backend/comment/dto/request/CommentUpdateRequest.java (1)
1-15: 구현이 깔끔하고 적절합니다.댓글 수정을 위한 DTO 클래스가 올바르게 구현되었습니다. Jakarta validation과 Lombok을 적절히 활용했고, 단일 책임 원칙을 잘 따르고 있습니다.
backend/src/main/java/org/juniortown/backend/comment/dto/request/CommentCreateRequest.java (1)
9-23: 댓글 생성 요청 DTO가 적절히 구현되었습니다.필수 필드에 대한 validation 설정이 올바르고, parentId가 선택적으로 설정되어 대댓글 기능을 지원하는 구조가 잘 설계되었습니다.
backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentCreateResponse.java (1)
10-40: 댓글 생성 응답 DTO가 적절히 구현되었습니다.필요한 모든 필드가 포함되어 있고, 정적 팩토리 메서드에서 부모 댓글에 대한 null 체크가 올바르게 처리되었습니다. 엔티티에서 DTO로의 매핑 로직이 깔끔합니다.
backend/src/test/java/org/juniortown/backend/comment/service/CommentTreeBuilderTest.java (1)
19-79: 댓글 트리 빌더 테스트가 포괄적으로 작성되었습니다.다양한 시나리오(빈 리스트, 부모 댓글만, 자식 댓글만, 혼합)에 대한 테스트 케이스가 적절히 구성되어 있고, 트리 구조 검증 로직이 정확합니다. 테스트 데이터 설정도 깔끔하게 처리되었습니다.
backend/src/test/java/org/juniortown/backend/post/service/PostServiceTest.java (2)
11-12: 댓글 저장소 의존성이 적절히 추가되었습니다.CommentRepository mock 추가로 게시글 상세 조회 시 댓글 기능 테스트가 가능해졌습니다.
Also applies to: 55-55
274-303: 댓글 트리 구조 테스트가 잘 구현되었습니다.계층형 댓글 구조(부모-자식 댓글)를 올바르게 생성하고, PostDetailResponse에서 댓글 트리가 정확히 반환되는지 검증하는 로직이 적절합니다. 댓글 개수와 내용까지 세밀하게 검증하고 있어 신뢰성이 높습니다.
backend/src/main/java/org/juniortown/backend/comment/entity/Comment.java (1)
55-57: 임시 주석 제거 및 replies 필드 완성도 검토
- backend/src/main/java/org/juniortown/backend/comment/entity/Comment.java (55–57행)
•// 임시로 작성주석을 삭제해주세요.replies필드는 현재 코드 어디에서도 호출(getter)되거나 서비스 로직에서 사용되지 않습니다.
• 실제 비즈니스 요구사항에 맞춰 getter/setter 또는 편의 메서드(addReply, removeReply 등)를 구현하고 사용처를 추가해야 합니다.@OneToMany(mappedBy = "parent")매핑 자체는 parent 쪽의@ManyToOne@JoinColumn(name = "parent_id")와 올바르게 대응되고 있으나,
양방향 연관관계를 제대로 활용하려면 컬렉션 변경 메서드도 함께 고려하시기 바랍니다.backend/src/test/java/org/juniortown/backend/controller/PostControllerPagingTest.java (2)
82-85: Redis 테스트 컨테이너 포트 설정 검토Redis 컨테이너를 6381 포트로 실행하도록 설정했는데, 특별한 이유가 있나요? 일반적으로 테스트 환경에서는 기본 포트(6379)를 사용하거나 랜덤 포트를 사용하는 것이 충돌을 방지하는데 도움이 됩니다.
133-142: 테스트 데이터 생성 위치 변경게시글 더미 데이터 생성을
@BeforeEach메서드 내부로 이동한 것은 적절합니다. 각 테스트마다 새로운 데이터를 생성하여 테스트 간 격리성을 보장합니다.backend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java (2)
78-81: 테스트 상수 정의 적절함테스트에서 사용되는 상수들을
static final로 정의한 것은 좋은 관행입니다. 가독성과 유지보수성을 높여줍니다.
342-376: 깊이 제한 테스트 구현 우수대댓글의 깊이를 2로 제한하는 비즈니스 로직을 테스트하는 것은 중요합니다. 할아버지-부모-자식 관계를 설정하여 깊이 제한을 검증하는 테스트가 잘 구현되었습니다.
backend/src/main/java/org/juniortown/backend/comment/service/CommentService.java (1)
65-68: 댓글 깊이 제한 로직 구현 우수대댓글의 깊이를 2로 제한하는 비즈니스 요구사항이 명확하게 구현되었습니다. 부모 댓글이 이미 대댓글인 경우를 체크하여 3단계 이상의 중첩을 방지합니다.
backend/src/main/java/org/juniortown/backend/comment/controller/CommentController.java
Outdated
Show resolved
Hide resolved
backend/src/main/java/org/juniortown/backend/comment/controller/CommentController.java
Outdated
Show resolved
Hide resolved
backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.java
Outdated
Show resolved
Hide resolved
| @ManyToOne | ||
| @JoinColumn(name = "parent_id") | ||
| private Comment parent; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
순환 참조 가능성 검증 부재
댓글이 자기 자신을 부모로 가지거나 순환 참조가 발생할 수 있는 검증 로직이 없습니다.
서비스 레이어에서 부모 댓글 설정 시 다음과 같은 검증이 필요합니다:
- 자기 자신을 부모로 설정하지 못하도록 검증
- 순환 참조 체크 (A→B→C→A)
- 최대 깊이 제한 확인 (PR 설명에 따르면 1단계까지만 허용)
public void validateParent(Comment parent) {
if (parent != null) {
if (parent.getId().equals(this.getId())) {
throw new InvalidCommentHierarchyException("댓글은 자기 자신을 부모로 가질 수 없습니다.");
}
if (parent.getParent() != null) {
throw new InvalidCommentHierarchyException("대댓글에는 답글을 달 수 없습니다.");
}
}
}🤖 Prompt for AI Agents
In backend/src/main/java/org/juniortown/backend/comment/entity/Comment.java
around lines 37 to 39, add validation logic in the service layer when setting a
parent comment to prevent self-parenting, cyclic references, and enforce the
maximum depth of one level. Implement checks to ensure the parent is not the
comment itself, that the parent does not already have a parent (to avoid deeper
nesting), and throw appropriate exceptions if these conditions are violated.
There was a problem hiding this comment.
오 이부분을 검증하는 걸 생각 못했네 좀 찝찝했는데 잘 찝어줬네 라임 죽인다
There was a problem hiding this comment.
@Doncham 감사합니다! 🎯
댓글 시스템에서 순환 참조나 무한 깊이 문제는 나중에 발견하기 어려운 버그가 될 수 있어서 미리 잡아내는 것이 중요합니다. 특히 이번 PR에서 1단계 깊이만 허용한다고 하셨으니, 서비스 레이어에서 이런 검증 로직을 추가하시면 더 안전한 댓글 시스템이 될 것 같습니다.
코드 리뷰가 도움이 되었다니 기쁩니다! 😊
backend/src/main/java/org/juniortown/backend/comment/entity/Comment.java
Outdated
Show resolved
Hide resolved
backend/src/test/java/org/juniortown/backend/util/TestDataUtil.java
Outdated
Show resolved
Hide resolved
| <div style={{ whiteSpace: 'pre-wrap', color: comment.deletedAt ? '#adb5bd' : undefined }}> | ||
| {comment.deletedAt ? '삭제된 댓글입니다.' : comment.content} |
There was a problem hiding this comment.
XSS 공격 방지를 위한 콘텐츠 검증 필요
사용자 입력 댓글을 직접 렌더링하고 있어 XSS 공격에 취약할 수 있습니다. whiteSpace: 'pre-wrap'을 사용하는 경우 특히 주의가 필요합니다.
React는 기본적으로 텍스트를 이스케이프하지만, 추가적인 보안 조치를 고려해보세요:
- DOMPurify 같은 라이브러리 사용
- 서버 측에서도 입력 검증 수행
- Content Security Policy (CSP) 헤더 설정
🤖 Prompt for AI Agents
In frontend/src/pages/posts/CommentPage.jsx around lines 161 to 162, the comment
content is rendered directly, which risks XSS attacks especially with
whiteSpace: 'pre-wrap'. To fix this, sanitize the comment content before
rendering using a library like DOMPurify to clean any malicious scripts. Also
ensure server-side validation of inputs and consider setting appropriate Content
Security Policy headers for additional protection.
메서드명 통합, 불필요한 주석 제거, 예외 생성, 테스트 수정, 테스트에서 인덱스 하드 코딩하던거 상수로 처리
프론트 로깅 추가
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
backend/src/test/java/org/juniortown/backend/comment/service/CommentServiceTest.java (1)
270-294: 테스트 로직 오류 - 잘못된 예외 검증부모 댓글이 존재하지 않는 경우를 테스트하는데
CircularReferenceException을 기대하고 있습니다. 부모 댓글이 존재하지 않으면CommentNotFoundException이 발생해야 합니다.다음과 같이 수정하세요:
// when, then Assertions.assertThatThrownBy(() -> commentService.createComment(USER_ID, commentCreateRequest)) - .isInstanceOf(CircularReferenceException.class) - .hasMessage(CircularReferenceException.MESSAGE); + .isInstanceOf(CommentNotFoundException.class) + .hasMessage(CommentNotFoundException.MESSAGE);
🧹 Nitpick comments (1)
backend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java (1)
111-118: 중복된 저장 작업 제거가 필요합니다.Line 118에서 이미 저장된
post를 다시 저장하고 있습니다.다음과 같이 수정하세요:
// 게시글을 하나 생성한다. post = postRepository.save( Post.builder() .title("테스트 게시글") .content("테스트 내용입니다.") .user(testUser) .build() ); -postRepository.save(post);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
backend/src/main/java/org/juniortown/backend/comment/controller/CommentController.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/entity/Comment.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/exception/CircularReferenceException.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/exception/NoRightForCommentUpdateException.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/service/CommentService.java(1 hunks)backend/src/main/java/org/juniortown/backend/comment/service/CommentTreeBuilder.java(1 hunks)backend/src/main/java/org/juniortown/backend/dummyData/DummyDataInit.java(1 hunks)backend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java(1 hunks)backend/src/test/java/org/juniortown/backend/comment/service/CommentServiceTest.java(1 hunks)backend/src/test/java/org/juniortown/backend/comment/service/CommentTreeBuilderTest.java(1 hunks)backend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.java(7 hunks)backend/src/test/java/org/juniortown/backend/post/service/PostServiceTest.java(3 hunks)backend/src/test/java/org/juniortown/backend/util/TestDataUtil.java(1 hunks)frontend/src/pages/posts/CommentPage.jsx(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- backend/src/main/java/org/juniortown/backend/comment/exception/CircularReferenceException.java
🚧 Files skipped from review as they are similar to previous changes (10)
- backend/src/main/java/org/juniortown/backend/comment/service/CommentTreeBuilder.java
- backend/src/test/java/org/juniortown/backend/post/service/PostServiceTest.java
- backend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.java
- backend/src/test/java/org/juniortown/backend/util/TestDataUtil.java
- backend/src/main/java/org/juniortown/backend/dummyData/DummyDataInit.java
- backend/src/test/java/org/juniortown/backend/comment/service/CommentTreeBuilderTest.java
- backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.java
- backend/src/main/java/org/juniortown/backend/comment/controller/CommentController.java
- frontend/src/pages/posts/CommentPage.jsx
- backend/src/main/java/org/juniortown/backend/comment/entity/Comment.java
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: Doncham
PR: Doncham/JuniorTown#14
File: backend/src/main/java/org/juniortown/backend/comment/service/CommentTreeBuilder.java:12-29
Timestamp: 2025-08-05T08:28:46.091Z
Learning: CommentTreeBuilder에서는 댓글이 createdAt 기준 오름차순으로 정렬되어 있다는 가정하에 단일 루프로 트리를 구성한다. 이는 부모 댓글이 항상 자식 댓글보다 먼저 생성되기 때문에 가능한 최적화이다.
📚 Learning: commentcontroller 클래스에서 commentdeleterequest와 commentupdaterequest 메서드명이 java 명명 규칙에 맞지 않아 deletecom...
Learnt from: Doncham
PR: Doncham/JuniorTown#14
File: backend/src/main/java/org/juniortown/backend/comment/controller/CommentController.java:45-50
Timestamp: 2025-08-05T06:50:30.697Z
Learning: CommentController 클래스에서 CommentDeleteRequest와 CommentUpdateRequest 메서드명이 Java 명명 규칙에 맞지 않아 deleteComment와 updateComment로 변경이 필요하다.
Applied to files:
backend/src/test/java/org/juniortown/backend/comment/service/CommentServiceTest.javabackend/src/main/java/org/juniortown/backend/comment/exception/NoRightForCommentUpdateException.javabackend/src/main/java/org/juniortown/backend/comment/service/CommentService.javabackend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java
📚 Learning: 사용자 doncham은 spring security와 인증 처리에 대해 별도로 공부하는 것을 선호하며, 당장 구현보다는 학습을 통해 제대로 이해한 후 적용하는 접근 방식을 취한다....
Learnt from: Doncham
PR: Doncham/JuniorTown#10
File: backend/src/main/java/org/juniortown/backend/post/controller/PostController.java:58-65
Timestamp: 2025-07-08T15:09:35.134Z
Learning: 사용자 Doncham은 Spring Security와 인증 처리에 대해 별도로 공부하는 것을 선호하며, 당장 구현보다는 학습을 통해 제대로 이해한 후 적용하는 접근 방식을 취한다.
Applied to files:
backend/src/test/java/org/juniortown/backend/comment/service/CommentServiceTest.javabackend/src/main/java/org/juniortown/backend/comment/service/CommentService.java
📚 Learning: spring boot 통합 테스트(@SpringBootTest)에서는 전체 애플리케이션 컨텍스트가 로드되므로, 특정 컨트롤러가 직접 사용하지 않는 의존성이라도 해당 의존성의 빈 생...
Learnt from: Doncham
PR: Doncham/JuniorTown#12
File: backend/src/test/java/org/juniortown/backend/controller/AuthControllerTest.java:7-8
Timestamp: 2025-07-26T12:44:23.618Z
Learning: Spring Boot 통합 테스트(@SpringBootTest)에서는 전체 애플리케이션 컨텍스트가 로드되므로, 특정 컨트롤러가 직접 사용하지 않는 의존성이라도 해당 의존성의 빈 생성 과정에서 외부 서비스(Redis, DB 등) 연결을 시도할 수 있다. 이런 경우 테스트용 mock 설정이 필요하다.
Applied to files:
backend/src/test/java/org/juniortown/backend/comment/service/CommentServiceTest.javabackend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java
📚 Learning: commenttreebuilder에서는 댓글이 createdat 기준 오름차순으로 정렬되어 있다는 가정하에 단일 루프로 트리를 구성한다. 이는 부모 댓글이 항상 자식 댓글보다 먼저...
Learnt from: Doncham
PR: Doncham/JuniorTown#14
File: backend/src/main/java/org/juniortown/backend/comment/service/CommentTreeBuilder.java:12-29
Timestamp: 2025-08-05T08:28:46.091Z
Learning: CommentTreeBuilder에서는 댓글이 createdAt 기준 오름차순으로 정렬되어 있다는 가정하에 단일 루프로 트리를 구성한다. 이는 부모 댓글이 항상 자식 댓글보다 먼저 생성되기 때문에 가능한 최적화이다.
Applied to files:
backend/src/main/java/org/juniortown/backend/comment/service/CommentService.java
🧬 Code Graph Analysis (2)
backend/src/main/java/org/juniortown/backend/comment/exception/NoRightForCommentUpdateException.java (3)
backend/src/main/java/org/juniortown/backend/post/exception/PostUpdatePermissionDeniedException.java (3)
PostUpdatePermissionDeniedException(6-17)getStatusCode(13-16)PostUpdatePermissionDeniedException(9-11)backend/src/main/java/org/juniortown/backend/post/exception/PostDeletePermissionDeniedException.java (1)
PostDeletePermissionDeniedException(6-18)backend/src/main/java/org/juniortown/backend/exception/Unauthorized.java (1)
Unauthorized(3-14)
backend/src/main/java/org/juniortown/backend/comment/service/CommentService.java (9)
backend/src/main/java/org/juniortown/backend/comment/exception/AlreadyDeletedCommentException.java (1)
AlreadyDeletedCommentException(6-17)backend/src/main/java/org/juniortown/backend/comment/exception/CircularReferenceException.java (1)
CircularReferenceException(6-16)backend/src/main/java/org/juniortown/backend/comment/exception/CommentNotFoundException.java (1)
CommentNotFoundException(5-16)backend/src/main/java/org/juniortown/backend/comment/exception/DepthLimitTwoException.java (1)
DepthLimitTwoException(6-17)backend/src/main/java/org/juniortown/backend/comment/exception/NoRightForCommentDeleteException.java (1)
NoRightForCommentDeleteException(6-17)backend/src/main/java/org/juniortown/backend/comment/exception/NoRightForCommentUpdateException.java (1)
NoRightForCommentUpdateException(6-17)backend/src/main/java/org/juniortown/backend/comment/exception/ParentPostMismatchException.java (1)
ParentPostMismatchException(5-16)backend/src/main/java/org/juniortown/backend/post/exception/PostNotFoundException.java (1)
PostNotFoundException(5-15)backend/src/main/java/org/juniortown/backend/user/exception/UserNotFoundException.java (1)
UserNotFoundException(6-15)
🔇 Additional comments (7)
backend/src/main/java/org/juniortown/backend/comment/exception/NoRightForCommentUpdateException.java (1)
6-17: LGTM! 예외 클래스 구현이 일관성 있게 잘 되어 있습니다.다른 권한 관련 예외 클래스들과 동일한 패턴을 따르고 있으며, 403 Forbidden 상태 코드와 한국어 메시지가 적절합니다.
backend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java (1)
52-571: 포괄적인 테스트 커버리지가 훌륭합니다.댓글 생성, 수정, 삭제의 성공 케이스와 다양한 실패 시나리오들을 잘 다루고 있습니다. 특히 권한 검증, 유효성 검사, 비즈니스 규칙 검증이 철저합니다.
backend/src/test/java/org/juniortown/backend/comment/service/CommentServiceTest.java (1)
37-475: 포괄적인 단위 테스트 구성이 훌륭합니다.모든 서비스 메서드의 성공/실패 시나리오를 철저히 테스트하고 있으며, Mock 객체 사용과 검증이 적절합니다.
backend/src/main/java/org/juniortown/backend/comment/service/CommentService.java (4)
39-90: 댓글 생성 로직이 비즈니스 요구사항을 잘 구현했습니다.사용자/게시글 검증, 부모 댓글 유효성 검사, 깊이 제한(2단계), 순환 참조 방지 등 모든 비즈니스 규칙이 적절히 구현되어 있습니다. 로깅도 디버깅에 유용하게 구성되어 있습니다.
132-140: 순환 참조 검증 로직이 효율적입니다.부모 댓글 체인을 따라가면서 순환 참조를 확인하는 로직이 간단하고 효과적입니다. 2단계 깊이 제한과 함께 안전한 댓글 구조를 보장합니다.
92-110: 댓글 삭제 로직이 안전하게 구현되었습니다.사용자 권한 검증과 소프트 삭제 방식이 적절하며, 적절한 예외 처리와 로깅이 포함되어 있습니다.
112-131: 댓글 수정 로직이 일관성 있게 구현되었습니다.권한 검증, 업데이트 로직, 순환 참조 재검증이 모두 포함되어 있어 안전한 수정 기능을 제공합니다.
| Comment comment = Comment.builder() | ||
| .content("테스트 댓글") | ||
| .post(post) | ||
| .user(ownerUser) | ||
| .username(testUser.getName()) | ||
| .build(); |
There was a problem hiding this comment.
댓글 생성 시 사용자 설정 오류
댓글을 ownerUser로 생성하면서 username을 testUser.getName()으로 설정하고 있습니다. 일관성을 위해 ownerUser.getName()을 사용해야 합니다.
다음과 같이 수정하세요:
Comment comment = Comment.builder()
.content("테스트 댓글")
.post(post)
.user(ownerUser)
- .username(testUser.getName())
+ .username(ownerUser.getName())
.build();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Comment comment = Comment.builder() | |
| .content("테스트 댓글") | |
| .post(post) | |
| .user(ownerUser) | |
| .username(testUser.getName()) | |
| .build(); | |
| Comment comment = Comment.builder() | |
| .content("테스트 댓글") | |
| .post(post) | |
| .user(ownerUser) | |
| .username(ownerUser.getName()) | |
| .build(); |
🤖 Prompt for AI Agents
In
backend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java
around lines 549 to 554, the Comment object is created with user set to
ownerUser but username set to testUser.getName(), causing inconsistency. Fix
this by changing the username assignment to ownerUser.getName() to match the
user field.
댓글/대댓글 CRUD API와 화면 만들기
대댓글은 1-depth까지만 허용
closed #13
Summary by CodeRabbit
신규 기능
버그 수정
테스트
문서화/스타일
환경설정/기타