Skip to content

Feat#13 댓글/대댓글기능#14

Merged
Doncham merged 11 commits intomainfrom
feat#13-댓글/대댓글기능
Aug 5, 2025

Hidden character warning

The head ref may contain hidden characters: "feat#13-\ub313\uae00/\ub300\ub313\uae00\uae30\ub2a5"
Merged

Feat#13 댓글/대댓글기능#14
Doncham merged 11 commits intomainfrom
feat#13-댓글/대댓글기능

Conversation

@Doncham
Copy link
Owner

@Doncham Doncham commented Aug 5, 2025

댓글/대댓글 CRUD API와 화면 만들기
대댓글은 1-depth까지만 허용
closed #13

Summary by CodeRabbit

  • 신규 기능

    • 게시글에 댓글 기능이 추가되었습니다. 댓글 작성, 수정, 삭제, 답글(대댓글) 작성이 가능합니다.
    • 댓글은 트리 구조로 표시되며, 삭제된 댓글은 별도 표시됩니다.
    • 댓글 작성, 수정, 삭제 시 본인만 가능하며, 입력값 검증 및 권한 체크가 적용됩니다.
    • 게시글 상세 조회 시 댓글 트리 구조가 포함되어 표시됩니다.
    • 프론트엔드에 댓글 UI 컴포넌트가 추가되어 댓글 관리가 가능해졌습니다.
    • 댓글 관련 예외 처리 및 깊이 제한, 순환 참조 방지 기능이 포함되었습니다.
    • 더미 데이터 자동 생성 기능이 추가되어 개발 환경에서 테스트 데이터가 자동으로 생성됩니다.
  • 버그 수정

    • 댓글, 게시글, 사용자 관련 예외 메시지 및 상태 코드가 명확하게 처리됩니다.
  • 테스트

    • 댓글 기능 전반(생성, 수정, 삭제, 예외 상황 등)에 대한 단위 및 통합 테스트가 추가되었습니다.
    • 댓글 트리 빌더 유틸리티에 대한 테스트가 포함되었습니다.
    • 테스트 환경에서 일관된 시간 처리를 위한 Clock 설정이 도입되었습니다.
  • 문서화/스타일

    • 일부 테스트 및 코드의 주석, 네이밍, 불필요 코드가 정리되었습니다.
  • 환경설정/기타

    • 프론트엔드에 댓글 관련 라이브러리(base-64)가 추가되었습니다.

@Doncham Doncham self-assigned this Aug 5, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 5, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

백엔드에 댓글 기능이 새롭게 도입되어 댓글 엔티티, DTO, 예외, 서비스, 컨트롤러, 저장소, 트리 빌더 등이 추가되었습니다. 게시글 상세 응답에 댓글 트리가 포함되고, 프론트엔드에서는 댓글 UI 및 API 연동 컴포넌트가 도입되었습니다. 테스트 코드와 시간 관련 설정도 보강되었습니다.

Changes

Cohort / File(s) Change Summary
댓글 도메인 신규 도입
backend/src/main/java/org/juniortown/backend/comment/entity/Comment.java,
.../comment/dto/request/CommentCreateRequest.java,
.../comment/dto/request/CommentUpdateRequest.java,
.../comment/dto/response/CommentCreateResponse.java,
.../comment/dto/response/CommentsInPost.java,
.../comment/exception/AlreadyDeletedCommentException.java,
.../comment/exception/CommentNotFoundException.java,
.../comment/exception/DepthLimitTwoException.java,
.../comment/exception/NoRightForCommentDeleteException.java,
.../comment/exception/ParentPostMismatchException.java,
.../comment/exception/CircularReferenceException.java,
.../comment/exception/NoRightForCommentUpdateException.java,
.../comment/repository/CommentRepository.java,
.../comment/service/CommentService.java,
.../comment/service/CommentTreeBuilder.java,
.../comment/controller/CommentController.java
댓글 엔티티, 생성/수정/조회 DTO, 계층 트리 빌더, 서비스, 컨트롤러, 저장소, 댓글 관련 예외 클래스 등 전체 댓글 기능 신규 추가
게시글 상세 댓글 트리 통합
backend/src/main/java/org/juniortown/backend/post/dto/response/PostDetailResponse.java,
.../post/service/PostService.java
게시글 상세 응답에 댓글 트리 포함 및 서비스에서 댓글 트리 조회/구성 로직 추가
시간 및 감사(Auditing) 설정
backend/src/main/java/org/juniortown/backend/config/AuditingDateTimeProvider.java,
.../config/TimeConfig.java,
.../BackendApplication.java
JPA 감사용 시간 제공자 커스텀화, 테스트 프로필 분리, 감사 설정 변경
더미데이터 및 유틸리티
backend/src/main/java/org/juniortown/backend/dummyData/DummyDataInit.java,
.../util/TestDataUtil.java
테스트/개발용 더미 데이터 초기화 및 엔티티 생성 유틸리티 추가
테스트: 댓글 도메인
backend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java,
.../comment/entity/CommentTest.java,
.../comment/service/CommentServiceTest.java,
.../comment/service/CommentTreeBuilderTest.java
댓글 API, 엔티티, 서비스, 트리 빌더에 대한 단위 및 통합 테스트 신규 추가
테스트: 시간 설정
backend/src/test/java/org/juniortown/backend/config/TestClockConfig.java,
.../config/TestClockNotMockConfig.java
테스트용 Clock 빈 설정(고정/실시간) 신규 추가
테스트: 게시글, 인증, 좋아요
backend/src/test/java/org/juniortown/backend/controller/AuthControllerTest.java,
.../controller/PostControllerPagingTest.java,
.../controller/PostControllerTest.java,
.../controller/PostRedisReadControllerTest.java,
.../like/controller/LikeControllerTest.java,
.../post/entity/PostTest.java,
.../post/service/PostServiceTest.java
댓글 연동, 시간 설정, Redis 컨테이너 적용 등 테스트 환경 및 검증 강화
기타 사소한 코드 변경
backend/src/main/java/org/juniortown/backend/post/dto/request/PostCreateRequest.java,
.../post/exception/PostNotFoundException.java,
.../post/repository/PostRepository.java,
.../user/exception/UserNotFoundException.java
주석/가시성/불필요 import 등 사소한 코드 정리
프론트엔드: 댓글 UI 및 연동
frontend/package.json,
frontend/src/pages/posts/CommentPage.jsx,
frontend/src/pages/posts/PostDetailPage.jsx
댓글 컴포넌트 신규 도입, 게시글 상세에 댓글 UI 추가, base-64 패키지 의존성 추가

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)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
댓글/대댓글 CRUD API 구현 및 대댓글 1-depth 제한 (#13)
댓글/대댓글 화면 구현 (#13)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
시간 및 감사 설정 변경 (backend/src/main/java/org/juniortown/backend/config/AuditingDateTimeProvider.java, TimeConfig.java, BackendApplication.java) 감사 시간 제공자 커스텀 및 프로필 분리는 댓글 기능 구현과 직접 관련 없으나 테스트 및 운영 환경을 위한 인프라 개선으로 보임
더미 데이터 초기화 및 테스트 유틸리티 추가 (DummyDataInit.java, TestDataUtil.java) 댓글 기능과 직접 관련 없는 테스트 및 개발 편의성 향상 목적의 코드
Redis 컨테이너 적용 및 테스트 환경 설정 변경 (PostControllerPagingTest.java, AuthControllerTest.java, LikeControllerTest.java, PostControllerTest.java, PostRedisReadControllerTest.java) 댓글 기능과 직접 관련 없는 테스트 환경 개선 및 인프라 설정 변경

Possibly related PRs

  • Feat#13 댓글/대댓글기능 #14: 동일한 댓글 및 대댓글 기능 구현과 관련된 PR로, 컨트롤러, DTO, 엔티티, 서비스, 예외, 트리 빌더 등 코드 수준에서 직접적인 연관성이 있음.

Suggested labels

🌠 feat

Poem

🐇
댓글이 달리고, 트리가 자라
새싹처럼 대댓글이 가지를 뻗네
예외도 꼼꼼, 테스트도 빵빵
프론트엔드엔 댓글창이 활짝!
리뷰어도 토끼도 미소짓는
오늘은 댓글의 날, 코드를 만끽해요!
🥕✨

Note

⚡️ Unit Test Generation is now available in beta!

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


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f353107 and 2a36d56.

📒 Files selected for processing (1)
  • frontend/src/pages/posts/PostDetailPage.jsx (3 hunks)
✨ 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#13-댓글/대댓글기능

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

@github-actions github-actions bot left a comment

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: 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로 다음을 고려해보세요:

  1. @builder 패턴을 사용하고 있어 setter가 불필요할 수 있습니다
  2. Request DTO는 일반적으로 불변객체로 설계하는 것이 좋습니다
  3. 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: 변수명 오타 수정 필요

saveCommentsavedComment로 수정하는 것이 일관성 있는 명명 규칙입니다.

-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

📥 Commits

Reviewing files that changed from the base of the PR and between ea3a65c and c081994.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is 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.java
  • backend/src/test/java/org/juniortown/backend/controller/PostControllerTest.java
  • backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.java
  • backend/src/test/java/org/juniortown/backend/post/entity/PostTest.java
  • backend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.java
  • backend/src/test/java/org/juniortown/backend/post/service/PostServiceTest.java
  • backend/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.java
  • backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.java
  • backend/src/main/java/org/juniortown/backend/post/dto/response/PostDetailResponse.java
  • backend/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.java
  • backend/src/main/java/org/juniortown/backend/comment/dto/response/CommentsInPost.java
  • backend/src/main/java/org/juniortown/backend/post/dto/response/PostDetailResponse.java
  • backend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.java
  • backend/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.java
  • backend/src/test/java/org/juniortown/backend/like/controller/LikeControllerTest.java
  • backend/src/main/java/org/juniortown/backend/dummyData/DummyDataInit.java
  • backend/src/test/java/org/juniortown/backend/controller/AuthControllerTest.java
  • backend/src/test/java/org/juniortown/backend/controller/PostRedisReadControllerTest.java
  • backend/src/test/java/org/juniortown/backend/post/service/PostServiceTest.java
  • backend/src/test/java/org/juniortown/backend/controller/PostControllerPagingTest.java
  • backend/src/test/java/org/juniortown/backend/comment/controller/CommentControllerTest.java
  • backend/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: 댓글 기능 통합을 위한 의존성 추가가 적절함

댓글 기능을 게시글 상세 조회에 통합하기 위한 필요한 의존성들이 올바르게 추가되었습니다. CommentRepositoryCommentTreeBuilder를 통해 댓글 조회 및 트리 구조 변환을 지원합니다.


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단계 이상의 중첩을 방지합니다.

Comment on lines +37 to +39
@ManyToOne
@JoinColumn(name = "parent_id")
private Comment parent;
Copy link

@coderabbitai coderabbitai bot Aug 5, 2025

Choose a reason for hiding this comment

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

🛠️ 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.

Copy link
Owner Author

Choose a reason for hiding this comment

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

오 이부분을 검증하는 걸 생각 못했네 좀 찝찝했는데 잘 찝어줬네 라임 죽인다

Copy link

Choose a reason for hiding this comment

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

@Doncham 감사합니다! 🎯

댓글 시스템에서 순환 참조나 무한 깊이 문제는 나중에 발견하기 어려운 버그가 될 수 있어서 미리 잡아내는 것이 중요합니다. 특히 이번 PR에서 1단계 깊이만 허용한다고 하셨으니, 서비스 레이어에서 이런 검증 로직을 추가하시면 더 안전한 댓글 시스템이 될 것 같습니다.

코드 리뷰가 도움이 되었다니 기쁩니다! 😊

Comment on lines +161 to +162
<div style={{ whiteSpace: 'pre-wrap', color: comment.deletedAt ? '#adb5bd' : undefined }}>
{comment.deletedAt ? '삭제된 댓글입니다.' : comment.content}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Doncham added 2 commits August 5, 2025 18:19
메서드명 통합, 불필요한 주석 제거, 예외 생성, 테스트 수정, 테스트에서 인덱스 하드 코딩하던거 상수로 처리
Copy link

@github-actions github-actions bot left a comment

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

📥 Commits

Reviewing files that changed from the base of the PR and between c081994 and f353107.

📒 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.java
  • backend/src/main/java/org/juniortown/backend/comment/exception/NoRightForCommentUpdateException.java
  • backend/src/main/java/org/juniortown/backend/comment/service/CommentService.java
  • backend/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.java
  • backend/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.java
  • backend/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 on lines +549 to +554
Comment comment = Comment.builder()
.content("테스트 댓글")
.post(post)
.user(ownerUser)
.username(testUser.getName())
.build();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

댓글 생성 시 사용자 설정 오류

댓글을 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.

Suggested change
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.

@Doncham Doncham merged commit 6507a3b into main Aug 5, 2025
1 of 2 checks passed
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

LGTM 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

댓글/대댓글 기능 + 화면

1 participant