Skip to content

Conversation

@leesumin0526
Copy link
Collaborator

@leesumin0526 leesumin0526 commented Aug 15, 2025

PR 타입(하나 이상의 PR 타입을 선택해주세요)

  • 기능 추가
  • 기능 삭제
  • 버그 수정
  • 의존성, 환경 변수, 빌드 관련 코드 업데이트
  • 리팩터링

반영 브랜치

dev -> main

작업 내용

  • 투두 뱃지 수여 및 에러 조건 수정
  • 팟 이름 수정 API 개발

테스트 결과

스크린샷 2025-08-15 오후 3 21 07

Summary by CodeRabbit

  • New Features
    • 팟 이름 변경 엔드포인트 추가: PATCH /pots/{pot_id}/rename (소유자만 변경 가능)
  • Refactor
    • 배지 부여 기준 개선: 서로 다른 완료자 기준으로 상위 2명에게만 부여하며, 완료자 수가 2명 미만이면 부여되지 않음
    • 일부 날짜 필드가 문자열로 저장되도록 변경
  • Documentation
    • 특정 배지 API의 가능한 오류 코드 목록 정리
  • Style
    • 오류 메시지 문구 변경: "TODO를 완료한 사람이 2명 미만입니다. 최소 2명 이상이어야 합니다."

* [FEAT/##413]
- 투두 뱃지 제공 예외 처리 수정

* [FEAT/##413]
- 팟 이름 수정 API 개발
@leesumin0526 leesumin0526 self-assigned this Aug 15, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 15, 2025

Walkthrough

배지 선정 로직을 완료한 “서로 다른 사용자 수” 기준으로 개편하고 관련 리포지토리 쿼리를 페이징·카운트 기반으로 변경했습니다. Pot 이름 변경을 위한 PATCH 엔드포인트·DTO·서비스 구현과 Pot 엔터티의 setter가 추가되었고, 일부 DTO/서비스에서 날짜 타입이 String으로 변경되었습니다. 에러 메시지와 컨트롤러의 문서화된 에러 코드 일부가 수정되었습니다.

Changes

Cohort / File(s) Summary
배지 상위회원 선정 로직 갱신
src/main/java/stackpot/stackpot/badge/service/BadgeServiceImpl.java, src/main/java/stackpot/stackpot/todo/repository/UserTodoRepository.java, src/main/java/stackpot/stackpot/badge/controller/PotBadgeMemberController.java
상위 2명 선정을 전체 완료 Todo 수가 아닌 서로 다른 완료 사용자 수 기준으로 변경(완료 사용자 수 < 2 조기 종료). UserTodoRepository에 distinct 사용자 카운트·페이징 기반 top-user 쿼리 및 top2 기본메서드 추가, 기존 고정 top2 쿼리 제거. 컨트롤러의 ApiErrorCodeExamples에서 BADGE_NOT_FOUND 제거.
에러 메시지 수정
src/main/java/stackpot/stackpot/apiPayload/code/status/ErrorStatus.java
BADGE_INSUFFICIENT_TODO_COUNTS 메시지를 "TODO를 완료한 사람이 2명 미만입니다. 최소 2명 이상이어야 합니다."로 변경.
Pot 이름 변경 기능 추가
src/main/java/stackpot/stackpot/pot/controller/PotController.java, src/main/java/stackpot/stackpot/pot/service/pot/PotCommandService.java, src/main/java/stackpot/stackpot/pot/service/pot/PotCommandServiceImpl.java, src/main/java/stackpot/stackpot/pot/dto/PotNameUpdateRequestDto.java, src/main/java/stackpot/stackpot/pot/entity/Pot.java
PATCH /pots/{pot_id}/rename 엔드포인트 추가, PotNameUpdateRequestDto DTO 신설, PotCommandService/PotCommandServiceImplupdatePotName 도입(소유자 검증 포함), Pot 엔터티에 setPotName 추가.
날짜 표현을 String으로 변경(부분)
src/main/java/stackpot/stackpot/pot/dto/CompletedPotRequestDto.java, src/main/java/stackpot/stackpot/pot/service/pot/PotCommandServiceImpl.java
CompletedPotRequestDto.potStartDate 타입을 LocalDateString으로 변경. 서비스 내부에서 potEndDateLocalDate.now() 대신 String.valueOf(LocalDate.now())로 저장하도록 변경.
Pot 멤버 리포지토리 확장
src/main/java/stackpot/stackpot/pot/repository/PotMemberRepository.java
countByPot_PotId(Long potId) 추가. 기존 findByPot_PotIdAndUser_Id 서명은 동일하나 파일 내 위치 조정.
기타 리포지토리/엔티티 보조 변경
src/main/java/stackpot/stackpot/todo/repository/UserTodoRepository.java
deleteByPotId 추가 및 페이징 관련 import 추가.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PotController
  participant PotCommandServiceImpl
  participant AuthService
  participant PotRepository
  participant DB

  Client->>PotController: PATCH /pots/{id}/rename { potName }
  PotController->>PotCommandServiceImpl: updatePotName(id, request)
  PotCommandServiceImpl->>AuthService: getCurrentUser()
  PotCommandServiceImpl->>PotRepository: findById(id)
  PotRepository-->>PotCommandServiceImpl: Pot
  PotCommandServiceImpl->>PotCommandServiceImpl: 소유자 검증
  PotCommandServiceImpl->>DB: setPotName(...) 저장
  PotCommandServiceImpl-->>PotController: 새 이름(String)
  PotController-->>Client: ApiResponse<String>
Loading
sequenceDiagram
  participant Caller
  participant BadgeServiceImpl
  participant UserTodoRepository
  participant BadgeRepository
  participant PotMemberRepository
  participant PotMemberBadgeRepository

  Caller->>BadgeServiceImpl: assignBadgeToTopMembers(potId)
  BadgeServiceImpl->>UserTodoRepository: countDistinctUserIdsByPotAndStatus(potId, COMPLETED)
  UserTodoRepository-->>BadgeServiceImpl: completedUserCount
  alt completedUserCount < 2
    BadgeServiceImpl-->>Caller: throw BADGE_INSUFFICIENT_TODO_COUNTS
  else
    BadgeServiceImpl->>UserTodoRepository: findTop2UserIds(potId, COMPLETED)
    UserTodoRepository-->>BadgeServiceImpl: [userId1, userId2]
    BadgeServiceImpl->>BadgeRepository: getBadge(1L)
    loop for each userId
      BadgeServiceImpl->>PotMemberRepository: findByPot_PotIdAndUser_Id(potId, userId)
      PotMemberRepository-->>BadgeServiceImpl: PotMember
      BadgeServiceImpl->>PotMemberBadgeRepository: save(PotMemberBadge)
    end
    BadgeServiceImpl-->>Caller: 완료
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • Hyun0828

Poem

깡총깡총, 토끼가 말하네, 이름 한 자 바꿨다네 🐇
두 명 미만이면 멈춰서서 귀 기울이고
숫자 대신 이름으로 날짜를 속삭여주고
상위 둘에게 배지 퐁당, 발자국 남기며 달리고
깡총, 새 릴리즈에 당근 한 입 축하한다 ✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 662396e and c6f6521.

📒 Files selected for processing (1)
  • src/main/java/stackpot/stackpot/apiPayload/code/status/ErrorStatus.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/stackpot/stackpot/apiPayload/code/status/ErrorStatus.java
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

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 (6)
src/main/java/stackpot/stackpot/pot/entity/Pot.java (1)

41-43: potName에 대한 공개 Setter 도입은 도메인 무결성에 취약합니다. 접근 제한 또는 도메인 메서드로 캡슐화 제안

외부에서 무제한으로 이름을 변경할 수 있어 길이(255 초과), 공백/빈 문자열, 앞뒤 공백, 금칙어/중복명 검증 등을 우회할 수 있습니다. 최소한 접근 제어를 낮추거나, 유효성 검증을 포함한 도메인 메서드로 캡슐화하는 것을 권장합니다.

적용 예시(선택 1: 접근 제한):

-    @Setter
+    @Setter(AccessLevel.PROTECTED)
     @Column(nullable = false, length = 255)
     private String potName;

적용 예시(선택 2: 도메인 메서드 추가 — 해당 엔티티 내부에 추가, 서비스는 이 메서드를 사용):

public void rename(String newName) {
    if (newName == null || newName.isBlank()) {
        throw new IllegalArgumentException("팟 이름은 필수입니다.");
    }
    String trimmed = newName.trim();
    if (trimmed.length() > 255) {
        throw new IllegalArgumentException("팟 이름은 255자 이하여야 합니다.");
    }
    this.potName = trimmed;
}
src/main/java/stackpot/stackpot/pot/dto/CompletedPotRequestDto.java (1)

18-18: potStartDate를 String으로 변경 시 형식/필수값 검증이 누락되었습니다

엔티티는 potStartDate가 NOT NULL이며(컬럼 nullable=false), 주석상 형식은 “yyyy.MM”로 보입니다. 필수값과 형식 검증을 DTO에 추가하세요.

적용 예시:

 package stackpot.stackpot.pot.dto;

 import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Pattern;
 import lombok.Builder;
 import lombok.Getter;
 import lombok.Setter;

@@
-    private String potStartDate;
+    @NotBlank(message = "팟 시작일은 필수입니다.")
+    @Pattern(regexp = "^\\d{4}\\.\\d{2}$", message = "팟 시작일 형식은 yyyy.MM 이어야 합니다.")
+    private String potStartDate;

컨트롤러 메서드에 @Valid를 적용하여 검증을 활성화하는 것도 잊지 마세요.

src/main/java/stackpot/stackpot/pot/service/pot/PotCommandService.java (1)

24-24: API 일관성 고려: 반환 타입을 PotResponseDto 또는 void(204)로 통일하는 방안 검토

다른 메서드는 대부분 PotResponseDto를 반환합니다. 여기만 String(이름) 반환이라 클라이언트/스웨거 스키마 일관성이 떨어질 수 있습니다.

대안:

  • PotResponseDto 반환으로 통일하여 갱신된 엔티티 스냅샷 제공
  • 또는 204 No Content로 응답(비동기 UI라면 ETag 재조회 유도)
src/main/java/stackpot/stackpot/pot/repository/PotMemberRepository.java (1)

96-98: 중복/유사 Finder 정리 검토

동일 기능을 수행하는 findByPotIdAndUserId(Line 54-56, JPQL 기반)와 새 파생 메서드(findByPot_PotIdAndUser_Id)가 공존합니다. 팀 컨벤션에 맞춰 하나로 정리하거나, 기존 메서드에 @deprecated를 붙여 사용처를 이관하면 혼동을 줄일 수 있습니다.

src/main/java/stackpot/stackpot/pot/service/pot/PotCommandServiceImpl.java (1)

274-287: 팟 이름 업데이트 시 입력 정제(공백 트림) 권장

DTO의 Bean Validation이 있더라도, 서비스 단에서 최소한의 정제를 해두면 불필요한 공백 저장을 방지할 수 있습니다.

적용 제안:

-        pot.setPotName(request.getPotName());
+        // 선행 @Valid로 null/blank 방어가 된다는 전제에서 트림 적용
+        pot.setPotName(request.getPotName().trim());
src/main/java/stackpot/stackpot/todo/repository/UserTodoRepository.java (1)

41-51: 동률 시 결정적 순서 보장을 위한 보조 정렬 추가 제안

COUNT가 동일한 사용자가 여러 명일 때 결과 순서가 비결정적일 수 있습니다. 사용자 id 오름차순 등 보조 정렬 키를 추가해 안정성을 확보하는 것을 권장합니다.

적용 제안:

     @Query("""
         SELECT ut.user.id
         FROM UserTodo ut
         WHERE ut.pot.potId = :potId
           AND ut.status = :status
         GROUP BY ut.user.id
-        ORDER BY COUNT(ut.todoId) DESC
+        ORDER BY COUNT(ut.todoId) DESC, ut.user.id ASC
     """)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 26a6f9d and 662396e.

📒 Files selected for processing (11)
  • src/main/java/stackpot/stackpot/apiPayload/code/status/ErrorStatus.java (1 hunks)
  • src/main/java/stackpot/stackpot/badge/controller/PotBadgeMemberController.java (0 hunks)
  • src/main/java/stackpot/stackpot/badge/service/BadgeServiceImpl.java (1 hunks)
  • src/main/java/stackpot/stackpot/pot/controller/PotController.java (1 hunks)
  • src/main/java/stackpot/stackpot/pot/dto/CompletedPotRequestDto.java (1 hunks)
  • src/main/java/stackpot/stackpot/pot/dto/PotNameUpdateRequestDto.java (1 hunks)
  • src/main/java/stackpot/stackpot/pot/entity/Pot.java (1 hunks)
  • src/main/java/stackpot/stackpot/pot/repository/PotMemberRepository.java (1 hunks)
  • src/main/java/stackpot/stackpot/pot/service/pot/PotCommandService.java (2 hunks)
  • src/main/java/stackpot/stackpot/pot/service/pot/PotCommandServiceImpl.java (4 hunks)
  • src/main/java/stackpot/stackpot/todo/repository/UserTodoRepository.java (3 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/stackpot/stackpot/badge/controller/PotBadgeMemberController.java
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/stackpot/stackpot/pot/dto/PotNameUpdateRequestDto.java (2)
src/main/java/stackpot/stackpot/pot/dto/CompletedPotRequestDto.java (1)
  • Getter (10-24)
src/main/java/stackpot/stackpot/pot/dto/PotRequestDto.java (1)
  • Getter (13-42)
🔇 Additional comments (6)
src/main/java/stackpot/stackpot/pot/repository/PotMemberRepository.java (1)

96-98: 파생 쿼리 메서드 추가, 배지 로직 요구사항과 정합성 양호

countByPot_PotId, findByPot_PotIdAndUser_Id 모두 JPA 파생 쿼리 관례에 맞고, 상위 로직(배지 수여)에서 요구하는 데이터 접근 패턴을 충족합니다. 성능 및 가독성 측면에서도 적절합니다.

src/main/java/stackpot/stackpot/badge/service/BadgeServiceImpl.java (3)

45-47: 2인 이하 팟에 대한 Early Return 동작 확인 요청

멤버가 2명 이하인 경우 이제 아무 작업도 수행하지 않습니다. 이전에는 에러를 던졌다면 클라이언트/운영 관점 동작 변화가 생깁니다. 의도된 정책인지 최종 확인 부탁드립니다.


49-55: 서로 다른 완료 사용자 수 기반 선행 검증, 로직 적정

countDistinctUserIdsByPotAndStatus로 완료 사용자 수를 선행 검증하는 변경은 요구사항(“완료한 사용자 수” 기준)과 일치합니다.


58-62: 페이징 기반 Top2 조회로 확장성 확보

findTop2UserIds(페이징 래핑)로 상위 2명 조회를 수행하는 접근은 향후 Top N 확장에 유리합니다. 사이즈 < 2 시의 예외 처리도 타당합니다.

src/main/java/stackpot/stackpot/pot/service/pot/PotCommandServiceImpl.java (1)

195-202: 검증 결과 — potEndDate 타입 일관됨 (추가 수정 불필요)

Pot 엔티티의 potEndDate가 String으로 선언되어 있고 updateFields에서 (String)으로 할당하므로, PotCommandServiceImpl에서 String.valueOf(LocalDate.now())로 설정한 것은 타입 불일치가 아닙니다.

수정/검토한 위치:

  • src/main/java/stackpot/stackpot/pot/entity/Pot.java — private String potEndDate; 및 updateFields의 case "potEndDate" -> this.potEndDate = (String) value;
  • src/main/java/stackpot/stackpot/pot/service/pot/PotCommandServiceImpl.java — updateValues.put("potEndDate", String.valueOf(LocalDate.now()));
  • src/main/java/stackpot/stackpot/pot/dto/PotRequestDto.java, CompletedPotRequestDto.java 등 — potStartDate/potEndDate가 String으로 선언되어 있음
src/main/java/stackpot/stackpot/todo/repository/UserTodoRepository.java (1)

30-56: Distinct 집계 + 페이징 TopN 도입 적절

  • countDistinctUserIdsByPotAndStatus: “서로 다른 완료 사용자 수” 요구사항을 정확히 반영합니다.
  • findTopUserIdsByPotAndStatus + default findTop2UserIds: TopN 확장성 및 재사용성이 좋습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants