Skip to content

[COMMUNITY] 커뮤니티 폼 데이터 처리 통일 및 코드리뷰 반영#44

Merged
usn757 merged 2 commits intoPETTY-HUB:mainfrom
LimPark996:main
May 31, 2025
Merged

[COMMUNITY] 커뮤니티 폼 데이터 처리 통일 및 코드리뷰 반영#44
usn757 merged 2 commits intoPETTY-HUB:mainfrom
LimPark996:main

Conversation

@LimPark996
Copy link
Contributor

🚀 게시글 폼 데이터 처리 통일 및 성능 최적화

📜 PR 내용 요약

이번 PR은 두 가지 주요 개선사항을 포함합니다:

  1. 프론트엔드: 게시글 작성/수정 폼의 데이터 처리 방식을 FormData로 통일하여 일관성 및 안정성 향상
  2. 백엔드: 게시글 카운트 업데이트 성능을 3000배 개선하는 쿼리 최적화

⚒️ 작업 및 변경 내용(상세하게)

🎯 프론트엔드 폼 데이터 처리 표준화

문제점

  • 게시글 작성/수정 폼에서 데이터 추출 방식이 파일마다 제각각
  • getElementById() vs querySelector() vs FormData 혼재 사용
  • name 속성 누락으로 인한 데이터 손실 위험
  • 에러 처리 일관성 부족

해결 방안

📁 HTML 파일 수정 (5개 파일)

<!-- Before: name 속성 누락 -->
<input type="radio" id="edit-qna-pet-dog" value="DOG">

<!-- After: name 속성 추가로 FormData 호환 -->
<input type="radio" id="edit-qna-pet-dog" name="petType" value="DOG">

  • post-qna-form.html: 모든 input에 name 속성 추가
  • post-review-form.html: FormData 호환성 개선
  • post-showoff-form.html: 필수 속성 통일
  • edit-qna.html: 수정 폼 표준화
  • edit-review.html: 일관된 name 속성 적용
  • edit-showoff.html: 통일된 폼 구조

📁 JavaScript 파일 리팩토링 (4개 파일)

Before (비일관적):

// 각기 다른 방식으로 데이터 추출
const title = document.getElementById("title").value;
const petType = getRadioValue("petType");
const content = document.querySelector("#content").value;

After (통일된 FormData 방식):

// 모든 파일에서 동일한 방식 사용
const formData = new FormData(form);
const title = formData.get('title')?.trim();
const petType = formData.get('petType');
const content = formData.get('content')?.trim();
  • form.js: 새 게시글 작성 FormData 표준화
  • edit-qna.js: QnA 수정 FormData 적용
  • edit-review.js: 리뷰 수정 FormData 적용
  • edit-showoff.js: 자랑글 수정 FormData 적용

개선된 에러 처리

// 향상된 사용자 친화적 알림 시스템
function showErrorMessage(message) {
  const alertDiv = document.createElement('div');
  alertDiv.className = 'alert alert-error';
  alertDiv.innerHTML = `
    <span class="alert-icon">⚠️</span>
    <span class="alert-message">${message}</span>
    <button class="alert-close" onclick="this.parentElement.remove()">×</button>
  `;
  document.body.insertBefore(alertDiv, document.body.firstChild);

// 5초 후 자동 제거
setTimeout(() => {
if (alertDiv.parentElement) alertDiv.remove();
}, 5000);
}

🚀 백엔드 성능 최적화

PostRepository.java

// 🆕 추가: 벌크 업데이트 JPQL 쿼리
@Query("""
UPDATE Post p 
SET p.commentCount = (SELECT COUNT(c) FROM Comment c WHERE c.post = p),
    p.likeCount = (SELECT COUNT(l) FROM PostLike l WHERE l.post = p)
""")
@Modifying
@Transactional
void updateAllPostCounts();

// 🆕 추가: 성능 향상을 위한 네이티브 쿼리 대안
@Query(value = """
UPDATE posts p
SET comment_count = (SELECT COUNT() FROM comments c WHERE c.post_id = p.id),
like_count = (SELECT COUNT(
) FROM post_likes l WHERE l.post_id = p.id)
""", nativeQuery = true)
@Modifying
@Transactional
void updateAllPostCountsNative();

PostServiceImpl.java

Before (N+1 쿼리 문제):

// ❌ 비효율적: 게시글 1000개 시 3001개 쿼리 실행
List<Post> allPosts = postRepository.findAll(); // 1개 쿼리
for (Post post : allPosts) { // N번 반복
    long commentCount = commentRepository.countByPostId(post.getId()); // N개 쿼리
    post.setCommentCount((int) commentCount);
    long likeCount = postLikeRepository.countByPost(post); // N개 쿼리
    post.setLikeCount((int) likeCount);
    postRepository.save(post); // N개 쿼리
}

After (최적화된 벌크 업데이트):

// ✅ 효율적: 게시글 수와 관계없이 1개 쿼리만 실행
@Override
public void updateAllPostCounts() {
    postRepository.updateAllPostCounts();
    System.out.println("✅ 모든 게시글의 댓글 수와 좋아요 수가 업데이트되었습니다.");
}

📊 성능 개선 효과

항목 기존 방식 개선된 방식 성능 향상
쿼리 수 1 + 3N개 1개 N=1000일 때 3000배 개선
메모리 사용량 모든 게시글 로드 최소 대용량 데이터 처리 가능
실행 시간 O(N) O(1) 게시글 수와 무관하게 일정
DB 부하 높음 최소 트랜잭션 부하 대폭 감소

📚 기타 참고 사항

프론트엔드 리뷰 포인트

  1. 데이터 일관성: 모든 폼에서 동일한 FormData 방식 사용 확인
  2. 에러 처리: 사용자 친화적 알림 시스템 동작 테스트
  3. 폼 검증: 필수 필드 validation 로직 검증
  4. 브라우저 호환성: FormData API 지원 범위 확인

백엔드 리뷰 포인트

  1. 쿼리 최적화: JPQL 서브쿼리가 올바르게 작동하는지 확인
  2. 트랜잭션 처리: @Transactional@Modifying 어노테이션 적절성 검토
  3. 인덱스 확인: post_id, comment.post_id, post_like.post_id 인덱스 존재 여부
  4. 동시성: 대용량 업데이트 시 테이블 락 발생 가능성 검토

@coderabbitai
Copy link

coderabbitai bot commented May 28, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Summary by CodeRabbit

  • 신규 기능

    • Q&A, 리뷰, 자랑하기 글 수정 및 등록 폼에 입력값 검증과 에러 메시지 표시 기능이 추가되어, 필수 입력값 누락 시 알림이 표시됩니다.
    • 에러 메시지는 5초 후 자동으로 사라지며, 각 입력란에 포커스가 이동합니다.
  • 버그 수정

    • 폼 입력 필드의 name 속성이 일관되게 적용되어, 폼 데이터 전송 및 처리의 오류 가능성이 줄어들었습니다.
    • petType 등 일부 입력값의 name 속성 불일치 문제를 해결하여 데이터 바인딩이 정확해졌습니다.
  • 개선 사항

    • 관리자만 게시글 집계 업데이트 기능을 사용할 수 있도록 접근 제어가 강화되었습니다.
    • 댓글 및 게시글 관련 로그와 예외 처리가 개선되어, 오류 진단이 용이해졌습니다.
    • 게시글 이미지 삭제와 순서 변경이 더 효율적으로 처리됩니다.
  • 문서 및 스타일

    • Q&A, 리뷰, 자랑하기, 작성 폼 등 템플릿의 입력 필드에 name 속성이 추가되어, 데이터 처리 일관성이 향상되었습니다.

Walkthrough

이 변경사항은 주로 폼 입력 필드의 name 속성 표준화, 클라이언트 측 입력 검증 및 오류 메시지 표시 개선, 서버 측 로깅 및 예외 처리 강화, 게시글 카운트 일괄 업데이트 기능의 효율화, 그리고 관련 저장소 및 서비스 계층의 리팩토링을 포함합니다. 주요 API 시그니처 일부가 관리자 권한 검증을 위해 수정되었습니다.

Changes

파일/경로 그룹 변경 요약
src/main/java/io/github/petty/community/controller/CommentController.java Lombok @Slf4j로 구조적 로깅 도입, System.out/err 제거, 예외 처리 및 로그 구분 강화, 변수 스코프 명확화
src/main/java/io/github/petty/community/controller/PostController.java updateAllPostCounts에 관리자 권한 검증 추가, 시그니처에 인증 사용자 파라미터 및 @PreAuthorize 적용
src/main/java/io/github/petty/community/dto/CommentRequest.java,
src/main/java/io/github/petty/community/dto/PostRequest.java
Size 어노테이션 import를 javax에서 jakarta로 변경
src/main/java/io/github/petty/community/repository/PostRepository.java 게시글의 댓글/좋아요 카운트 일괄 업데이트용 JPQL 및 네이티브 쿼리 메소드 2종 추가
src/main/java/io/github/petty/community/service/PostImageServiceImpl.java 이미지 삭제 및 순서 업데이트를 일괄 처리로 리팩토링, 중복 DB 조회 제거, 스트림 기반 Map 활용
src/main/java/io/github/petty/community/service/PostServiceImpl.java 게시글 카운트 업데이트를 반복문에서 저장소 일괄 업데이트 메소드 호출로 단순화
src/main/resources/static/js/common/edit-qna.js,
edit-review.js,
edit-showoff.js
폼 입력값 추출을 FormData로 통일, 필수 입력 검증 및 오류 메시지 alert 시스템 추가, name 속성 기반 처리로 정규화
src/main/resources/static/js/common/form.js FormData 기반 입력 추출 및 검증, 기존 DOM 접근 방식 제거
src/main/resources/templates/edit-qna.html,
edit-review.html,
edit-showoff.html,
post-qna-form.html,
post-review-form.html,
post-showoff-form.html
폼 input, textarea, file input 등에 name 속성 추가 또는 정규화, radio name 속성 통일

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend(JS)
    participant Server(Controller)
    participant Service
    participant Repository

    User->>Frontend(JS): 폼 입력 및 제출
    Frontend(JS)->>Frontend(JS): FormData로 입력값 추출 및 검증
    alt 필수값 누락
        Frontend(JS)-->>User: 오류 alert 표시 및 입력 focus
    else 검증 통과
        Frontend(JS)->>Server(Controller): 유효한 데이터 전송
        Server(Controller)->>Service: 요청 처리
        Service->>Repository: DB 작업(이미지 일괄 삭제/업데이트 등)
        Repository-->>Service: 결과 반환
        Service-->>Server(Controller): 처리 완료
        Server(Controller)-->>Frontend(JS): 응답 반환
        Frontend(JS)-->>User: 결과 반영
    end
Loading
sequenceDiagram
    participant Admin
    participant Server(PostController)
    participant Service
    participant Repository

    Admin->>Server(PostController): updateAllPostCounts() 요청
    Server(PostController)->>Server(PostController): 관리자 권한 검증
    alt 권한 없음
        Server(PostController)-->>Admin: 403 Forbidden 응답
    else 권한 있음
        Server(PostController)->>Service: updateAllPostCounts() 호출
        Service->>Repository: updateAllPostCounts() (JPQL/Native 일괄 쿼리)
        Repository-->>Service: 처리 완료
        Service-->>Server(PostController): 완료 알림
        Server(PostController)-->>Admin: 성공 응답
    end
Loading

Possibly related PRs

Poem

🐰
새 이름을 달고, 폼이 반짝
오류 알림이 뿅! 사용자도 깜짝
로그는 조용히, 예외는 똑똑히
관리자만이 버튼을 콕!
토끼는 오늘도 코드밭에서
깔끔한 입력을 꿈꾸며
귀를 쫑긋 세웠어요!


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.
    • @coderabbitai modularize this function.
  • 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.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

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

@LimPark996
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented May 28, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@LimPark996
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented May 28, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🧹 Nitpick comments (2)
src/main/java/io/github/petty/community/controller/PostController.java (1)

103-109: 중복 권한 검사 최적화 필요

@PreAuthorize("hasRole('ADMIN')")와 수동 권한 검사가 동시에 있어 중복됩니다. Spring Security의 어노테이션 기반 접근 제어가 이미 메서드 실행 전에 권한을 검증하므로, 수동 검사는 불필요합니다.

다음 diff를 적용하여 중복을 제거하세요:

 @PostMapping("/update-counts")
 @PreAuthorize("hasRole('ADMIN')")
-public ResponseEntity<?> updateAllPostCounts(@AuthenticationPrincipal CustomUserDetails userDetails) {
-        // 관리자 권한 확인
-        if (!userDetails.getAuthorities().stream()
-            .anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"))) {
-            return ResponseEntity.status(403).body("관리자 권한이 필요합니다.");
-            }
+public ResponseEntity<?> updateAllPostCounts() {
     postService.updateAllPostCounts();
     return ResponseEntity.ok(Map.of("message", "모든 게시글의 댓글 수와 좋아요 수가 업데이트되었습니다."));
 }
src/main/resources/static/js/common/edit-showoff.js (1)

40-67: 에러 메시지 표시 시스템이 잘 구현되었습니다.

사용자 친화적인 알림 시스템으로 UX가 크게 개선되었습니다. 자동 제거 기능과 기존 알림 정리 로직도 적절합니다.

다만 XSS 보안 취약점을 방지하기 위해 innerHTML 대신 안전한 방법을 사용하는 것을 권장합니다.

보안 강화를 위해 다음과 같이 수정을 권장합니다:

-  alertDiv.innerHTML = `
-    <span class="alert-icon">⚠️</span>
-    <span class="alert-message">${message}</span>
-    <button class="alert-close" onclick="this.parentElement.remove()">×</button>
-  `;
+  const iconSpan = document.createElement('span');
+  iconSpan.className = 'alert-icon';
+  iconSpan.textContent = '⚠️';
+  
+  const messageSpan = document.createElement('span');
+  messageSpan.className = 'alert-message';
+  messageSpan.textContent = message;
+  
+  const closeButton = document.createElement('button');
+  closeButton.className = 'alert-close';
+  closeButton.textContent = '×';
+  closeButton.onclick = () => alertDiv.remove();
+  
+  alertDiv.appendChild(iconSpan);
+  alertDiv.appendChild(messageSpan);
+  alertDiv.appendChild(closeButton);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8835392 and e618dcc.

📒 Files selected for processing (17)
  • src/main/java/io/github/petty/community/controller/CommentController.java (3 hunks)
  • src/main/java/io/github/petty/community/controller/PostController.java (2 hunks)
  • src/main/java/io/github/petty/community/dto/CommentRequest.java (1 hunks)
  • src/main/java/io/github/petty/community/dto/PostRequest.java (1 hunks)
  • src/main/java/io/github/petty/community/repository/PostRepository.java (2 hunks)
  • src/main/java/io/github/petty/community/service/PostImageServiceImpl.java (2 hunks)
  • src/main/java/io/github/petty/community/service/PostServiceImpl.java (1 hunks)
  • src/main/resources/static/js/common/edit-qna.js (3 hunks)
  • src/main/resources/static/js/common/edit-review.js (4 hunks)
  • src/main/resources/static/js/common/edit-showoff.js (3 hunks)
  • src/main/resources/static/js/common/form.js (1 hunks)
  • src/main/resources/templates/edit-qna.html (4 hunks)
  • src/main/resources/templates/edit-review.html (2 hunks)
  • src/main/resources/templates/edit-showoff.html (2 hunks)
  • src/main/resources/templates/post-qna-form.html (3 hunks)
  • src/main/resources/templates/post-review-form.html (2 hunks)
  • src/main/resources/templates/post-showoff-form.html (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/resources/static/js/common/edit-review.js (3)
src/main/resources/static/js/common/edit-qna.js (11)
  • formData (284-284)
  • form (88-88)
  • resolvedCheckbox (157-157)
  • resolvedCheckbox (221-221)
  • resolvedLabel (158-158)
  • resolvedLabel (222-222)
  • titleElement (209-209)
  • contentElement (210-210)
  • post (181-181)
  • post (207-207)
  • petTypeInputs (216-216)
src/main/resources/static/js/common/edit-showoff.js (7)
  • formData (260-260)
  • form (88-88)
  • titleElement (197-197)
  • contentElement (198-198)
  • post (170-170)
  • post (195-195)
  • petTypeInputs (204-204)
src/main/resources/static/js/common/form.js (9)
  • formData (116-116)
  • formData (189-189)
  • form (188-188)
  • title (192-192)
  • content (193-193)
  • petType (194-194)
  • petName (195-195)
  • region (196-196)
  • isResolved (197-197)
🔇 Additional comments (35)
src/main/java/io/github/petty/community/repository/PostRepository.java (3)

8-8: 필요한 어노테이션 임포트가 정확히 추가되었습니다.

@Modifying@Transactional 임포트가 새로운 벌크 업데이트 메서드들을 위해 적절히 추가되었습니다.

Also applies to: 12-12


27-34:

Details

✅ Verification successful

JPQL 벌크 업데이트 메서드가 올바르게 구현되었습니다.

N+1 쿼리 문제를 해결하는 효율적인 접근 방식입니다. 서브쿼리를 통해 각 게시글의 댓글 수와 좋아요 수를 한 번의 쿼리로 업데이트합니다.

다음 스크립트를 실행하여 관련 엔티티들의 관계 매핑이 올바른지 확인해주세요:


🏁 Script executed:

#!/bin/bash
# 설명: Comment와 PostLike 엔티티의 Post와의 관계 확인

# Comment 엔티티에서 post 필드 확인
ast-grep --pattern $'@Entity
class Comment {
  $$$
  @ManyToOne
  $$$
  Post post;
  $$$
}'

# PostLike 엔티티에서 post 필드 확인  
ast-grep --pattern $'@Entity
class PostLike {
  $$$
  @ManyToOne
  $$$
  Post post;
  $$$
}'

Length of output: 186


아래 스크립트를 실행하여 Comment.javaPostLike.java 엔티티 파일이 실제로 존재하는지, 그리고 @ManyToOne 어노테이션과 Post post 필드 매핑이 올바른지 재확인해 주세요.


🏁 Script executed:

#!/bin/bash
# 1. 엔티티 파일 경로 찾기
comment_file=$(fd -e java Comment.java || echo "")
postlike_file=$(fd -e java PostLike.java || echo "")

echo "=== Comment 엔티티 파일 ==="
echo "$comment_file"
if [[ -n "$comment_file" ]]; then
  grep -n "@Entity" -C2 "$comment_file"
  grep -n "@ManyToOne" -C2 "$comment_file"
  grep -n "Post post" -C1 "$comment_file"
fi

echo
echo "=== PostLike 엔티티 파일 ==="
echo "$postlike_file"
if [[ -n "$postlike_file" ]]; then
  grep -n "@Entity" -C2 "$postlike_file"
  grep -n "@ManyToOne" -C2 "$postlike_file"
  grep -n "Post post" -C1 "$postlike_file"
fi

Length of output: 2282


JPQL 벌크 업데이트 매핑 검증 완료

Comment 및 PostLike 엔티티에서 Post와의 관계 매핑(@ManyToOne(fetch = FetchType.LAZY), @JoinColumn(name = "post_id"))이 올바르게 설정되어 있어,
updateAllPostCounts() 메서드의 서브쿼리가 정상적으로 작동함을 확인했습니다.
별도 수정 없이 머지하셔도 됩니다.

  • src/main/java/io/github/petty/community/entity/Comment.java (22–24행)
  • src/main/java/io/github/petty/community/entity/PostLike.java (23–25행)

37-52:

Details

✅ Verification successful

네이티브 SQL 쿼리의 테이블/컬럼명 검증이 필요합니다.

네이티브 SQL을 사용한 성능 최적화 접근은 좋습니다만, 실제 데이터베이스 스키마와 일치하는지 확인이 필요합니다.

다음 스크립트를 실행하여 실제 테이블 및 컬럼명을 확인해주세요:


🏁 Script executed:

#!/bin/bash
# 설명: 엔티티 클래스에서 실제 테이블명과 컬럼명 확인

# Post 엔티티의 테이블명과 컬럼명 확인
ast-grep --pattern $'@Entity
$$$
@Table(name = "$_")
$$$
class Post {
  $$$
}'

# Comment 엔티티의 테이블명 확인
ast-grep --pattern $'@Entity
$$$
@Table(name = "$_")
$$$  
class Comment {
  $$$
}'

# PostLike 엔티티의 테이블명 확인
ast-grep --pattern $'@Entity
$$$
@Table(name = "$_")
$$$
class PostLike {
  $$$
}'

Length of output: 248


아직 엔티티 클래스와 @table(name=…) 어노테이션을 찾지 못했습니다. 실제 엔티티 정의를 확인하기 위해 아래 스크립트를 실행해 주세요.


🏁 Script executed:

#!/bin/bash
set -eu
echo "### @Entity가 선언된 파일 및 상위 200줄 출력 ###"
rg --files-with-matches '@Entity' -g "*.java" | while read -r file; do
  echo
  echo "=== $file ==="
  sed -n '1,200p' "$file"
done

Length of output: 25657


네이티브 SQL 테이블·컬럼명 검증 완료

  • src/main/java/io/github/petty/community/entity/Post.java
    @table(name="posts")
    • commentCount → comment_count, likeCount → like_count
  • src/main/java/io/github/petty/community/entity/Comment.java
    @table(name="comments")
    @joincolumn(name="post_id")
  • src/main/java/io/github/petty/community/entity/PostLike.java
    @table(name="post_likes")
    @joincolumn(name="post_id")

위 설정이 모두 네이티브 쿼리(posts, comments, post_likes, comment_count, like_count, post_id)와 일치하므로 추가 수정 없이 진행 가능합니다.

src/main/java/io/github/petty/community/dto/PostRequest.java (1)

9-9: Jakarta EE 네임스페이스로의 마이그레이션이 올바르게 수행되었습니다.

javax.validation에서 jakarta.validation으로의 변경은 최신 Spring Boot 버전과의 호환성을 위해 필요한 표준 마이그레이션입니다.

src/main/java/io/github/petty/community/dto/CommentRequest.java (1)

7-7: 일관된 Jakarta EE 마이그레이션입니다.

PostRequest.java와 일관되게 검증 어노테이션 임포트가 Jakarta 네임스페이스로 업데이트되었습니다.

src/main/resources/templates/post-showoff-form.html (4)

25-25: 제목 입력 필드에 name 속성이 올바르게 추가되었습니다.

name="title" 속성 추가로 FormData를 통한 일관된 폼 데이터 처리가 가능해졌습니다.


32-56: 반려동물 타입 라디오 버튼들의 name 속성이 표준화되었습니다.

기존 "showoff-petType"에서 "petType"으로 변경하여 다른 폼들과의 일관성을 확보했습니다. 모든 라디오 버튼이 동일한 name 속성을 가져 올바른 그룹화가 이루어졌습니다.


64-64: 내용 입력 영역에 name 속성이 적절히 추가되었습니다.

name="content" 속성으로 폼 데이터 추출 시 일관된 처리가 가능해졌습니다.


74-74: 이미지 파일 입력에 name 속성이 올바르게 설정되었습니다.

name="imageFiles" 속성 추가로 다중 파일 업로드 시 FormData를 통한 일관된 처리가 가능해졌습니다.

src/main/resources/templates/post-qna-form.html (3)

25-25: 폼 데이터 처리를 위한 name 속성 추가가 적절합니다.

제목 입력 필드에 name="title" 속성이 추가되어 FormData를 통한 일관된 데이터 추출이 가능해졌습니다.


64-64: 콘텐츠 필드의 name 속성 추가가 올바릅니다.

textarea 요소에 name="content" 속성이 추가되어 폼 제출 시 콘텐츠 데이터가 올바르게 식별됩니다.


74-74: 이미지 파일 입력의 name 속성이 적절히 설정되었습니다.

파일 입력 요소에 name="imageFiles" 속성이 추가되어 다중 파일 업로드 시 데이터 처리가 표준화됩니다.

src/main/resources/templates/edit-showoff.html (4)

25-25: 제목 필드의 name 속성 추가로 일관성이 향상되었습니다.

제목 입력 필드에 name="title" 속성 추가로 다른 폼 템플릿과의 일관성이 확보되었습니다.


32-57: 라디오 버튼의 name 속성 표준화가 적절합니다.

반려동물 종류 라디오 버튼의 name 속성이 edit-showoff-petType에서 petType으로 변경되어 다른 폼 템플릿과 일관된 네이밍 규칙을 따르게 되었습니다. 이는 JavaScript에서 FormData 처리를 통일할 수 있게 합니다.


64-64: 콘텐츠 textarea의 name 속성이 올바르게 추가되었습니다.

자랑 내용 입력 필드에 name="content" 속성이 추가되어 폼 데이터 추출이 표준화되었습니다.


74-74: 파일 입력의 name 속성 추가가 적절합니다.

이미지 파일 입력에 name="imageFiles" 속성이 추가되어 파일 업로드 처리가 일관성을 가지게 되었습니다.

src/main/resources/templates/edit-review.html (3)

25-35: 기본 입력 필드들의 name 속성 추가가 완벽합니다.

제목, 반려동물 이름, 여행 장소 입력 필드에 각각 name="title", name="petName", name="region" 속성이 추가되어 후기 폼의 모든 데이터가 올바르게 식별됩니다.


42-67: 반려동물 종류 라디오 버튼의 name 속성 표준화가 우수합니다.

라디오 버튼의 name 속성이 edit-review-petType에서 petType으로 통일되어 다른 폼 템플릿과 일관된 네이밍 규칙을 따릅니다. 이는 JavaScript에서 FormData 처리를 단순화합니다.


74-84: 콘텐츠 및 파일 입력의 name 속성이 적절히 설정되었습니다.

후기 내용 textarea와 이미지 파일 입력에 각각 name="content", name="imageFiles" 속성이 추가되어 폼 데이터 처리의 일관성이 확보되었습니다.

src/main/resources/templates/edit-qna.html (1)

25-25: 폼 데이터 바인딩 표준화 완료!

모든 폼 입력 요소에 적절한 name 속성이 추가되어 FormData 사용을 위한 표준화가 잘 이루어졌습니다. 이는 클라이언트 측 폼 처리 일관성을 크게 향상시킬 것입니다.

Also applies to: 32-32, 36-36, 40-40, 44-44, 48-48, 52-52, 56-56, 66-66, 75-75, 85-85

src/main/resources/templates/post-review-form.html (1)

25-25: 폼 입력 요소 표준화 완료!

모든 입력 요소에 일관된 name 속성이 추가되었고, 특히 반려동물 종류 라디오 버튼이 다른 폼들과 동일한 petType으로 통일되어 전체적인 일관성이 확보되었습니다.

Also applies to: 30-30, 35-35, 42-42, 46-46, 50-50, 54-54, 58-58, 62-62, 66-66, 74-74, 84-84

src/main/java/io/github/petty/community/controller/CommentController.java (3)

13-13: 구조화된 로깅 도입 승인!

@Slf4j 어노테이션 추가로 적절한 로깅 프레임워크 사용이 구현되었습니다. 이는 운영 환경에서의 관찰 가능성을 크게 향상시킬 것입니다.

Also applies to: 17-17


34-52: 로깅 개선 및 에러 처리 강화 완료!

구조화된 로깅과 상세한 컨텍스트 정보 추가로 디버깅 효율성이 크게 향상되었습니다. 특히 postIdusername 정보가 포함되어 문제 추적이 용이해졌습니다.


68-82: 삭제 로직 로깅 개선 완료!

댓글 삭제 과정의 로깅이 체계적으로 개선되어 운영 환경에서의 추적성이 향상되었습니다. 예외 스택 트레이스와 컨텍스트 정보가 적절히 기록됩니다.

src/main/resources/static/js/common/edit-qna.js (3)

40-66: 에러 메시지 시스템 구현이 우수합니다!

새로 추가된 에러 메시지 표시 시스템이 잘 구현되었습니다:

  • 자동 해제 기능 (5초)
  • 기존 알림 중복 방지
  • 사용자 친화적 인터페이스

101-134: FormData 사용으로 폼 처리 개선됨

FormData를 사용한 입력값 추출과 검증 로직이 잘 구현되었습니다:

  • name 속성 기반 데이터 추출
  • 필수 필드 검증 강화
  • 사용자 친화적 에러 메시지와 포커스 처리

209-225:

Details

❓ Verification inconclusive

name 속성 우선 접근 방식 개선됨

필드 선택 로직이 name 속성을 우선으로 하고 ID를 폴백으로 사용하는 방식으로 개선되어 HTML 표준에 더 부합합니다.

다만 일관성을 위해 다음 사항을 확인해보세요:


🏁 Script executed:

#!/bin/bash
# Description: HTML 템플릿의 name 속성 일관성 확인
# Expected: 모든 폼 필드가 적절한 name 속성을 가지고 있는지 확인

rg -A 3 'edit-qna-title|edit-qna-content|edit-qna-petName|edit-qna-region' --type html

Length of output: 1027


HTML 폼 필드 name 속성 일관성 재확인 필요

아래 두 필드는 의도한 대로 name 속성이 잘 적용되어 있습니다.

  • src/main/resources/templates/edit-qna.html
    • <input id="edit-qna-title" name="title" …>
    • <textarea id="edit-qna-content" name="content" …>

하지만 추가 필드(예: petType, petName, region 등)가 모두 name 속성을 일관되게 갖추고 있는지 확인이 필요합니다.
필드가 누락되었거나 다른 속성명으로 정의되어 있지 않은지 검토해주세요.

src/main/resources/static/js/common/form.js (1)

188-226: FormData 기반 폼 처리 로직 우수함

FormData를 활용한 새로운 폼 처리 방식이 잘 구현되었습니다:

  • name 속성 기반 일관된 데이터 추출
  • 포괄적인 필수 필드 검증
  • 향상된 사용자 피드백

특히 체크박스 처리에서 formData.has('isResolved') 사용이 적절합니다.

src/main/resources/static/js/common/edit-review.js (1)

159-167: isResolved 토글 기능 우수함

체크박스 상태에 따른 라벨 텍스트 동적 업데이트 기능이 잘 구현되었습니다. 사용자 경험을 크게 개선합니다.

src/main/java/io/github/petty/community/service/PostImageServiceImpl.java (3)

77-87: 이미지 일괄 삭제 최적화 우수함

개별 삭제 대신 일괄 삭제로 변경하여 성능을 크게 개선했습니다:

  • N+1 쿼리 문제 해결
  • 트랜잭션 내에서 안전한 일괄 처리
  • 파일 삭제도 함께 처리

94-102: 새 이미지 추가 로직 개선됨

새 이미지 추가 시 ordering 값의 null 체크와 기본값 설정이 잘 구현되었습니다.


105-115:

Details

✅ Verification successful

기존 이미지 매핑으로 성능 최적화

기존 이미지들을 Map으로 변환하여 반복적인 데이터베이스 조회를 방지한 것이 우수합니다.

하지만 삭제된 이미지에 대한 처리를 확인해보세요:


🏁 Script executed:

#!/bin/bash
# Description: 삭제된 이미지가 맵에서 제거되는지 확인
# Expected: 삭제 후 맵에서 해당 이미지들이 참조되지 않아야 함

ast-grep --pattern $'if (!Boolean.TRUE.equals($_.getIsDeleted()) && $_.getId() != null && $_.getOrdering() != null) {
  PostImage image = existingImagesMap.get($_.getId());
  $$$
}'

Length of output: 959


🏁 Script executed:

#!/bin/bash
# Print the relevant part of PostImageServiceImpl to inspect deletion logic
sed -n '1,200p' src/main/java/io/github/petty/community/service/PostImageServiceImpl.java

Length of output: 4469


삭제된 이미지 맵 필터링은 이미 처리됩니다

updateImagesFromRequest 메소드에서
1️⃣ 삭제 로직(isDeleted == true)으로 DB와 Supabase 에서 제거된 후,
5️⃣ Ordering 업데이트 단계에서 !Boolean.TRUE.equals(dto.getIsDeleted()) 조건으로 해당 DTO가 제외됩니다.
따라서 existingImagesMap에 여전히 남아 있어도 참조되지 않아 별도 제거 로직이 필요 없습니다.

src/main/resources/static/js/common/edit-showoff.js (3)

101-126: FormData 사용과 폼 검증 로직이 잘 구현되었습니다.

FormData를 사용한 표준화된 접근 방식과 포괄적인 필드 검증이 코드의 일관성과 안정성을 크게 향상시켰습니다. 특히 사용자에게 명확한 피드백을 제공하는 점이 우수합니다.


127-133: 페이로드 구성이 검증된 변수를 사용하도록 개선되었습니다.

이전의 DOM 직접 조회 방식에서 검증된 변수를 사용하는 방식으로 변경되어 데이터 일관성이 보장됩니다.


197-207: name 속성을 활용한 요소 선택과 펫 타입 처리가 개선되었습니다.

HTML의 name 속성을 활용한 표준화된 접근 방식으로 변경되었고, 기존 ID를 fallback으로 사용하는 호환성 로직도 잘 구현되었습니다. 펫 타입 입력 처리의 일관성도 향상되었습니다.

Comment on lines +40 to +66
// 🔥 에러 메시지 표시 함수 추가
function showErrorMessage(message) {
// 기존 알림 제거
removeExistingAlerts();

const alertDiv = document.createElement('div');
alertDiv.className = 'alert alert-error';
alertDiv.innerHTML = `
<span class="alert-icon">⚠️</span>
<span class="alert-message">${message}</span>
<button class="alert-close" onclick="this.parentElement.remove()">×</button>
`;

document.body.insertBefore(alertDiv, document.body.firstChild);

// 5초 후 자동 제거
setTimeout(() => {
if (alertDiv.parentElement) {
alertDiv.remove();
}
}, 5000);
}

function removeExistingAlerts() {
const existingAlerts = document.querySelectorAll('.alert');
existingAlerts.forEach(alert => alert.remove());
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

에러 메시지 함수 중복 발견

showErrorMessageremoveExistingAlerts 함수가 edit-qna.js와 동일하게 구현되었습니다.

공통 유틸리티 함수로 분리하여 코드 중복을 제거하는 것을 권장합니다:

// 새 파일: src/main/resources/static/js/utils/alert-utils.js 생성
+export function showErrorMessage(message) {
+  // 기존 구현 이동
+}
+
+export function removeExistingAlerts() {
+  // 기존 구현 이동
+}

// 각 파일에서:
+import { showErrorMessage, removeExistingAlerts } from '../utils/alert-utils.js';
-// 중복된 함수 정의 제거

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/resources/static/js/common/edit-review.js around lines 40 to 66, the
functions showErrorMessage and removeExistingAlerts are duplicated from
edit-qna.js. To fix this, extract these functions into a shared utility
JavaScript file and import them where needed, then remove the duplicate
implementations from this file to eliminate code redundancy.

@usn757
Copy link
Contributor

usn757 commented May 31, 2025

고생하셨습니다! 전반적으로 많은 개선 사항이 포함된 중요한 PR로 보입니다. 특히 폼 처리 표준화와 백엔드 성능 최적화 노력이 돋보입니다.

[긍정적인 부분]

  • 백엔드 성능 최적화:

    • PostServiceImpl에서 updateAllPostCounts 로직을 N+1 방식에서 PostRepository의 JPQL/Native 벌크 업데이트로 변경하여 쿼리 수를 획기적으로 줄인 점(1+3N -> 1)은 매우 훌륭한 개선입니다. 실제 서비스에서 큰 성능 향상이 기대됩니다.
    • PostImageServiceImpl에서 이미지 삭제 및 순서 변경 로직을 스트림과 일괄 처리를 활용하여 개선한 점도 좋습니다.
  • 🎨 프론트엔드 개선:

    • 모든 커뮤니티 폼(Q&A, 리뷰, 자랑하기 - 생성/수정)에서 name 속성을 추가하고 FormData API를 사용하도록 표준화하여 일관성과 안정성을 높인 점이 매우 좋습니다.
    • showErrorMessage 함수를 도입하여 사용자에게 일관된 에러 피드백을 제공하고, 5초 후 자동 제거되는 기능은 사용자 경험(UX)을 향상시킵니다.
    • 필수 필드에 대한 클라이언트 사이드 유효성 검사 추가도 좋은 변화입니다.
  • 🔐 보안 및 안정성 강화:

    • PostController/update-counts 엔드포인트에 @PreAuthorize("hasRole('ADMIN')")를 추가하여 관리자 권한을 적용한 것은 중요한 보안 강화입니다.
    • CommentController에서 System.out/err 대신 SLF4J 로거를 사용하도록 변경하고, 예외 처리를 세분화한 점은 디버깅 및 운영에 도움이 됩니다.
  • 🧩 코드 일관성 및 현대화:

    • DTO에서 javax.validationjakarta.validation으로 변경한 것은 최신 스펙을 따르는 좋은 마이그레이션입니다.

[제안 및 논의 사항]

  • JS 함수 중복:

    • edit-qna.js, edit-review.js, edit-showoff.js 파일에 showErrorMessageremoveExistingAlerts 함수가 중복으로 존재합니다. CodeRabbit AI 봇의 제안처럼, 이들을 공통 유틸리티 파일(alert-utils.js 등)로 분리하여 관리하는 것을 고려해 보시면 좋을 것 같습니다. (DRY 원칙)
  • updateAllPostCounts 네이티브 쿼리 사용 여부:

    • PostRepository에 JPQL 버전과 Native SQL 버전의 updateAllPostCounts가 모두 추가되었습니다. PostServiceImpl에서는 현재 JPQL 버전(postRepository.updateAllPostCounts())을 호출하고 있습니다. Native SQL 버전(updateAllPostCountsNative)은 특정 상황을 위한 것인지, 혹은 향후 전환 가능성이 있는지 궁금합니다.
  • HTTP 상태 코드 변경 (댓글 삭제 실패 시):

    • ed9a789 커밋에서 댓글 삭제 실패 시 응답 상태 코드가 400 Bad Request에서 500 Internal Server Error로 변경되었습니다. 이 변경의 구체적인 의도(예: 클라이언트 책임 vs 서버 내부 오류 구분)를 공유해주시면 이해에 도움이 될 것 같습니다.

전반적으로 매우 훌륭한 기여입니다. 코드의 품질과 성능, 사용자 경험을 한 단계 높이는 데 크게 기여할 것으로 보입니다!

@usn757 usn757 merged commit 82ff5b0 into PETTY-HUB:main May 31, 2025
2 checks passed
@LimPark996
Copy link
Contributor Author

LimPark996 commented Jun 1, 2025

감사합니다!!

updateAllPostCounts 네이티브 쿼리 사용 여부:

PostRepository에 JPQL 버전과 Native SQL 버전의 updateAllPostCounts가 모두 추가되었습니다. PostServiceImpl에서는 현재 JPQL 버전(postRepository.updateAllPostCounts())을 호출하고 있습니다. Native SQL 버전(updateAllPostCountsNative)은 특정 상황을 위한 것인지, 혹은 향후 전환 가능성이 있는지 궁금합니다.
HTTP 상태 코드 변경 (댓글 삭제 실패 시):

ed9a789 커밋에서 댓글 삭제 실패 시 응답 상태 코드가 400 Bad Request에서 500 Internal Server Error로 변경되었습니다. 이 변경의 구체적인 의도(예: 클라이언트 책임 vs 서버 내부 오류 구분)를 공유해주시면 이해에 도움이 될 것 같습니다

수정 완료하였습니다.!

@LimPark996 LimPark996 changed the title [fix] community edit form & code review updated & added name tag [COMM] community edit form & code review updated & added name tag Jun 1, 2025
@LimPark996 LimPark996 changed the title [COMM] community edit form & code review updated & added name tag [COMM] 커뮤니티 폼 데이터 처리 통일 및 코드리뷰 반영 Jun 1, 2025
@LimPark996 LimPark996 changed the title [COMM] 커뮤니티 폼 데이터 처리 통일 및 코드리뷰 반영 [COMMUNITY] 커뮤니티 폼 데이터 처리 통일 및 코드리뷰 반영 Jun 1, 2025
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.

2 participants