Skip to content

Feat: V3 배포#222

Merged
tishakong merged 22 commits into
mainfrom
dev
Mar 31, 2026
Merged

Feat: V3 배포#222
tishakong merged 22 commits into
mainfrom
dev

Conversation

@tishakong

Copy link
Copy Markdown
Collaborator

이슈 번호

작업 내용

  • 멀티프로필 Mypage API 배포
  • 게시글/댓글 신고 API 배포

tishakong and others added 22 commits March 13, 2026 17:53
- 회의 중 기획이 변경된 것과 같이 신고 객체에 신고 당시 시점의 데이터를 스냅샷할 수 있도록 컬럼 추가했습니다.
- 기획 상 요구되는 신고 게시글 바로가기를 위한 postId, 신고 게시판을 위한 postType을 추가했습니다. Post 객체를 업로드하는 것은 Post나 comment가 삭제되더라도 신고 기록을 남겨야 하기에 FK 설정을 하지 않기 위해 postId와 postType을 기록하는 형식으로 구현했습니다.
@tishakong tishakong self-assigned this Mar 31, 2026
@tishakong tishakong merged commit 63d10b1 into main Mar 31, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive MyPage feature, refactors the reporting system to support both posts and comments, and implements profile switching functionality. Key changes include the addition of MyPage-related controllers and services, updates to the Report entity and its associated logic, and repository enhancements for optimized data fetching. Feedback identifies a critical security risk regarding the database DDL configuration in the application properties and points out code duplication in report handling within the Post entity. Additionally, recommendations are provided to maintain API response consistency in the MyPage controller, implement missing self-report validations for comments, and remove commented-out legacy files to improve code maintainability.

Comment thread src/main/resources/application.properties
Comment on lines +1 to +68
//package org.example.tackit.domain.admin.controller;
//
//import lombok.RequiredArgsConstructor;
//import org.example.tackit.domain.admin.dto.ReportedPostDTO;
//import org.example.tackit.domain.admin.service.ReportedPostService;
//import org.example.tackit.domain.entity.postType;
//import org.example.tackit.common.dto.PageResponseDTO;
//import org.springframework.data.domain.Page;
//import org.springframework.data.domain.Pageable;
//import org.springframework.data.domain.Sort;
//import org.springframework.data.web.PageableDefault;
//import org.springframework.http.ResponseEntity;
//import org.springframework.web.bind.annotation.*;
//
//import java.util.Map;
//
//@RestController
//@RequestMapping("/api/admin/report")
//@RequiredArgsConstructor
//public class AdminPostController {
// private final Map<Post, ReportedPostService> reportedPostServices;
//
// // 신고된 게시글 조회
// @GetMapping("/{postType}/posts")
// public ResponseEntity<PageResponseDTO<ReportedPostDTO>> getReportedPosts(
// @PathVariable("postType") Post postType,
// @PageableDefault(size = 5, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) {
// ReportedPostService service = reportedPostServices.get(postType);
//
// if (service == null) {
// throw new IllegalArgumentException("지원하지 않는 게시글 유형입니다: " + postType);
// }
//
// Page<ReportedPostDTO> posts = service.getDeletedPosts(pageable);
// return ResponseEntity.ok(PageResponseDTO.from(posts));
// }
//
// // 게시글 완전 삭제
// @DeleteMapping("/{postType}/posts/{postId}")
// public ResponseEntity<Void> deleteReportedPost(
// @PathVariable("postType") Post postType,
// @PathVariable("postId") Long postId) {
//
// ReportedPostService service = reportedPostServices.get(postType);
// if (service == null) {
// throw new IllegalArgumentException("지원하지 않는 게시글 유형입니다: " + postType);
// }
//
// service.deletePost(postId);
// return ResponseEntity.noContent().build();
// }
//
// // 게시글 활성화
// @PatchMapping("/{postType}/posts/{postId}/activate")
// public ResponseEntity<String> activateReportedPost(
// @PathVariable("postType") Post postType,
// @PathVariable("postId") Long postId) {
//
// ReportedPostService service = reportedPostServices.get(postType);
// if (service == null) {
// throw new IllegalArgumentException("지원하지 않는 게시글 유형입니다: " + postType);
// }
//
// service.activatePost(postId);
// return ResponseEntity.ok("게시글이 활성화되었습니다.");
// }
//
//}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

파일 전체가 주석 처리되어 있습니다. 더 이상 사용하지 않는 코드라면 주석으로 남겨두기보다 파일을 삭제하여 코드 베이스를 깔끔하게 유지하는 것을 권장합니다. ExecutiveReportController.java 파일도 동일한 확인이 필요해 보입니다.

Comment on lines +161 to +167
public void receiveReport() {
this.reportCnt++;

if (this.reportCnt >= 3) {
this.activeStatus = ActiveStatus.DELETED;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

기존에 존재하는 increaseReportCount() 메서드(145행)와 새로 추가된 receiveReport() 메서드가 거의 동일한 로직(신고 횟수 증가 및 3회 이상 시 삭제 상태 변경)을 수행하고 있습니다. 코드의 중복을 피하고 유지보수성을 높이기 위해 하나의 메서드로 통합하는 것이 좋습니다.

Comment on lines +84 to +86
public ResponseEntity<SignInResponse> switchProfile() {
return ResponseEntity.ok(authService.switchProfile());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

해당 컨트롤러의 다른 API 엔드포인트들은 ApiResponse 래퍼를 사용하여 일관된 응답 형식을 반환하고 있으나, switchProfile 메서드만 SignInResponse를 직접 반환하고 있습니다. 클라이언트에서 공통된 응답 처리를 할 수 있도록 ApiResponse.success()를 사용하여 형식을 맞추는 것이 좋습니다.

Suggested change
public ResponseEntity<SignInResponse> switchProfile() {
return ResponseEntity.ok(authService.switchProfile());
}
@PostMapping("/switch")
public ResponseEntity<ApiResponse<SignInResponse>> switchProfile() {
return ApiResponse.success(HttpStatus.OK, "프로필 전환 성공", authService.switchProfile());
}

Comment on lines +59 to +82
public void reportComment(ReportReqDto reqDto, Long requesterMemberOrgId, Long commentId) {
MemberOrg reporter = memberOrgValidator.validateActiveMembership(requesterMemberOrgId);

Comment comment = commentRepository.findByIdWithPost(commentId)
.orElseThrow(() -> new IllegalArgumentException("해당 댓글을 찾을 수 없습니다."));

Post post = comment.getPost();

Report report = Report.builder()
.reporter(reporter)
.targetMember(comment.getWriter())
.targetId(comment.getId())
.targetType(TargetType.COMMENT)
.postId(post.getId())
.postType(post.getPostType())
.reportedPostTitle(post.getTitle())
.reportedContent(comment.getContent())
.reportReason(reqDto.getReportReason())
.detailReason(reqDto.getDetailReason())
.build();

comment.receiveReport();
reportRepository.save(report);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

reportPost 메서드(36행)에서는 본인이 작성한 게시글을 신고할 수 없도록 검증하는 로직이 포함되어 있으나, reportComment 메서드에는 해당 검증이 누락되어 있습니다. 일관성 및 서비스 오남용 방지를 위해 본인이 작성한 댓글에 대한 신고 차단 로직을 추가해 주세요. 이때, 해당 검증 로직은 MemberOrgValidator와 같은 별도의 검증 컴포넌트에서 중앙 집중식으로 관리하여 재사용성을 높이는 것을 권장합니다.

References
  1. Centralize ownership validation logic in a dedicated validator component (e.g., MemberOrgValidator) for reusability, rather than implementing it inline within service methods.

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