Skip to content

Conversation

@semsemin
Copy link
Collaborator

@semsemin semsemin commented May 18, 2025

이슈 번호

#8

작업 내용

  • 팔로우 api 구현
  • 언팔로우 api 구현
  • 나를 팔로우하는 사용자 목록 api 구현
  • 내가 팔로우하는 사용자 목록 조회 api 구현
  • MemberRepository에 이메일로 회원 정보 조회 코드 추가, jpa 확장
public interface MemberRepository extends JpaRepository<Member, Long> {
    Optional<Member> findByEmail(String email); // 이메일로 회원 조회
}
  • Member mock 데이터 추가 (mock > MemberTestDataInitializer.java)
  • 패키지명 java 관례에 따라 소문자로 통일 (fixlog)

기타

  • jwt 구현 전까지 요청자 이메일(requesterEmail)을 Param으로 임시 사용 -> 로그인 구현 후 수정

Summary by CodeRabbit

  • 신규 기능

    • 팔로우/언팔로우 기능이 추가되어, 사용자는 다른 회원을 팔로우하거나 언팔로우할 수 있습니다.
    • 내 팔로워 및 팔로잉 목록을 조회할 수 있는 API가 제공됩니다.
    • 팔로우/언팔로우 요청 및 응답을 위한 데이터 구조가 추가되었습니다.
  • 버그 수정

    • 패키지명 대소문자 일관성 문제를 수정하여, 일부 파일의 패키지명이 통일되었습니다.
  • 테스트

    • 테스트 데이터 자동 초기화 기능이 추가되어, 앱 시작 시 테스트 회원이 자동으로 생성됩니다.

@semsemin semsemin self-assigned this May 18, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 18, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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.

Walkthrough

이번 변경에서는 패키지명 대소문자 일관성 수정과 함께, 팔로우 기능의 전체적인 백엔드 구조가 추가되었습니다. 팔로우/언팔로우 요청 및 응답 DTO, 서비스, 컨트롤러, JPA 레포지토리 등이 새로 생성되었으며, 멤버 테스트 데이터 초기화 컴포넌트도 추가되었습니다. 일부 불필요한 빈 클래스는 삭제되었습니다.

Changes

파일/그룹 변경 요약
src/main/java/com/example/fixlog/* → src/main/java/com/example/fixLog/* 패키지명 대소문자(fixlogfixLog) 일관성 수정 (도메인, 엔티티, 애플리케이션, 예외, 테스트 등)
src/main/java/com/example/FixLog/repository/MemberRepository.java
src/main/java/com/example/fixLog/repository/MemberRepository.java
MemberRepository가 JPA 레포지토리로 변경 및 findByEmail 메소드 추가, 새 위치로 이동
src/main/java/com/example/fixLog/repository/follow/FollowRepository.java 팔로우 관계 관리용 JPA 레포지토리 신설 및 팔로우/언팔로우/조회 관련 메소드 추가
src/main/java/com/example/fixLog/dto/follow/request/FollowRequestDto.java
src/main/java/com/example/fixLog/dto/follow/request/UnfollowRequestDto.java
팔로우/언팔로우 요청 DTO 신설
src/main/java/com/example/fixLog/dto/follow/response/FollowResponseDto.java
src/main/java/com/example/fixLog/dto/follow/response/FollowerListResponseDto.java
src/main/java/com/example/fixLog/dto/follow/response/FollowingListResponseDto.java
팔로우/팔로워/팔로잉 응답 DTO 신설
src/main/java/com/example/fixLog/controller/follow/FollowController.java 팔로우 관련 REST API 컨트롤러 신설(팔로우/언팔로우/팔로워/팔로잉 목록 조회)
src/main/java/com/example/fixLog/service/follow/FollowService.java 팔로우 비즈니스 로직 서비스 신설(팔로우, 언팔로우, 목록 조회 등)
src/main/java/com/example/fixLog/mock/MemberTestDataInitializer.java 멤버 테스트 데이터 초기화 컴포넌트 신설
src/main/java/com/example/FixLog/controller/MemberController.java
src/main/java/com/example/FixLog/service/MemberService.java
빈 클래스 삭제
src/main/java/com/example/fixLog/controller/MemberController.java
src/main/java/com/example/fixLog/service/MemberService.java
빈 클래스 새로 생성(이동)

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant FollowController
    participant FollowService
    participant MemberRepository
    participant FollowRepository

    Client->>FollowController: POST /follow (FollowRequestDto, requesterEmail)
    FollowController->>FollowService: follow(requesterEmail, targetMemberId)
    FollowService->>MemberRepository: findByEmail(requesterEmail)
    MemberRepository-->>FollowService: Optional<Member>
    FollowService->>MemberRepository: findById(targetMemberId)
    MemberRepository-->>FollowService: Optional<Member>
    FollowService->>FollowRepository: existsByFollowerAndFollowing(follower, following)
    FollowRepository-->>FollowService: boolean
    FollowService->>FollowRepository: save(new Follow)
    FollowRepository-->>FollowService: Follow
    FollowService-->>FollowController: FollowResponseDto
    FollowController-->>Client: Response<FollowResponseDto>
Loading
sequenceDiagram
    participant Client
    participant FollowController
    participant FollowService
    participant MemberRepository
    participant FollowRepository

    Client->>FollowController: POST /follow/unfollow (UnfollowRequestDto, requesterEmail)
    FollowController->>FollowService: unfollow(requesterEmail, targetMemberId)
    FollowService->>MemberRepository: findByEmail(requesterEmail)
    MemberRepository-->>FollowService: Optional<Member>
    FollowService->>MemberRepository: findById(targetMemberId)
    MemberRepository-->>FollowService: Optional<Member>
    FollowService->>FollowRepository: findByFollowerAndFollowing(follower, following)
    FollowRepository-->>FollowService: Optional<Follow>
    FollowService->>FollowRepository: delete(follow)
    FollowRepository-->>FollowService: void
    FollowService-->>FollowController: void
    FollowController-->>Client: Response<Void>
Loading

Poem

🐰
팔로우 토끼, 깡총깡총 뛰며
새 컨트롤러와 서비스로 길을 내요.
친구를 찾고, 언팔로우도 척척,
DTO 바구니에 응답을 담아.
대소문자도 맞추니, 프로젝트가 반짝!
오늘도 즐거운 코드의 숲 속에서,
토끼는 행복하게 PR을 마무리해요. 🌱

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.

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.

@semsemin
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 18, 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
Contributor

@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 (8)
src/main/java/com/example/fixlog/domain/member/Member.java (1)

11-11: 동일 패키지 내 임포트 구문이 필요한지 검토해주세요.

SocialTypeMember 클래스와 동일한 패키지(com.example.fixlog.domain.member)에 있으므로 명시적인 임포트가 필요하지 않습니다. 동일 패키지 내 클래스는 자동으로 임포트되기 때문입니다.

-import com.example.fixlog.domain.member.SocialType;
src/main/java/com/example/FixLog/mock/MemberTestDataInitializer.java (1)

20-25: 테스트 데이터 초기화 로직이 잘 구현되었습니다.

애플리케이션 실행 시 회원 데이터가 없을 때만 테스트 데이터를 생성하는 로직이 적절합니다. 다만, 민감한 정보(비밀번호)가 하드코딩되어 있으므로 실제 프로덕션 환경에서는 제거하거나 암호화된 값으로 대체하는 것이 좋습니다.

시스템 출력 메시지는 로깅 프레임워크를 사용하는 것이 좋습니다:

-            System.out.println("테스트용 멤버 2명 삽입 완료");
+            log.info("테스트용 멤버 2명 삽입 완료");

클래스에 @Slf4j 어노테이션을 추가하거나 로거를 직접 선언하여 사용하세요.

src/main/java/com/example/FixLog/dto/follow/request/UnfollowRequestDto.java (2)

7-12: 필드 설명 주석이 누락되었습니다.

DTO 구현은 적절하지만, FollowRequestDto에는 있는 필드 설명 주석이 이 클래스에는 누락되어 있습니다. 코드 일관성을 위해 주석을 추가하는 것이 좋겠습니다.

@JsonProperty("target_member_id")
-private Long targetMemberId;
+private Long targetMemberId;  // 언팔로우 대상 ID

1-12: 코드 중복 고려사항

FollowRequestDtoUnfollowRequestDto가 동일한 구조를 가지고 있습니다. 코드 중복을 줄이기 위해 상위 클래스를 만들거나, 하나의 클래스로 통합하는 것을 고려해볼 수 있습니다. 이렇게 하면 향후 필드 변경 시 일관성을 유지하기 쉽습니다.

// 예시: 공통 상위 클래스 생성
@Getter
@NoArgsConstructor
public abstract class MemberTargetRequestDto {
    @JsonProperty("target_member_id")
    private Long targetMemberId;  // 대상 회원 ID
}

// 이후 상속
public class FollowRequestDto extends MemberTargetRequestDto {
}

public class UnfollowRequestDto extends MemberTargetRequestDto {
}
src/main/java/com/example/FixLog/dto/follow/response/FollowingListResponseDto.java (1)

7-17: 필드 설명 주석 추가 권장

DTO 설계가 적절하며 필요한 어노테이션이 잘 적용되어 있습니다. 그러나 각 필드의 의미를 명확히 하기 위해 FollowRequestDto처럼 한글 주석을 추가하는 것이 코드 가독성과 유지보수성을 높일 수 있습니다.

@JsonProperty("follow_id")
-private Long followId;
+private Long followId;  // 팔로우 관계 ID

@JsonProperty("following_id")
-private Long followingId;
+private Long followingId;  // 팔로잉 대상 ID

-private String nickname;
+private String nickname;  // 팔로잉 대상 닉네임
src/main/java/com/example/FixLog/service/follow/FollowService.java (2)

47-65: 언팔로우 로직 개선 가능

언팔로우 기능이 적절히 구현되었습니다. 다만, 자기 자신 팔로우 불가 체크 로직은 이미 팔로우 관계가 존재하지 않을 것이므로 불필요할 수 있습니다.

자기 자신 팔로우 불가 체크 로직을 제거하는 것을 고려해보세요:

    @Transactional
    public void unfollow(String requesterEmail, Long targetMemberId) {
        Member follower = memberRepository.findByEmail(requesterEmail)
                .orElseThrow(() -> new IllegalArgumentException("요청자 회원 없음"));

        Member following = memberRepository.findById(targetMemberId)
                .orElseThrow(() -> new IllegalArgumentException("언팔로우 대상 없음"));

-        // 자기 자신은 팔로우 불가
-        if (follower.getId().equals(following.getId())) {
-            throw new IllegalArgumentException("자기 자신은 팔로우할 수 없음");
-        }

        Follow follow = followRepository.findByFollowerAndFollowing(follower, following)
                .orElseThrow(() -> new IllegalArgumentException("팔로우 관계가 존재하지 않음"));

        followRepository.delete(follow);
    }

16-22: 에러 메시지 일관성 개선 필요

서비스 내 에러 메시지가 일관되지 않습니다. 일부는 "회원 정보가 없음", 다른 곳은 "요청자 회원 없음" 등으로 다르게 표현됩니다.

에러 메시지를 일관되게 수정하는 것을 권장합니다:

    @Transactional
    public FollowResponseDto follow(String requesterEmail, Long targetMemberId){
        Member follower = memberRepository.findByEmail(requesterEmail)
-                .orElseThrow(() -> new IllegalArgumentException("회원 정보가 없음"));
+                .orElseThrow(() -> new IllegalArgumentException("요청자 회원 없음"));
        Member following = memberRepository.findById(targetMemberId)
                .orElseThrow(() -> new IllegalArgumentException("팔로우 대상 없음"));
src/main/java/com/example/FixLog/controller/follow/FollowController.java (1)

32-40: 언팔로우 엔드포인트 RESTful 디자인 개선 가능

언팔로우 기능이 POST 메소드로 구현되어 있습니다. 보다 RESTful한 접근법은 DELETE 메소드를 사용하는 것입니다.

다음과 같이 변경을 고려해보세요:

-    @PostMapping("/unfollow")
-    public ResponseEntity<Response<Void>> unfollow(
-            @RequestBody UnfollowRequestDto requestDto,
-            @RequestParam String requesterEmail) {
+    @DeleteMapping("/{targetMemberId}")
+    public ResponseEntity<Response<Void>> unfollow(
+            @PathVariable Long targetMemberId,
+            @RequestParam String requesterEmail) {

-        followService.unfollow(requesterEmail, requestDto.getTargetMemberId());
+        followService.unfollow(requesterEmail, targetMemberId);
         return ResponseEntity.ok(Response.success("언팔로우 완료", null));
     }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 4f2e4ef and dfc7359.

📒 Files selected for processing (12)
  • src/main/java/com/example/FixLog/controller/follow/FollowController.java (1 hunks)
  • src/main/java/com/example/FixLog/dto/follow/request/FollowRequestDto.java (1 hunks)
  • src/main/java/com/example/FixLog/dto/follow/request/UnfollowRequestDto.java (1 hunks)
  • src/main/java/com/example/FixLog/dto/follow/response/FollowResponseDto.java (1 hunks)
  • src/main/java/com/example/FixLog/dto/follow/response/FollowerListResponseDto.java (1 hunks)
  • src/main/java/com/example/FixLog/dto/follow/response/FollowingListResponseDto.java (1 hunks)
  • src/main/java/com/example/FixLog/mock/MemberTestDataInitializer.java (1 hunks)
  • src/main/java/com/example/FixLog/repository/MemberRepository.java (1 hunks)
  • src/main/java/com/example/FixLog/repository/follow/FollowRepository.java (1 hunks)
  • src/main/java/com/example/FixLog/service/follow/FollowService.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/follow/Follow.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/member/Member.java (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/main/java/com/example/FixLog/dto/follow/request/FollowRequestDto.java (1)
src/main/java/com/example/FixLog/dto/follow/response/FollowResponseDto.java (1)
  • Getter (7-17)
src/main/java/com/example/FixLog/dto/follow/response/FollowResponseDto.java (1)
src/main/java/com/example/FixLog/dto/follow/request/FollowRequestDto.java (1)
  • Getter (7-12)
🔇 Additional comments (13)
src/main/java/com/example/fixlog/domain/follow/Follow.java (1)

27-30: 생성자 추가가 잘 되었습니다!

followerfollowing을 초기화하는 생성자가 적절하게 구현되었습니다. 이 생성자는 팔로우 관계를 생성할 때 필요한 필수 관계를 명확하게 설정합니다.

src/main/java/com/example/FixLog/dto/follow/request/FollowRequestDto.java (1)

7-12: DTO 구현이 간결하고 명확합니다.

DTO 클래스가 적절히 설계되었으며, Lombok 어노테이션(@Getter, @NoArgsConstructor)과 JSON 매핑을 위한 어노테이션(@JsonProperty)을 올바르게 사용하고 있습니다. 필드에 한글 주석을 추가한 점도 좋습니다.

src/main/java/com/example/FixLog/repository/follow/FollowRepository.java (1)

10-15: 리포지토리 메서드 구현이 명확하고 주석이 유용합니다.

JpaRepository를 확장하여 필요한 메서드들이 잘 정의되어 있습니다. 각 메서드의 목적을 설명하는 한글 주석이 이해를 돕습니다. 메서드 명명 규칙도 Spring Data JPA 관행을 잘 따르고 있습니다.

src/main/java/com/example/FixLog/dto/follow/response/FollowingListResponseDto.java (1)

7-17: 응답 DTO 구조가 적절합니다.

FollowingListResponseDto 클래스는 팔로잉 목록을 조회하는 API의 응답으로 적합한 구조로 설계되었습니다. @Getter@AllArgsConstructor 어노테이션이 적절히 사용되었고, JSON 직렬화를 위한 @JsonProperty 어노테이션도 잘 적용되었습니다.

src/main/java/com/example/FixLog/dto/follow/response/FollowResponseDto.java (1)

1-17: 잘 구현된 응답 DTO

응답 DTO가 적절히 구현되었습니다. Lombok 어노테이션을 사용하여 불필요한 보일러플레이트 코드를 줄이고, JSON 직렬화를 위해 @JsonProperty를 적절히 사용했습니다.

src/main/java/com/example/FixLog/dto/follow/response/FollowerListResponseDto.java (1)

1-17: 응답 DTO 구조 적절

팔로워 목록 응답 DTO가 적절히 구현되었습니다. 필드명과 JSON 프로퍼티 이름이 일관되게 작성되었습니다.

src/main/java/com/example/FixLog/service/follow/FollowService.java (3)

23-45: 팔로우 기능 로직 검증

팔로우 기능이 적절히 구현되었습니다. 자기 자신 팔로우 방지, 중복 팔로우 방지 등의 검증 로직이 포함되어 있습니다.


67-82: 팔로워 목록 조회 기능 적절

팔로워 목록 조회 기능이 적절히 구현되었습니다. 읽기 전용 트랜잭션을 사용하여 성능을 최적화했습니다.


84-99: 팔로잉 목록 조회 기능 적절

팔로잉 목록 조회 기능이 적절히 구현되었습니다. 스트림 API를 활용하여 코드가 간결하게 작성되었습니다.

src/main/java/com/example/FixLog/controller/follow/FollowController.java (4)

22-30: 팔로우 엔드포인트 적절

팔로우 기능 엔드포인트가 적절히 구현되었습니다. 표준화된 응답 형식을 사용하여 일관성 있는 API를 제공합니다.


42-49: 팔로워 목록 조회 엔드포인트 적절

팔로워 목록 조회 엔드포인트가 적절히 구현되었습니다. GET 메소드를 사용하여 조회 작업을 처리합니다.


51-58: 팔로잉 목록 조회 엔드포인트 적절

팔로잉 목록 조회 엔드포인트가 적절히 구현되었습니다. 응답 메시지가 명확합니다.


25-27: 인증 구현 계획 적절

JWT 인증 구현 전까지 임시로 requesterEmail 파라미터를 사용하는 접근은 적절합니다. 주석에서 향후 AuthenticationPrincipal로 대체할 계획을 명시한 것도 좋습니다.

@semsemin
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 18, 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
Contributor

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

🧹 Nitpick comments (3)
src/main/java/com/example/FixLog/service/follow/FollowService.java (3)

1-1: 패키지명은 소문자를 사용해주세요

Java 패키지명은 관례적으로 전부 소문자를 사용합니다. 대문자가 섞이면 IDE 탐색·배포 스크립트에서 의도치 않은 충돌이 발생할 수 있습니다.
예) com.example.fixlog.service.follow


56-60: 자기 자신 체크 로직 중복

follow()·unfollow() 모두 동일한 “자기 자신” 검사 로직을 갖고 있습니다. private 메서드로 추출하면 가독성과 유지보수가 향상됩니다.


86-99: 응답 정렬·페이징 없음

팔로잉 수가 많을 때 무작위 순서로 전부 반환하면 클라이언트 UX 저하 및 트래픽 과다 유발 가능성이 있습니다.
order by follow.id descPage<…> 반환을 권장합니다.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between dfc7359 and e7c7275.

📒 Files selected for processing (19)
  • src/main/java/com/example/FixLog/mock/MemberTestDataInitializer.java (1 hunks)
  • src/main/java/com/example/FixLog/repository/MemberRepository.java (1 hunks)
  • src/main/java/com/example/FixLog/repository/follow/FollowRepository.java (1 hunks)
  • src/main/java/com/example/FixLog/service/follow/FollowService.java (1 hunks)
  • src/main/java/com/example/fixlog/FixLogApplication.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/bookmark/BookmarkTag.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/bookmark/BookmarkTagMap.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/follow/Follow.java (2 hunks)
  • src/main/java/com/example/fixlog/domain/fork/Fork.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/like/PostLike.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/member/Member.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/member/SocialType.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/post/Post.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/post/PostImage.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/post/PostTag.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/tag/Tag.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/tag/TagCategory.java (1 hunks)
  • src/test/java/com/example/FixLog/FixLogApplicationTests.java (1 hunks)
✅ Files skipped from review due to trivial changes (13)
  • src/main/java/com/example/fixlog/domain/post/PostImage.java
  • src/main/java/com/example/fixlog/FixLogApplication.java
  • src/main/java/com/example/fixlog/domain/tag/Tag.java
  • src/main/java/com/example/fixlog/domain/bookmark/BookmarkTagMap.java
  • src/test/java/com/example/FixLog/FixLogApplicationTests.java
  • src/main/java/com/example/fixlog/domain/like/PostLike.java
  • src/main/java/com/example/fixlog/domain/post/Post.java
  • src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java
  • src/main/java/com/example/fixlog/domain/member/SocialType.java
  • src/main/java/com/example/fixlog/domain/post/PostTag.java
  • src/main/java/com/example/fixlog/domain/bookmark/BookmarkTag.java
  • src/main/java/com/example/fixlog/domain/fork/Fork.java
  • src/main/java/com/example/fixlog/domain/tag/TagCategory.java
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/main/java/com/example/fixlog/domain/member/Member.java
  • src/main/java/com/example/fixlog/domain/follow/Follow.java
  • src/main/java/com/example/FixLog/mock/MemberTestDataInitializer.java
  • src/main/java/com/example/FixLog/repository/follow/FollowRepository.java
  • src/main/java/com/example/FixLog/repository/MemberRepository.java

@semsemin
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 18, 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.

coderabbitai[bot]
coderabbitai bot previously requested changes May 18, 2025
Copy link
Contributor

@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 (11)
src/main/java/com/example/fixLog/mock/MemberTestDataInitializer.java (1)

1-27: 코드는 기본 기능을 충실히 수행하지만 몇 가지 개선 사항이 있습니다.

테스트 데이터 초기화 로직이 잘 구현되어 있으나, 다음과 같은 개선 사항을 고려해보세요:

  1. System.out.println 대신 로깅 프레임워크(SLF4J) 사용
  2. 개발/테스트 환경에서만 활성화되도록 @Profile 어노테이션 추가
  3. 다양한 SocialType을 가진 테스트 데이터 제공
package com.example.fixLog.mock;

import com.example.fixLog.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import com.example.fixLog.domain.member.Member;
import com.example.fixLog.domain.member.SocialType;
+import lombok.extern.slf4j.Slf4j;

import java.util.List;

+@Slf4j
+@Profile({"dev", "test"})
@Component
@RequiredArgsConstructor
public class MemberTestDataInitializer implements CommandLineRunner {

    private final MemberRepository memberRepository;

    @Override
    public void run(String... args) {
        if (memberRepository.count() == 0) {
            Member member1 = Member.of("[email protected]", "1234", "가나다", SocialType.EMAIL);
            Member member2 = Member.of("[email protected]", "1234", "라마바", SocialType.EMAIL);
+           Member member3 = Member.of("[email protected]", "1234", "사아자", SocialType.KAKAO);
-           memberRepository.saveAll(List.of(member1, member2));
-           System.out.println("테스트용 멤버 2명 삽입 완료");
+           memberRepository.saveAll(List.of(member1, member2, member3));
+           log.info("테스트용 멤버 3명 삽입 완료");
        }
    }
}
src/main/java/com/example/fixLog/repository/MemberRepository.java (1)

1-10: 기본 구현이 잘 되어 있습니다.

Spring Data JPA 규칙에 맞게 잘 구현되어 있습니다. 추가 개선 사항으로 이메일 대소문자 무시 옵션과 중복 이메일 검증 메서드를 고려해볼 수 있습니다.

package com.example.fixLog.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.example.fixLog.domain.member.Member;

import java.util.Optional;

public interface MemberRepository extends JpaRepository<Member, Long> {
    Optional<Member> findByEmail(String email); // 이메일로 회원 조회
+   Optional<Member> findByEmailIgnoreCase(String email); // 대소문자 구분없이 이메일로 회원 조회
+   boolean existsByEmail(String email); // 이메일 중복 확인
}
src/main/java/com/example/fixLog/repository/follow/FollowRepository.java (1)

1-15: Repository 인터페이스가 잘 설계되어 있습니다.

팔로우 기능에 필요한 핵심 메서드들이 잘 정의되어 있습니다. 다만 데이터가 많아질 경우를 대비한 페이징 처리 메서드 추가를 고려해보세요.

package com.example.fixLog.repository.follow;

import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
import com.example.fixLog.domain.follow.Follow;
import com.example.fixLog.domain.member.Member;

import java.util.List;
import java.util.Optional;

public interface FollowRepository extends JpaRepository<Follow, Long> {
    boolean existsByFollowerAndFollowing(Member follower, Member following); // 중복 방지 - 같은 사람 다시 팔로우
    Optional<Follow> findByFollowerAndFollowing(Member follower, Member following); // 팔로우 관계 조회
    List<Follow> findByFollowing(Member following); // 나를 팔로우하는 사용자 조회 (팔로워들)
    List<Follow> findByFollower(Member follower); // 내가 팔로우하는 사용자 조회 (팔로잉들)
+   Page<Follow> findByFollowing(Member following, Pageable pageable); // 페이징된 팔로워 목록
+   Page<Follow> findByFollower(Member follower, Pageable pageable); // 페이징된 팔로잉 목록
}
src/main/java/com/example/fixLog/service/follow/FollowService.java (2)

67-82: 팔로워 목록 조회 로직이 잘 구현되어 있습니다.

팔로워 목록 조회 로직이 잘 구현되어 있으나, 대용량 데이터 처리를 위한 페이징 적용을 고려해보세요.

    // 나를 팔로우하는 목록 조회 (팔로워들)
    @Transactional(readOnly = true)
    public List<FollowerListResponseDto> getMyFollowers(String requesterEmail) {
        Member me = memberRepository.findByEmail(requesterEmail)
                .orElseThrow(() -> new IllegalArgumentException("요청자 정보를 찾을 수 없음"));

        List<Follow> follows = followRepository.findByFollowing(me);

        return follows.stream()
                .map(follow -> new FollowerListResponseDto(
                        follow.getId(),
                        follow.getFollower().getId(),
                        follow.getFollower().getNickname()
                ))
                .toList();
    }
+   
+   // 페이징을 적용한 팔로워 목록 조회
+   @Transactional(readOnly = true)
+   public Page<FollowerListResponseDto> getMyFollowersWithPaging(String requesterEmail, Pageable pageable) {
+       Member me = memberRepository.findByEmail(requesterEmail)
+               .orElseThrow(() -> new IllegalArgumentException("요청자 정보를 찾을 수 없음"));
+       
+       Page<Follow> follows = followRepository.findByFollowing(me, pageable);
+       
+       return follows.map(follow -> new FollowerListResponseDto(
+               follow.getId(),
+               follow.getFollower().getId(),
+               follow.getFollower().getNickname()
+       ));
+   }

84-99: 팔로잉 목록 조회 로직이 잘 구현되어 있습니다.

팔로잉 목록 조회 로직이 잘 구현되어 있으나, 팔로워 목록과 마찬가지로 페이징 적용을 고려해보세요.

페이징 처리와 중복 코드 추출을 통한 코드 개선을 권장합니다. 앞서 제안된 리팩토링과 유사한 방식으로 팔로잉 목록에도 페이징 기능을 추가하세요.

src/main/java/com/example/fixLog/controller/follow/FollowController.java (6)

22-30: 팔로우 API 구현이 적절합니다만, 201 상태 코드 사용을 고려해 보세요.

팔로우 기능은 새로운 리소스(팔로우 관계)를 생성하는 작업이므로, HTTP 상태 코드 200 보다는 201(Created)이 더 적합할 수 있습니다.

-        return ResponseEntity.ok(Response.success("팔로우 완료", result));
+        return ResponseEntity.status(201).body(Response.success("팔로우 완료", result));

32-40: 언팔로우 API의 HTTP 메서드를 고려해 보세요.

REST 원칙에 따르면 리소스 삭제는 DELETE 메서드를 사용하는 것이 더 적합합니다. 언팔로우는 팔로우 관계를 삭제하는 작업이므로 POST보다 DELETE가 의미적으로 더 맞을 수 있습니다.

-    @PostMapping("/unfollow")
+    @DeleteMapping("/unfollow")

36-38: 불필요한 빈 줄이 있습니다.

37번 줄의 빈 줄은 필요하지 않으므로 제거하는 것이 좋겠습니다.

    public ResponseEntity<Response<Void>> unfollow(
            @RequestBody UnfollowRequestDto requestDto,
            @RequestParam String requesterEmail) {
-
        followService.unfollow(requesterEmail, requestDto.getTargetMemberId());
        return ResponseEntity.ok(Response.success("언팔로우 완료", null));
    }

42-49: 팔로워 목록 조회 API에 불필요한 빈 줄이 있습니다.

46번 줄의 빈 줄은 필요하지 않으므로 제거하는 것이 좋겠습니다.

    @GetMapping("/followers")
    public ResponseEntity<Response<List<FollowerListResponseDto>>> getMyFollowers(
            @RequestParam String requesterEmail) {
-
        List<FollowerListResponseDto> followers = followService.getMyFollowers(requesterEmail);
        return ResponseEntity.ok(Response.success("나를 팔로우하는 목록 조회 성공", followers));
    }

51-58: 팔로잉 목록 조회 API에 불필요한 빈 줄이 있습니다.

55번 줄의 빈 줄은 필요하지 않으므로 제거하는 것이 좋겠습니다.

    @GetMapping("/followings")
    public ResponseEntity<Response<List<FollowingListResponseDto>>> getMyFollowings(
            @RequestParam String requesterEmail) {
-
        List<FollowingListResponseDto> followings = followService.getMyFollowings(requesterEmail);
        return ResponseEntity.ok(Response.success("내가 팔로우 중인 목록 조회 성공", followings));
    }

1-59: API 문서화를 위한 주석이나 어노테이션이 부족합니다.

코드 가독성과 API 문서화를 위해 Swagger/OpenAPI 어노테이션(예: @operation, @apiresponse 등)을 추가하거나, 각 메서드에 javadoc 형식의 주석을 추가하는 것이 좋습니다. 이는 다른 개발자들이 API를 이해하고 사용하는 데 도움이 됩니다.

/**
 * 사용자를 팔로우합니다.
 * 
 * @param followRequestDto 팔로우할 대상 사용자 ID를 포함한 요청 DTO
 * @param requesterEmail 요청자 이메일 (임시, JWT 구현 후 제거 예정)
 * @return 팔로우 성공 응답
 */
@PostMapping
public ResponseEntity<Response<FollowResponseDto>> follow(...)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e7c7275 and 5f20b7a.

📒 Files selected for processing (33)
  • src/main/java/com/example/FixLog/controller/MemberController.java (0 hunks)
  • src/main/java/com/example/FixLog/service/MemberService.java (0 hunks)
  • src/main/java/com/example/fixLog/controller/MemberController.java (1 hunks)
  • src/main/java/com/example/fixLog/controller/follow/FollowController.java (1 hunks)
  • src/main/java/com/example/fixLog/dto/Response.java (1 hunks)
  • src/main/java/com/example/fixLog/dto/follow/request/FollowRequestDto.java (1 hunks)
  • src/main/java/com/example/fixLog/dto/follow/request/UnfollowRequestDto.java (1 hunks)
  • src/main/java/com/example/fixLog/dto/follow/response/FollowResponseDto.java (1 hunks)
  • src/main/java/com/example/fixLog/dto/follow/response/FollowerListResponseDto.java (1 hunks)
  • src/main/java/com/example/fixLog/dto/follow/response/FollowingListResponseDto.java (1 hunks)
  • src/main/java/com/example/fixLog/exception/CustomException.java (1 hunks)
  • src/main/java/com/example/fixLog/exception/ErrorCode.java (1 hunks)
  • src/main/java/com/example/fixLog/exception/GlobalExceptionHandler.java (1 hunks)
  • src/main/java/com/example/fixLog/mock/MemberTestDataInitializer.java (1 hunks)
  • src/main/java/com/example/fixLog/repository/MemberRepository.java (1 hunks)
  • src/main/java/com/example/fixLog/repository/follow/FollowRepository.java (1 hunks)
  • src/main/java/com/example/fixLog/service/MemberService.java (1 hunks)
  • src/main/java/com/example/fixLog/service/follow/FollowService.java (1 hunks)
  • src/main/java/com/example/fixlog/FixLogApplication.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/bookmark/BookmarkTag.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/bookmark/BookmarkTagMap.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/follow/Follow.java (2 hunks)
  • src/main/java/com/example/fixlog/domain/fork/Fork.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/like/PostLike.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/member/Member.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/member/SocialType.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/post/Post.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/post/PostImage.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/post/PostTag.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/tag/Tag.java (1 hunks)
  • src/main/java/com/example/fixlog/domain/tag/TagCategory.java (1 hunks)
  • src/test/java/com/example/fixLog/FixLogApplicationTests.java (1 hunks)
💤 Files with no reviewable changes (2)
  • src/main/java/com/example/FixLog/service/MemberService.java
  • src/main/java/com/example/FixLog/controller/MemberController.java
✅ Files skipped from review due to trivial changes (13)
  • src/test/java/com/example/fixLog/FixLogApplicationTests.java
  • src/main/java/com/example/fixLog/exception/ErrorCode.java
  • src/main/java/com/example/fixlog/domain/tag/Tag.java
  • src/main/java/com/example/fixLog/exception/CustomException.java
  • src/main/java/com/example/fixLog/dto/Response.java
  • src/main/java/com/example/fixLog/controller/MemberController.java
  • src/main/java/com/example/fixLog/service/MemberService.java
  • src/main/java/com/example/fixLog/exception/GlobalExceptionHandler.java
  • src/main/java/com/example/fixLog/dto/follow/response/FollowingListResponseDto.java
  • src/main/java/com/example/fixLog/dto/follow/request/UnfollowRequestDto.java
  • src/main/java/com/example/fixLog/dto/follow/response/FollowerListResponseDto.java
  • src/main/java/com/example/fixLog/dto/follow/request/FollowRequestDto.java
  • src/main/java/com/example/fixLog/dto/follow/response/FollowResponseDto.java
🚧 Files skipped from review as they are similar to previous changes (13)
  • src/main/java/com/example/fixlog/domain/member/Member.java
  • src/main/java/com/example/fixlog/domain/post/PostTag.java
  • src/main/java/com/example/fixlog/domain/member/SocialType.java
  • src/main/java/com/example/fixlog/FixLogApplication.java
  • src/main/java/com/example/fixlog/domain/post/Post.java
  • src/main/java/com/example/fixlog/domain/post/PostImage.java
  • src/main/java/com/example/fixlog/domain/bookmark/BookmarkTagMap.java
  • src/main/java/com/example/fixlog/domain/like/PostLike.java
  • src/main/java/com/example/fixlog/domain/fork/Fork.java
  • src/main/java/com/example/fixlog/domain/follow/Follow.java
  • src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java
  • src/main/java/com/example/fixlog/domain/tag/TagCategory.java
  • src/main/java/com/example/fixlog/domain/bookmark/BookmarkTag.java
🔇 Additional comments (3)
src/main/java/com/example/fixLog/service/follow/FollowService.java (1)

24-45: 팔로우 로직이 잘 구현되었습니다.

팔로우 로직에 필요한 검증이 잘 구현되어 있습니다. 자기 자신 팔로우 방지와 중복 팔로우 방지 등 적절한 예외 처리가 되어 있습니다.

src/main/java/com/example/fixLog/controller/follow/FollowController.java (2)

1-19: 컨트롤러 선언과 구조가 잘 정의되었습니다.

컨트롤러 클래스의 전반적인 구조와 의존성 주입 방식이 Spring 권장 사항을 잘 따르고 있습니다. @RequiredArgsConstructor를 통한 생성자 주입 패턴이 적절히 사용되었습니다.


26-26: 인증 메커니즘 관련 주석이 명확합니다.

JWT 구현 전까지 임시로 이메일 파라미터를 사용한다는 주석은 명확하게 작성되었습니다. 보안을 위해 JWT 구현 후에는 반드시 이 부분을 변경해야 합니다.

…java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@FixLog FixLog deleted a comment from coderabbitai bot May 18, 2025
@FixLog FixLog deleted a comment from coderabbitai bot May 18, 2025
Copy link
Member

@sungchaewon sungchaewon left a comment

Choose a reason for hiding this comment

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

영서님께서 남기신 부분 작동만 잘 되면 문제 없을 것 같습니다! 고생하셨습니다!!

@semsemin
Copy link
Collaborator Author

  • responsedata 필드 null 일 경우 출력 x

@semsemin semsemin merged commit 3a0ed94 into develop May 21, 2025
1 check passed
@semsemin semsemin deleted the feature/#8-follow-sm branch May 21, 2025 10:02
@semsemin semsemin added the ♻️ refactoring 전면 수정 label May 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

♻️ refactoring 전면 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants