[4주차] 송유경/feat 게시물·댓글·신고 도메인 상태 전이 및 중복 방지 API 구현#138
Hidden character warning
[4주차] 송유경/feat 게시물·댓글·신고 도메인 상태 전이 및 중복 방지 API 구현#138yukyoungs wants to merge 4 commits intoLeets-Official:송유경/mainfrom
Conversation
| public PostResponse create(PostRequest.Create request) { | ||
| public PostResponse create(AuthUser authUser, PostRequest.Create request) { | ||
| User user = userRepository.findById(authUser.getUserId()) | ||
| .orElseThrow(() -> new IllegalArgumentException(ErrorCode.USER_NOT_FOUND.getMessage())); |
There was a problem hiding this comment.
PostService 전반에서 ErrorCode를 IllegalArgumentException에 message로 풀어 던지고 계신데요, 같은 PR의 CommentService/ReportService는 BusinessException(ErrorCode.XXX)를 던지고 있어서 전역 예외 처리기에서 받는 방식이 도메인마다 갈라질 것 같습니다. PostService에서도 BusinessException으로 통일해주시면 응답 포맷과 HTTP 상태 코드가 일관되게 내려갈 것 같아요! (USER_NOT_FOUND, POST_NOT_FOUND, FORBIDDEN 모두 동일하게요)
| @Component | ||
| @RequiredArgsConstructor | ||
| public class SeedDataInitializer implements CommandLineRunner { | ||
|
|
There was a problem hiding this comment.
@Component + CommandLineRunner 조합이라 환경과 관계없이 부팅 시 항상 실행되는 구조인데요, admin/user1/user2 같은 고정 비밀번호 계정이 운영 환경에서도 자동으로 생성될 여지가 있어 보입니다. @Profile("local") 또는 @ConditionalOnProperty로 dev/local 프로파일에서만 동작하도록 가드를 한 겹 두시면 실수로 운영에 시드가 새는 사고를 막을 수 있을 것 같아요!
| return ResponseEntity.ok(BaseResponse.ok(response)); | ||
| } | ||
|
|
||
| @GetMapping("/me") |
There was a problem hiding this comment.
/me에서 AuthUser를 그대로 응답으로 내려주고 계신데요, AuthUser는 인증 컨텍스트용 내부 객체라 응답 모델로 노출되면 향후 필드를 추가할 때 의도치 않게 API 스펙이 같이 바뀔 수 있을 것 같습니다. 다른 엔드포인트처럼 AuthResponse.UserInfo 같은 응답 DTO로 매핑해서 내려주시면 응답 계약을 분리해서 관리하기 좋을 것 같아요!
| return ResponseEntity.ok(BaseResponse.ok(authUser)); | ||
| } | ||
|
|
||
| @GetMapping("/users/{userId}") |
There was a problem hiding this comment.
@RequestMapping("/api/auth") 아래에 /users/{userId} 조회가 들어와 있는데요, 인증 흐름(signup/login/me)과 사용자 단건 조회는 책임이 조금 달라 보여서 경로상 /api/auth/users/{userId}가 약간 어색하게 느껴집니다. UserController로 분리하고 /api/users/{userId}로 빼주시면 도메인별 라우팅이 더 명확해질 것 같아요!
| private final String email; | ||
| private final String nickname; | ||
| private final UserRole role; | ||
| private final String authHeaderName; |
There was a problem hiding this comment.
로그인 응답에 authHeaderName("X-USER-ID")이 포함되어 있는데요, 헤더 이름은 API 스펙(혹은 Swagger 문서)에서 클라이언트가 알게 되는 정보라 응답 페이로드마다 같이 내려보내는 건 다소 중복일 수 있습니다. 임시 인증 방식이라는 의도가 있다면 PR 본문/Swagger 설명에서 안내하는 쪽으로 옮기시고 응답에서는 빼주셔도 좋을 것 같아요!
|
|
||
| @Transactional | ||
| public ReportResponse resolve(AuthUser authUser, Long reportId) { | ||
| if (authUser.getRole() != UserRole.ADMIN) { |
There was a problem hiding this comment.
resolve() 안에서도 admin 검증을 직접 하고 계신데, 아래 findAll/findById는 validateAdmin 헬퍼를 쓰고 있어요. resolve()도 validateAdmin(authUser)로 통일해주시면 권한 체크 로직이 한 곳에 모여서 나중에 정책이 바뀔 때 한 군데만 손대면 될 것 같습니다!
| PostResponse response = postService.activate(authUser, id); | ||
| return ResponseEntity.ok(BaseResponse.ok(response)); | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
파일 끝 개행이 빠져 있네요. SwaggerConfig.java, PostService.java도 동일한 상태로 보여서 함께 줄바꿈 한 줄 추가해주시면 깔끔할 것 같아요!
theSnackOverflow
left a comment
There was a problem hiding this comment.
4주차 분량이 많은데 도메인 상태 전이를 엔티티 메서드로 깔끔하게 캡슐화하고, 신고 중복 방지를 DB 유니크 제약까지 걸어 막아주신 점 인상 깊었어요. @CurrentUser 리졸버 분리와 readOnly 트랜잭션 패턴도 일관되게 잡혀 있어 보기 좋았습니다. 몇 가지 확인해보시면 좋을 것 같은 부분 남겨봅니다!
|
게시물과 댓글 신고를 POST /api/posts/{postId}/reports와 POST /api/comments/{commentId}/reports로 깔끔하게 분리한 점이 좋은것 같습니다! PATCH /api/reports/{reportId}/resolve로 신고 상태를 관리하는 로직도 체계적인 거같아서 잘 구현하신것 같네요. 고생하셨습니다! |
|
@currentuser와 ArgumentResolver를 활용해 인증 로직을 깔끔하게 분리하 게시글·댓글·신고 시스템의 상태 관리 체계를 명확히 구축한 점이 인상적입니다. 각 API가 비즈니스 목적에만 집중할 수 있는 순수한 계층 분리를 구현하신 것 같습니다. 오늘도 배워갑니다. |
1. 과제 요구사항 중 구현한 내용
구현 API(주요):
POST /api/posts/{postId}/comments댓글 작성PATCH /api/comments/{commentId}/accept댓글 채택 (게시글당 1개 제한)POST /api/posts/{postId}/reports게시물 신고POST /api/comments/{commentId}/reports댓글 신고PATCH /api/reports/{reportId}/resolve신고 처리 완료 (PENDING -> RESOLVED)PATCH /api/posts/{id}/hide,PATCH /api/posts/{id}/activate게시물 상태 전이2. 핵심 변경 사항
@CurrentUser+CurrentUserArgumentResolver로X-USER-ID인증 주입PostStatus를ACTIVE/HIDDEN으로 변경CommentStatus추가(ACTIVE/HIDDEN)Report,ReportStatus(PENDING/RESOLVED),ReportTargetType(POST/COMMENT)도입, 동일 유저의 동일 대상 신고 중복 방지3. 실행 및 검증 결과
./gradlew test통과Authorize -> X-USER-ID설정 후 API 호출 정상POST /api/posts성공 시authorId가 로그인 유저 ID로 저장됨ACTIVE <-> HIDDEN정상PENDING -> RESOLVED정상POST /api/posts/{postId}/reports4. 완료 사항
5. 추가 사항
closed #133현재 인증은 과제 진행용 X-USER-ID 헤더 기반 최소 구현입니다.
시드 데이터는 서버 부팅 시 실행되며, 조건 기반으로 중복 생성을 방지합니다.
제출 체크리스트
Reviewer 참고