-
Notifications
You must be signed in to change notification settings - Fork 3
[Feat/#423] api 수정 #425
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feat/#423] api 수정 #425
Conversation
Walkthrough의존성에서 Actuator를 제거하고 Hibernate/JPA를 추가했다. 트랜잭션 애노테이션을 Jakarta에서 Spring으로 교체했다. PotSummaryDto에 potName과 isMember 필드를 추가하고 PotConverter 시그니처를 확장했다. PotMember 매핑 로직을 수정했다. MyPotService에 사용자별 어필 조회를 추가하고 위임 변경 로직을 보강했다. UserController에 새로운 경로로 사용자별 어필 조회 엔드포인트를 도입했다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant UC as UserController
participant S as MyPotServiceImpl
participant R as Repositories
participant C as Converters
U->>UC: GET /potAppealContent/{pot_id}/{user_id}
UC->>S: getUserAppealContent(potId, userId)
S->>R: find Pot by potId / validate completed
alt member exists
S->>R: find PotMember by (potId, userId)
S->>R: fetch badges/role
S->>C: toCompletedPotDetailDto(...)
C-->>S: CompletedPotDetailDto
S-->>UC: AppealContentDto
UC-->>U: 200 OK + body
else not found/invalid
S-->>UC: error (e.g., not found/forbidden)
UC-->>U: error response
end
sequenceDiagram
autonumber
actor Owner as Current Owner
participant S as MyPotServiceImpl
participant R as PotMemberRepo/PotRepo
Owner->>S: patchDelegate(potId, newOwnerMemberId)
S->>R: validate pot & ownership
S->>R: find prevOwner / newOwner by memberId
S->>R: update prevOwner.owner=false, newOwner.owner=true, pot.user=newOwner.user
R-->>S: saved
S-->>Owner: success message
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels
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. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
src/main/java/stackpot/stackpot/user/service/UserCommandServiceImpl.java (3)
90-99: Authentication의 principal 캐스팅 안전성 보강 필요
(TempUser) authentication.getPrincipal()캐스팅은 컨텍스트 상태에 따라ClassCastException가능성이 있습니다. 널/타입 체크를 추가하세요.- Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - TempUser tempUserContext = (TempUser) authentication.getPrincipal(); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null || !(authentication.getPrincipal() instanceof TempUser)) { + log.error("임시 사용자 컨텍스트가 유효하지 않습니다. authentication={}", authentication); + throw new UserHandler(ErrorStatus.USER_NOT_FOUND); + } + TempUser tempUserContext = (TempUser) authentication.getPrincipal();
105-136: 메서드명isnewUser→isNewUser로 일관성 있게 변경 필요
카멜 케이스 컨벤션에 맞춰 메서드명을 수정하면 가독성이 향상됩니다. 변경 시 아래 호출부도 함께 모두 수정해야 합니다.수정해야 할 위치:
- 인터페이스 선언부
src/main/java/stackpot/stackpot/user/service/UserCommandService.java(라인 13)- UserResponseDto.loginDto isnewUser(Provider provider, String providerId, String email); + UserResponseDto.loginDto isNewUser(Provider provider, String providerId, String email);- 구현체 선언부
src/main/java/stackpot/stackpot/user/service/UserCommandServiceImpl.java(라인 105)- public UserResponseDto.loginDto isnewUser(Provider provider, String providerId, String email) { + public UserResponseDto.loginDto isNewUser(Provider provider, String providerId, String email) {- 컨트롤러 호출부
src/main/java/stackpot/stackpot/user/controller/UserController.java
- 카카오 로그인 처리: 라인 109
- 네이버 로그인 처리: 라인 142
- 구글 로그인 처리: 라인 175
- userCommandService.isnewUser(Provider.KAKAO, providerId, email) + userCommandService.isNewUser(Provider.KAKAO, providerId, email)- 테스트 코드 호출부
src/test/java/stackpot/stackpot/user/service/UserCommandServiceImplTest.java
- 기존 유저 테스트: 라인 70
- 신규 유저 테스트: 라인 100
- userCommandService.isnewUser(provider, providerId, email); + userCommandService.isNewUser(provider, providerId, email);위치별로 메서드명이 변경되었는지 전역 검색/치환을 통해 꼼꼼히 확인해 주세요.
482-495: null 안전성 보강: nickname·roleName은 null일 수 있으므로 적절한 기본값 처리 필요
- PotMember.user는
@JoinColumn(nullable=false)제약으로 null이 되지 않으므로 별도 null 체크 불필요potMember.getUser().getNickname()은 DB·코드 레벨에서 nullable(true)이므로 null일 때(알 수 없음)기본값 적용potMember.getRoleName()은 역시 nullable 컬럼이므로 null일 경우Role.UNKNOWN으로 대체코드 변경 예시:
@@ -482,7 +482,14 @@ private void sendDeletionNotifications(List<PotMember> potMembers, Pot pot) { - try { - emailService.sendPotDeleteNotification( - potMember.getUser().getEmail(), - pot.getPotName(), - potMember.getUser().getNickname() + " " + Role.toVegetable(potMember.getRoleName().name()) - ); + try { + // nickname null-safe 처리 + String nickname = Optional.ofNullable(potMember.getUser().getNickname()) + .orElse("(알 수 없음)"); + // roleName null-safe 처리 + String roleStr = Optional.ofNullable(potMember.getRoleName()) + .orElse(Role.UNKNOWN) + .name(); + emailService.sendPotDeleteNotification( + potMember.getUser().getEmail(), + pot.getPotName(), + nickname + " " + Role.toVegetable(roleStr) + ); } catch (Exception e) { log.error("이메일 발송 실패: {}", e.getMessage()); }build.gradle (2)
37-39: 중복 의존성 제거 필요 (MySQL 커넥터 & Spring Security)build.gradle 에서 다음 의존성이 중복 선언되어 있습니다. 불필요한 중복을 제거하고, 한 번만 선언된 상태에서 빌드 의존성 그래프를 확인하세요.
MySQL 커넥터
• 유지:
– 37행:runtimeOnly 'com.mysql:mysql-connector-j'
• 제거 (중복):
– 38행:runtimeOnly 'mysql:mysql-connector-java:8.0.33'
– 62행:implementation 'mysql:mysql-connector-java:8.0.33'
– 78행:implementation 'mysql:mysql-connector-java:8.0.33'Spring Security
• 유지:
– 41행:implementation 'org.springframework.boot:spring-boot-starter-security'
– 64행:implementation 'org.springframework.security:spring-security-crypto'
• 제거 (중복):
– 63행:implementation 'org.springframework.boot:spring-boot-starter-security'
– 79행:implementation 'org.springframework.boot:spring-boot-starter-security'
– 80행:implementation 'org.springframework.security:spring-security-crypto'// ⬆ 기존 선언 유지 runtimeOnly 'com.mysql:mysql-connector-j' - runtimeOnly 'mysql:mysql-connector-java:8.0.33' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.security:spring-security-crypto' - implementation 'mysql:mysql-connector-java:8.0.33' - implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springframework.security:spring-security-crypto' - implementation 'mysql:mysql-connector-java:8.0.33'검증: 의존성 제거 후
./gradlew :dependencies --configuration runtimeClasspath명령으로 실제 적용된 라인업을 확인하시기 바랍니다.
49-49: build.gradle의 springdoc-openapi 버전 중복 제거 및 정렬 필요
build.gradle에서 아래 두 군데에 동일 아티팩트가 서로 다른 버전으로 선언되어 있습니다. 더 높은 버전(2.3.0)만 남기고, 의존성 목록을 정렬하세요.
- 수정 대상 위치
- 49행:
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'삭제- 77행:
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'유지 및 필요 시 알파벳 순으로 위치 조정- 예시(diff)
- implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'- 변경 후
./gradlew dependencies실행하여 의존성 충돌이 없는지 반드시 확인해주세요.src/main/java/stackpot/stackpot/pot/service/pot/MyPotServiceImpl.java (2)
154-162: isMember 계산 오류: 소유자(owner)가 false로 표기될 수 있음현재 로직은 PotMember 여부만 확인합니다. 소유자는 PotMember 레코드가 없을 수 있어(isOwner만) 본인이 만든 팟에서도
isMember=false가 내려갈 가능성이 큽니다. 프론트 표시/권한 분기에 영향을 줄 수 있으므로 수정이 필요합니다.- User user = authService.getCurrentUser(); - boolean isMember = potMemberRepository.existsByPotAndUser(pot, user); - - return potConverter.toDto(pot, isMember); + User user = authService.getCurrentUser(); + boolean isMember = + pot.getUser() != null && pot.getUser().getId().equals(user.getId()) + || potMemberRepository.existsByPotAndUser(pot, user); + + return potConverter.toDto(pot, isMember);
310-340: patchDelegate 메서드: 트랜잭션·예외 코드·@OverRide 적용 및 선택적 검증 추가 필요아래 사항들을 반영해 주세요:
• @transactional 누락
– 메서드 단위 원자성 보장을 위해@Transactional을 추가합니다.
– 기존에 클래스 최상단에서 사용 중인import jakarta.transaction.Transactional;대신
import org.springframework.transaction.annotation.Transactional;로 통일하세요.• @OverRide 누락
– 인터페이스 구현 메서드이므로@Override를 붙여 가독성과 컴파일 체크를 강화합니다.• 예외 코드 정정
–prevOwner == null및newOwner조회/팟 불일치 시 현재ErrorStatus.POT_NOT_FOUND또는ErrorStatus.INVALID_MEMBER대신
ErrorStatus.POT_MEMBER_NOT_FOUND를 사용해 “팟 멤버 없음” 상태를 명확히 표현하세요.• 선택적 검증/처리
– pot.user와 prevOwner.user 불일치 시 로그 경고 후POT_FORBIDDEN처리 (데이터 일관성 검증)
– prevOwner와 potMemberId가 같으면 no-op 처리 후 “이미 소유자입니다.” 메시지 반환제안 diff 예시:
-import jakarta.transaction.Transactional; +import org.springframework.transaction.annotation.Transactional; @Slf4j @Service @RequiredArgsConstructor public class MyPotServiceImpl implements MyPotService { + @Override + @Transactional public String patchDelegate(Long potId, Long potMemberId) { User user = authService.getCurrentUser(); Pot pot = potRepository.findById(potId) .orElseThrow(() -> new PotHandler(ErrorStatus.POT_NOT_FOUND)); - PotMember prevOwner = potMemberRepository.findByPot_PotIdAndOwnerTrue(potId); - if (prevOwner == null) { - throw new PotHandler(ErrorStatus.POT_NOT_FOUND); - } + PotMember prevOwner = potMemberRepository.findByPot_PotIdAndOwnerTrue(potId); + if (prevOwner == null) { + throw new PotHandler(ErrorStatus.POT_MEMBER_NOT_FOUND); + } + if (!pot.getUser().getId().equals(prevOwner.getUser().getId())) { + log.warn("Pot({}) 소유자 불일치: pot.user={}, prevOwner.user={}", + potId, pot.getUser().getId(), prevOwner.getUser().getId()); + throw new PotHandler(ErrorStatus.POT_FORBIDDEN); + } - PotMember newOwner = potMemberRepository.findById(potMemberId) - .orElseThrow(() -> new PotHandler(ErrorStatus.INVALID_MEMBER)); + PotMember newOwner = potMemberRepository.findById(potMemberId) + .orElseThrow(() -> new PotHandler(ErrorStatus.POT_MEMBER_NOT_FOUND)); // 같은 팟인지 확인 if (!newOwner.getPot().getPotId().equals(potId)) { - throw new PotHandler(ErrorStatus.INVALID_MEMBER); + throw new PotHandler(ErrorStatus.POT_MEMBER_NOT_FOUND); } + // 이미 소유자이면 no-op + if (prevOwner.getId().equals(potMemberId)) { + return "이미 소유자입니다."; + } prevOwner.updateOwner(false); newOwner.updateOwner(true); pot.setUser(newOwner.getUser()); potMemberRepository.save(prevOwner); potMemberRepository.save(newOwner); potRepository.save(pot); return "권한 위임 완료"; } }
🧹 Nitpick comments (13)
src/main/java/stackpot/stackpot/feed/service/FeedCommandServiceImpl.java (2)
81-132: 읽기 전용 트랜잭션 + N+1(saveCount) 제거 제안
- 본 메서드는 조회 전용이므로 readOnly를 명시하면 플러시 방지/최적화 이점이 있습니다.
- 스트림 내부에서
feedSaveRepository.countByFeed(feed)호출로 N+1이 발생합니다. 미리 feedIds를 모아 배치로 카운트를 조회한 뒤 Map으로 합치는 방식이 좋습니다.다음과 같이 반영을 고려해주세요.
- @Transactional + @Transactional(readOnly = true) public FeedResponseDto.FeedPreviewList getFeedsByUserId(Long userId, Long nextCursor, int pageSize) { ... - List<FeedResponseDto.FeedDto> feedDtos = feeds.stream() + // 1) saveCount 일괄 조회 (예: SELECT feed_id, COUNT(*) FROM feed_save WHERE feed_id IN (...) GROUP BY feed_id) + List<Long> feedIds = feeds.stream().map(Feed::getFeedId).toList(); + Map<Long, Integer> saveCountMap = feedSaveRepository.countSavesByFeedIds(feedIds); // Map<feedId, count> + + List<FeedResponseDto.FeedDto> feedDtos = feeds.stream() .map(feed -> { boolean isOwner = loginUserId != null && feed.getUser().getId().equals(loginUserId); Boolean isLiked = loginUserId != null && likedFeedIds.contains(feed.getFeedId()); Boolean isSaved = loginUserId != null && savedFeedIds.contains(feed.getFeedId()); - int saveCount = feedSaveRepository.countByFeed(feed); + int saveCount = saveCountMap.getOrDefault(feed.getFeedId(), 0); return feedConverter.feedDto(feed, isOwner, isLiked, isSaved, saveCount); }) .collect(Collectors.toList());참고:
countSavesByFeedIds는 커스텀 쿼리(예:@Query("select fs.feed.id, count(fs) ... group by fs.feed.id"))로 구현 가능합니다.필요 시
feedSaveRepository에 커스텀 메서드 정의까지 제안 드릴 수 있습니다. 원하시면 알려주세요.
226-269: 시리즈 댓글 최대 5개 제약은 좋습니다. 중복 방지를 스키마로 강제하세요비즈니스 로직에서 Set으로 중복을 걸러주고 있으나, (user_id, comment)에 유니크 인덱스를 두면 데이터 정합성이 보장됩니다.
DB 마이그레이션이 필요하면 알려주세요. 스크립트 제안드리겠습니다.
src/main/java/stackpot/stackpot/user/service/UserCommandServiceImpl.java (1)
289-296: 주석과 구현 불일치(공백 처리)주석은 “앞뒤 공백 유지”라고 되어 있으나
trim()으로 제거하고 있습니다. 의도에 맞춰 주석 또는 코드를 정리하세요.- // 앞뒤 공백 유지 + // 앞뒤 공백 제거 log.info("닉네임 생성 전 닉네임: {}", nickname); nickname = nickname.trim();src/main/java/stackpot/stackpot/pot/converter/PotMemberConverter.java (1)
63-66: toKaKaoMemberDto: potRole에 “멤버”(한글) 주입 시 API 일관성 확인 필요
roleName이 없을 때"멤버"(한글)가 내려갑니다. 클라이언트가 Enum(예: BACKEND/FRONTEND)만 기대한다면 파싱 이슈가 될 수 있습니다. 기본값을Role.UNKNOWN.name()등 영문 Enum으로 통일하고, 표시용 한글은nicknameWithRole에서만 처리하는 방식을 고려해주세요.해당 DTO의 스키마(명세) 기대값이 무엇인지 확인 부탁드립니다.
build.gradle (1)
71-73: WebMVC + WebFlux 동시 사용 주의
spring-boot-starter-web(Tomcat)과spring-boot-starter-webflux(Netty)를 함께 사용하면 런타임 충돌/예상치 못한 빈 선택 문제가 생길 수 있습니다. 명확한 필요(예: WebClient만)을 위해 WebFlux가 필요한지 점검하고, 필요 시webflux만의 의존성을 최소화(예:spring-webflux또는reactor-netty단독)하는 방식을 검토하세요.src/main/java/stackpot/stackpot/pot/dto/PotSummaryDto.java (1)
3-6: 불필요한 import 제거
BadgeDto는 사용되지 않습니다. 정리하면 컴파일 경고를 줄일 수 있습니다.-import stackpot.stackpot.badge.dto.BadgeDto;src/main/java/stackpot/stackpot/pot/service/pot/MyPotService.java (1)
16-16: 인터페이스에 타깃 유저 어필 조회 메서드 추가: 네이밍/계약 명확화 제안
- 파라미터 명을 컨트롤러·구현체와 통일해
userId로 맞추면 가독성이 좋아집니다.- 반환 계약(타깃 유저가 PotMember가 아닌 경우 필드 null 허용인지, 권한 정책)은 Javadoc으로 명시해 주세요. FE 연동 시 혼동을 줄일 수 있습니다.
src/main/java/stackpot/stackpot/pot/converter/PotConverter.java (1)
134-141: PotSummary 변환 메서드: 오버로드 명확화 및 null-세이프 처리 검토
- 동일 클래스에
toDto(...)오버로드가 많아 가독성이 떨어집니다.toSummaryDto(...)등 의미를 드러내는 이름으로의 리네임을 고려해 주세요.isMember가 tri-state(Boolean)로 설계된 게 의도인지 확인 필요합니다. 의도가 불확실하다면 null을 명시적으로 false로 매핑하는 편이 안전합니다.선호하는 방향이 null→false 매핑이라면 아래처럼 최소 수정 가능합니다.
- .isMember(isMember) + .isMember(Boolean.TRUE.equals(isMember))src/main/java/stackpot/stackpot/pot/service/pot/MyPotServiceImpl.java (3)
75-77: 읽기 전용 트랜잭션으로 전환 + Spring @transactional 사용 권장
- 조회 전용 메서드이므로
@Transactional(readOnly = true)가 적합합니다.- 본 PR 전반 가이드에 따라
jakarta.transaction.Transactional대신org.springframework.transaction.annotation.Transactional로 통일해 주세요.적용 diff(해당 메서드에 한정):
-@Transactional +@Transactional(readOnly = true) @Override public AppealContentDto getUserAppealContent(Long potId, Long targetUserId) {추가로, 파일 상단 import 교체가 필요합니다(선택 적용 코드):
// import 변경 제안 // import jakarta.transaction.Transactional; import org.springframework.transaction.annotation.Transactional;
83-86: 비즈니스 상태 오류 로깅 레벨 조정 제안완료되지 않은 팟 접근은 예상 가능한 사용자 입력 오류입니다.
log.error대신log.warn이 더 적절합니다. 운영 알람 노이즈를 줄일 수 있습니다.
88-99: 중복 DB 조회 제거로 성능 개선이미
potMember를 조회했으므로 역할 정보도 해당 엔티티에서 우선 취득하고, 없는 경우에만 한 번 더 조회하도록 변경하면 불필요한 쿼리를 줄일 수 있습니다.- // 4) 역할 조회 (한글명 매핑) - String userPotRole = potMemberRepository.findRoleByUserId(potId, targetUserId) - .map(role -> RoleNameMapper.getKoreanRoleName(role.name())) - .orElse(null); + // 4) 역할 조회 (한글명 매핑) - potMember 우선 사용, 없으면 fallback 조회 + String userPotRole = + (potMember != null && potMember.getRoleName() != null) + ? RoleNameMapper.getKoreanRoleName(potMember.getRoleName().name()) + : potMemberRepository.findRoleByUserId(potId, targetUserId) + .map(role -> RoleNameMapper.getKoreanRoleName(role.name())) + .orElse(null);src/main/java/stackpot/stackpot/user/controller/UserController.java (2)
318-331: 다른 사용자 어필 조회 엔드포인트: 메서드명/스웨거 에러 코드 보강
- 메서드명이 기존과 동일(
getAppealContent)하여 오버로드로 구분됩니다. 의미 명확화를 위해getUserAppealContent등으로 변경을 권장합니다.- 서비스 레이어에서
POT_NOT_FOUND,_BAD_REQUEST(완료 상태 아님)도 발생 가능하니 스웨거의@ApiErrorCodeExamples에 추가해 주세요.권장 diff:
- public ResponseEntity<ApiResponse<AppealContentDto>> getAppealContent( + public ResponseEntity<ApiResponse<AppealContentDto>> getUserAppealContent( @PathVariable(name = "pot_id") Long potId, @PathVariable(name = "user_id") Long userId) { AppealContentDto response = myPotService.getUserAppealContent(potId, userId); return ResponseEntity.ok(ApiResponse.onSuccess(response)); }@ApiErrorCodeExamples({ - ErrorStatus.USER_NOT_FOUND, + ErrorStatus.USER_NOT_FOUND, + ErrorStatus.POT_NOT_FOUND, + ErrorStatus._BAD_REQUEST, })
333-345: PotSummary 응답 스펙 문서화 보강
PotSummaryDto에potName,isMember가 추가되었습니다. 스웨거description에 해당 필드도 포함되도록 갱신해 주세요. FE 스펙 싱크를 위해 중요합니다.예시:
- description = "끓인 팟을 상세보기할 때 쓰이는 PotSummary, potLan을 반환합니다." + description = "끓인 팟 상세보기용 요약 정보(PotSummary, potLan, potName, isMember)를 반환합니다."
📜 Review details
Configuration used: Path: .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.
📒 Files selected for processing (9)
build.gradle(1 hunks)src/main/java/stackpot/stackpot/feed/service/FeedCommandServiceImpl.java(1 hunks)src/main/java/stackpot/stackpot/pot/converter/PotConverter.java(1 hunks)src/main/java/stackpot/stackpot/pot/converter/PotMemberConverter.java(1 hunks)src/main/java/stackpot/stackpot/pot/dto/PotSummaryDto.java(1 hunks)src/main/java/stackpot/stackpot/pot/service/pot/MyPotService.java(1 hunks)src/main/java/stackpot/stackpot/pot/service/pot/MyPotServiceImpl.java(3 hunks)src/main/java/stackpot/stackpot/user/controller/UserController.java(1 hunks)src/main/java/stackpot/stackpot/user/service/UserCommandServiceImpl.java(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/main/java/stackpot/stackpot/pot/converter/PotMemberConverter.java (1)
src/main/java/stackpot/stackpot/common/util/RoleNameMapper.java (1)
RoleNameMapper(7-43)
src/main/java/stackpot/stackpot/pot/service/pot/MyPotServiceImpl.java (1)
src/main/java/stackpot/stackpot/common/util/RoleNameMapper.java (1)
RoleNameMapper(7-43)
🔇 Additional comments (5)
src/main/java/stackpot/stackpot/feed/service/FeedCommandServiceImpl.java (2)
15-15: @transactional import를 Spring 것으로 전환한 부분 OKSpring 트랜잭션 인프라로 일관화되어 좋습니다. 다른 모듈들도 동일하게 교체되었는지만 한번 더 확인해주세요.
189-222: 좋아요 카운트 동시성 및 유니크 제약 검토 요청
동시 요청 시feed.setLikeCount(feed.getLikeCount() ± 1)방식으로 카운트를 갱신하면 경쟁 상태(race condition)가 발생해 실제 값과 불일치(심지어 음수)할 수 있습니다. 또한,(feed_id, user_id)에 대한 고유(unique) 제약이 없으면 중복 좋아요 삽입도 가능합니다.점검 사항:
- Feed 엔티티에 낙관적 락(@Version) 사용 여부 또는 DB 원자적 업데이트(
update Feed f set f.likeCount = f.likeCount + 1) 적용 여부 검토- FeedLike 테이블에
(feed_id, user_id)고유 인덱스/제약(unique constraint) 설정 여부 확인- 실측치 재계산(
long likeCount = feedLikeRepository.countByFeedId(feedId)) 방식 또는@Modifying원자적 증감 쿼리 적용 방안 고려필요 시 JPA용
@Modifying쿼리 예시를 제공해 드리겠습니다.src/main/java/stackpot/stackpot/user/service/UserCommandServiceImpl.java (1)
9-9: @transactional import 교체 OK트랜잭션 관리 계층의 일관성을 높이는 변경으로 보입니다.
src/main/java/stackpot/stackpot/pot/dto/PotSummaryDto.java (2)
14-16: 필드 확장(potName, isMember) 자체는 명확합니다응답 스키마가 풍부해져 클라이언트에서 별도 조회 없이 멤버 여부/이름을 사용할 수 있어 보입니다.
14-16: Boolean isMember의 널 가능성 의도 확인 및 문서화
Boolean(래퍼) 선택으로 tri-state(null/true/false)를 허용한 것인지 확인 바랍니다. 단순 불린이면boolean이 더 안전합니다. 또한 OpenAPI 문서에 필드 추가 반영 여부를 확인하세요.
| implementation 'org.springframework.boot:spring-boot-starter-actuator' | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
요약과 불일치: Actuator가 제거되지 않았습니다
PR 설명/요약에는 Actuator 제거로 되어 있으나, 현재 spring-boot-starter-actuator가 남아 있습니다. 의도대로라면 삭제하세요.
- implementation 'org.springframework.boot:spring-boot-starter-actuator'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| implementation 'org.springframework.boot:spring-boot-starter-actuator' |
🤖 Prompt for AI Agents
In build.gradle around lines 90 to 91, the PR summary says Actuator was removed
but the dependency implementation
'org.springframework.boot:spring-boot-starter-actuator' is still present; remove
that dependency line (or if Actuator should stay, update the PR summary to
reflect that) so the code and PR description are consistent.
| //hibernate | ||
| implementation 'org.springframework.boot:spring-boot-starter-data-jpa' | ||
| implementation 'org.hibernate.common:hibernate-commons-annotations:6.0.6.Final' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JPA 의존성 중복 선언(앞에서 이미 추가됨) — 정리 필요
이미 2635 라인에 94에서 다시 추가되었습니다. 중복은 해석 순서/버전 충돌, 의존성 그래프 혼선을 유발합니다. 아래처럼 후반부 항목을 제거하세요.spring-boot-starter-data-jpa가 선언되어 있는데, 92
- //hibernate
- implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
- implementation 'org.hibernate.common:hibernate-commons-annotations:6.0.6.Final'
+ // Hibernate Commons (필요 시에만)
+ implementation 'org.hibernate.common:hibernate-commons-annotations:6.0.6.Final'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| //hibernate | |
| implementation 'org.springframework.boot:spring-boot-starter-data-jpa' | |
| implementation 'org.hibernate.common:hibernate-commons-annotations:6.0.6.Final' | |
| // Hibernate Commons (필요 시에만) | |
| implementation 'org.hibernate.common:hibernate-commons-annotations:6.0.6.Final' |
🤖 Prompt for AI Agents
In build.gradle around lines 92 to 94, there is a duplicate declaration of
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' that was
already declared at lines 26–35; remove the later duplicate line (leave the
hibernate-commons-annotations line if still needed) so the JPA starter is
declared only once, then run a quick dependency refresh/Gradle sync to ensure no
version/graph issues remain.
| String creatorRole = RoleNameMapper.mapRoleName(entity.getRoleName().name()); | ||
| String nicknameWithRole = entity.getUser().getNickname() + " " + creatorRole; | ||
|
|
||
| return PotMemberInfoResponseDto.builder() | ||
| .potMemberId(entity.getPotMemberId()) | ||
| .nickname(nicknameWithRole) | ||
| .potRole(entity.getRoleName().name()) | ||
| .owner(true) | ||
| .owner(entity.isOwner()) // true 고정 대신 실제 owner 여부 반영 추천 | ||
| .build(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
toKaKaoCreatorDto: roleName/user 널 가드 추가 권장
entity.getRoleName().name()와 entity.getUser().getNickname()은 널일 경우 NPE를 유발합니다. toDto와 동일한 방식으로 방어 코드를 추가하세요. 또한 “추천” 코멘트는 구현에 반영되었으므로 주석 정리도 제안드립니다.
- String creatorRole = RoleNameMapper.mapRoleName(entity.getRoleName().name());
- String nicknameWithRole = entity.getUser().getNickname() + " " + creatorRole;
+ String rawRole = entity.getRoleName() != null ? entity.getRoleName().name() : "멤버";
+ String creatorRole = RoleNameMapper.mapRoleName(rawRole);
+ String baseNickname = (entity.getUser() != null) ? entity.getUser().getNickname() : "(알 수 없음)";
+ String nicknameWithRole = baseNickname + " " + creatorRole;
...
- .potRole(entity.getRoleName().name())
- .owner(entity.isOwner()) // true 고정 대신 실제 owner 여부 반영 추천
+ .potRole(rawRole)
+ .owner(entity.isOwner())📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| String creatorRole = RoleNameMapper.mapRoleName(entity.getRoleName().name()); | |
| String nicknameWithRole = entity.getUser().getNickname() + " " + creatorRole; | |
| return PotMemberInfoResponseDto.builder() | |
| .potMemberId(entity.getPotMemberId()) | |
| .nickname(nicknameWithRole) | |
| .potRole(entity.getRoleName().name()) | |
| .owner(true) | |
| .owner(entity.isOwner()) // true 고정 대신 실제 owner 여부 반영 추천 | |
| .build(); | |
| String rawRole = entity.getRoleName() != null | |
| ? entity.getRoleName().name() | |
| : "멤버"; | |
| String creatorRole = RoleNameMapper.mapRoleName(rawRole); | |
| String baseNickname = (entity.getUser() != null) | |
| ? entity.getUser().getNickname() | |
| : "(알 수 없음)"; | |
| String nicknameWithRole = baseNickname + " " + creatorRole; | |
| return PotMemberInfoResponseDto.builder() | |
| .potMemberId(entity.getPotMemberId()) | |
| .nickname(nicknameWithRole) | |
| .potRole(rawRole) | |
| .owner(entity.isOwner()) | |
| .build(); |
🤖 Prompt for AI Agents
In src/main/java/stackpot/stackpot/pot/converter/PotMemberConverter.java around
lines 51 to 59, add null guards like in toDto so calling
entity.getRoleName().name() and entity.getUser().getNickname() cannot NPE: check
entity.getRoleName() and entity.getUser() for null, compute potRole =
entity.getRoleName() != null ? entity.getRoleName().name() : "UNKNOWN" (or other
default), compute nickname = entity.getUser() != null &&
entity.getUser().getNickname() != null ? entity.getUser().getNickname() + " " +
RoleNameMapper.mapRoleName(potRole) : RoleNameMapper.mapRoleName(potRole) (or
use safe defaults), set potRole using the safe value, and remove the leftover
inline Korean "추천" comment so the code is clean.
* [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]>
* [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]>
* [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 * [Feat/#423] 어필하기 api 수정 * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]> * [FIX/#423] - 팟 상세보기 + 지원자 목록 조회 API에 IsSaved가 반영되도록 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]>
* [Feat/#423] 어필하기 api 수정 (#433) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]> * [Bug/#432] 팟 상세보기 + 지원자 조회 API 수정 (#435) * [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 * [Feat/#423] 어필하기 api 수정 * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]> * [FIX/#423] - 팟 상세보기 + 지원자 목록 조회 API에 IsSaved가 반영되도록 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]> --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]>
* [Feat/#423] 어필하기 api 수정 (#433) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]> * [Bug/#432] 팟 상세보기 + 지원자 조회 API 수정 (#435) * [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 * [Feat/#423] 어필하기 api 수정 * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [FEAT/#423] - 팟 멤버 정보 조회 API role 에러 수정 * [Feat/#423] api 수정 (#425) * [FEAT/#423] - 다른 사람 마이페이지 '여기서 저는요' 모달 조회 * [FEAT/#423] - 끓인팟 요약 조회: 팟 이름이랑 팟 멤버인지 여부 (boolean) 추가 * [FEAT/#423] - 권한 위임 API 오류 수정 * [FEAT/#423] - 여기서 저는요 작성 및 수정 API 버그 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]> * [FIX/#423] - 팟 상세보기 + 지원자 목록 조회 API에 IsSaved가 반영되도록 수정 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]> * [Feat/#432] 다른 사람 시리즈 조회 API 제작 (#437) * [FEAT/#423] - 다른 사람 시리즈 조회 API 제작 --------- Co-authored-by: jjaeroong <[email protected]> Co-authored-by: Hyun <[email protected]>
PR 타입(하나 이상의 PR 타입을 선택해주세요)
반영 브랜치
dev -> main
작업 내용
Summary by CodeRabbit
신기능
버그 수정
문서