Conversation
워크스루팔로우된 사용자를 닉네임 기반으로 언팔로우할 수 있는 새로운 기능을 추가합니다. 이를 위해 새로운 에러 코드, 예외 클래스, 서비스 메서드, 저장소 쿼리, API 엔드포인트가 구현되었으며, 사용자 프로필 업데이트 로직도 개선되었습니다. 변경사항
시퀀스 다이어그램sequenceDiagram
actor User as 사용자
participant Controller as UserController
participant Service as FollowService
participant Repo as FollowRepository
participant DB as Database
User->>Controller: DELETE /api/v1/users/unfollow<br/>(unFollowNickname)
Controller->>Service: unFollow(unFollowNickname,<br/>followerId)
Service->>Repo: 팔로워 조회
Repo->>DB: SELECT by followerId
DB-->>Repo: follower
Repo-->>Service: follower
Service->>Repo: 언팔로우 대상 조회
Repo->>DB: SELECT by nickname
DB-->>Repo: followee
Repo-->>Service: followee
alt 자신을 언팔로우 시도
Service-->>Controller: SameUnFollowException
Controller-->>User: 400 Bad Request
else
Service->>Repo: findByFollowerIdAndFolloweeId()
Repo->>DB: SELECT Follow 관계
DB-->>Repo: Follow entity
Repo-->>Service: Optional<Follow>
alt Follow 관계 없음
Service-->>Controller: NotFoundFollowException
Controller-->>User: 400 Bad Request
else Follow 관계 존재
Service->>Repo: delete(Follow)
Repo->>DB: DELETE Follow
DB-->>Repo: 삭제 완료
Repo-->>Service: 완료
Service-->>Controller: void
Controller-->>User: 201 Created<br/>"팔로우 취소 성공"
end
end
예상 코드 리뷰 시간🎯 3 (보통) | ⏱️ ~20분
관련된 가능성 있는 PR
시
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (8)
src/main/java/team/wego/wegobackend/user/application/UserService.java (1)
50-57: 닉네임 변경 조건 분기 개선 👍기존 닉네임과 다를 때만 중복 체크/업데이트하도록 바꾼 점 좋아 보입니다. 불필요한 DB exists 조회가 줄어들어 효율적입니다. 추가로, 닉네임에 공백 문자열 허용 여부를 DTO 레벨(@notblank 등)에서 명확히 해두면 더 안전할 것 같습니다.
src/test/http/user/user-api.http (1)
69-72: 언팔로우 성공/실패 케이스를 명확히 구분하는 것이 좋겠습니다현재 흐름상 accessToken 은 닉네임을
예은으로 바꾼 첫 번째 사용자이고, 팔로우 대상은"팔로우 대상"이라서, 아래 언팔로우 요청은 “자기 자신 언팔로우” 예외(SameUnFollowException)만 검증하게 됩니다.실제 언팔로우 성공 케이스도 확인하려면 예를 들어 다음과 같이 나누는 걸 고려해볼 수 있습니다.
### 팔로우 취소 (성공 케이스) DELETE http://localhost:8080/api/v1/users/unfollow?unFollowNickname=팔로우 대상 Authorization: Bearer {{accessToken}} ### 팔로우 취소 (본인 언팔로우 예외 케이스) DELETE http://localhost:8080/api/v1/users/unfollow?unFollowNickname=예은 Authorization: Bearer {{accessToken}}이렇게 하면 성공/실패 시나리오를 각각 손쉽게 재현할 수 있습니다.
src/main/java/team/wego/wegobackend/user/repository/FollowRepository.java (1)
3-10: 언팔로우용 조회 메서드 추가 적절합니다
Optional<Follow> findByFollowerIdAndFolloweeId추가로 언팔로우 시 관계 존재 여부를 깔끔하게 처리할 수 있어서 좋습니다.자잘한 부분이지만, 파라미터 이름
followingId를followeeId정도로 맞춰두면 도메인 용어(팔로워/팔로이)와 더 잘 매칭될 것 같습니다(동작에는 영향 없습니다).src/main/java/team/wego/wegobackend/user/presentation/UserController.java (1)
117-127: 언팔로우 엔드포인트 동작은 적절하지만 HTTP 상태 코드는 조정이 좋아 보입니다
- 언팔로우 비즈니스 플로우를
FollowService.unFollow에 위임한 구조는 명확합니다.- 다만
DELETE /unfollow에서HttpStatus.CREATED(201)를 반환하는 것은 REST 관점에서 다소 어색합니다. 일반적으로 삭제 성공 시에는200 OK(본문이 있을 때)나204 No Content를 많이 사용합니다.예를 들어 다음처럼 맞추는 것을 고려해볼 수 있습니다.
return ResponseEntity .status(HttpStatus.OK) .body(ApiResponse.success(200, "팔로우 취소 성공"));또한 메서드/파라미터 이름을
unfollow,unfollowNickname처럼 소문자 카멜케이스로 통일하면 기존follow메서드와도 스타일이 더 일관적일 것 같습니다.src/main/java/team/wego/wegobackend/common/exception/AppErrorCode.java (1)
30-33: 팔로우/언팔로우 전용 에러 코드 추가 일관성 좋습니다
NOT_SAME_FOLLOW,ALREADY_EXIST_FOLLOW와 동일한 패턴으로NOT_SAME_UNFOLLOW,NOT_FOUND_FOLLOW를 추가해서 도메인 에러가 잘 구분됩니다.선택 사항으로,
NOT_FOUND_FOLLOW는 리소스 부재에 가까운 의미라HttpStatus.NOT_FOUND(404)를 사용할지 한 번 더 팀 내에서 논의해 보면 좋겠습니다(현재 400도 큰 문제는 아닙니다만, 의미 상 404가 조금 더 직관적일 수 있습니다).src/main/java/team/wego/wegobackend/user/application/FollowService.java (2)
27-46: 팔로우 저장 로직 추가로 비즈니스 요구사항이 완성되었습니다
followRepository.save(Follow.builder()...)를 추가해 실제 팔로우 관계가 영속화되도록 한 점이 핵심 수정으로 보이고, 빌더에follower,follow를 명시해서 의도가 잘 드러납니다.추가로,
existsByFollowerIdAndFolloweeId로 사전 체크 후save하는 패턴은 동시성 환경에서 레이스 컨디션이 발생할 수 있으니, DB 레벨에서(follower_id, followee_id)유니크 인덱스를 두고 예외를 잡아 처리하는 방식도 한 번 고려해 볼 만합니다.
48-64: 언팔로우 플로우가 follow와 대칭적으로 잘 설계되었습니다
- follower 조회 → 자기 자신 언팔로우 방지(
SameUnFollowException) → 대상 유저 조회 → 관계 조회 후 없으면NotFoundFollowException, 있으면delete하는 흐름이 명확합니다.- 클래스 레벨
@Transactional덕분에 조회·삭제가 하나의 트랜잭션으로 처리되는 점도 적절합니다.선택적으로,
- 현재는 컨트롤러에서만 호출되므로 괜찮지만, 다른 호출 경로가 생길 경우를 대비해
unFollowNickname에 대한 null/blank 검증을 서비스 레이어에서도 한 번 더 해두면 방어적일 수 있습니다.findBy...후delete대신deleteByFollowerIdAndFolloweeId(...)같이 한 번에 삭제하고 영향 행 개수로 존재 여부를 판단하는 리포지토리 메서드를 두면, DB 라운드트립을 줄이고 의도가 더 분명해집니다.src/main/java/team/wego/wegobackend/user/presentation/UserControllerDocs.java (1)
52-56: 언팔로우 메서드/파라미터 네이밍 일관성 개선 제안
- 메서드명
unFollow, 파라미터/쿼리 파라미터"unFollowNickname"은 카멜 케이스가 다소 어색하고, 기존follow/followNickname과도 규칙이 달라 보입니다.unfollow/unfollowNickname처럼 모두 소문자 카멜 케이스로 통일하거나, 두 API 모두 동일하게"targetNickname"등으로 맞추는 것을 고려하면 가독성과 유지보수성이 좋아질 것 같습니다(클라이언트와의 API 계약 변경 범위는 한 번 더 검토 필요).예시:
- @Operation(summary = "팔로우 취소 API", description = "요청 닉네임에 해당하는 사용자를 팔로우 취소합니다.") - ResponseEntity<ApiResponse<String>> unFollow( + @Operation(summary = "팔로우 취소 API", description = "요청 닉네임에 해당하는 사용자를 팔로우 취소합니다.") + ResponseEntity<ApiResponse<String>> unfollow( @AuthenticationPrincipal CustomUserDetails userDetails, - @Valid @RequestParam("unFollowNickname") String unFollowNickname + @Valid @RequestParam("unfollowNickname") String unfollowNickname );
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/main/java/team/wego/wegobackend/common/exception/AppErrorCode.java(1 hunks)src/main/java/team/wego/wegobackend/user/application/FollowService.java(2 hunks)src/main/java/team/wego/wegobackend/user/application/UserService.java(1 hunks)src/main/java/team/wego/wegobackend/user/exception/NotFoundFollowException.java(1 hunks)src/main/java/team/wego/wegobackend/user/exception/SameUnFollowException.java(1 hunks)src/main/java/team/wego/wegobackend/user/presentation/UserController.java(1 hunks)src/main/java/team/wego/wegobackend/user/presentation/UserControllerDocs.java(1 hunks)src/main/java/team/wego/wegobackend/user/repository/FollowRepository.java(1 hunks)src/test/http/user/user-api.http(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/team/wego/wegobackend/user/application/FollowService.java (4)
src/main/java/team/wego/wegobackend/user/exception/ExistFollowException.java (1)
ExistFollowException(6-11)src/main/java/team/wego/wegobackend/user/exception/NotFoundFollowException.java (1)
NotFoundFollowException(6-11)src/main/java/team/wego/wegobackend/user/exception/SameFollowException.java (1)
SameFollowException(7-12)src/main/java/team/wego/wegobackend/user/exception/SameUnFollowException.java (1)
SameUnFollowException(6-11)
🔇 Additional comments (3)
src/main/java/team/wego/wegobackend/user/exception/SameUnFollowException.java (1)
1-11: 언팔로우 자기 자신 방지 예외 정의 좋습니다
SameFollowException과 대칭되는 전용 예외를 분리해 둔 점,AppErrorCode.NOT_SAME_UNFOLLOW와도 일관성이 있어 유지보수 측면에서 깔끔합니다.src/main/java/team/wego/wegobackend/user/exception/NotFoundFollowException.java (1)
1-11: 팔로우 관계 없음 전용 예외 정의 적절합니다팔로우 존재 여부 실패를
NotFoundFollowException으로 명확히 분리해 둔 덕분에 서비스 레이어에서 의도를 드러내기 좋고,AppErrorCode.NOT_FOUND_FOLLOW와도 잘 매핑되어 있습니다.src/main/java/team/wego/wegobackend/user/presentation/UserControllerDocs.java (1)
46-50: 팔로우 API 닉네임 설명 업데이트 적절합니다
followNickname쿼리 파라미터와 설명이 잘 맞춰져 있고, 기존 ID 기반 설명을 닉네임 기준으로 정리한 방향 좋습니다. 추가적인 변경 필요 없어 보입니다.
📝 Pull Request
📌 PR 종류
해당하는 항목에 체크해주세요.
✨ 변경 내용
팔로우 취소 API 개발
기존 팔로우 등록 API 엔티티 save 로직 추가 (이전 PR에서 누락)
🔍 관련 이슈
해당 PR이 해결하는 이슈가 있다면 연결해주세요.
Closes #61🧪 테스트
변경된 기능에 대한 테스트 범위 또는 테스트 결과를 작성해주세요.
Success
Fail
🚨 확인해야 할 사항 (Checklist)
PR을 제출하기 전에 아래 항목들을 확인해주세요.
🙋 기타 참고 사항
리뷰어가 참고하면 좋을 만한 추가 설명이 있다면 적어주세요.
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.