Conversation
|
Caution Review failedThe pull request is closed. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughImplements refrigerator sharing and real-time updates: converts Member–Refrigerator to a many-to-one relationship, adds RefrigeratorInvitation entity and services (command/query), extends follow APIs to include invitation status, introduces WebSocket STOMP (with JWT interceptor), and updates converters/DTOs and controllers to support invitations and broadcast ingredient updates. Changes
sequenceDiagram
participant Client as Web Client
participant WS as STOMP Endpoint (/ws-stomp)
participant StompHandler as StompHandler (JWT)
participant Controller as RefrigeratorInvitationController
participant CmdService as RefrigeratorInvitationCommandService
participant InviteRepo as RefrigeratorInvitationRepository
participant RefrigRepo as RefrigeratorRepository
participant MemberRepo as MemberRepository
Client->>WS: CONNECT (Authorization: Bearer <token>)
WS->>StompHandler: preSend(CONNECT)
StompHandler-->>WS: VALID / REJECT
Client->>Controller: POST /api/refrigerators/invitations/{nickname}/send
Controller->>CmdService: sendInvitation(inviter, nickname)
CmdService->>MemberRepo: findByNickname(nickname)
MemberRepo-->>CmdService: invitee
CmdService->>InviteRepo: findByInviterAndInviteeAndStatus(...)
InviteRepo-->>CmdService: Optional.empty()/existing
CmdService->>InviteRepo: save(new RefrigeratorInvitation(...))
CmdService-->>Controller: success
Controller-->>Client: ApiResponse(success)
Note over CmdService,RefrigRepo: On accept flow, CmdService transfers member between refrigerators and may delete empty refrigerator, then updates invitation status and broadcasts via SimpMessagingTemplate to /sub/refrigerator/{id}
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
Possibly related PRs
Poem
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (26)
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 |
Summary of ChangesHello @chan0831, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 PR은 공유 냉장고 기능을 도입하여 여러 사용자가 하나의 냉장고를 함께 관리할 수 있도록 합니다. 이를 위해 핵심 엔티티 관계를 재정의하고, 초대 발송, 수락, 거절, 취소 등 초대 라이프사이클을 관리하는 시스템을 구축했습니다. 또한, WebSocket을 활용하여 냉장고 내용물 변경 시 모든 공유 멤버에게 실시간으로 업데이트를 제공함으로써 협업 경험을 향상시켰습니다. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
공유 냉장고 기능 구현을 위한 PR 잘 보았습니다. 전반적으로 기능 구현이 잘 이루어진 것 같습니다. 특히 웹소켓을 이용한 실시간 업데이트와 초대 기능 구현이 인상적입니다. 몇 가지 개선점과 잠재적인 위험에 대해 리뷰 코멘트를 남겼으니 확인 부탁드립니다. 주요 내용으로는 Refrigerator 엔티티의 CascadeType 설정, NullPointerException 발생 가능성, 코드 중복, 그리고 API 엔드포인트 설계에 대한 제안이 있습니다.
src/main/java/novaminds/gradproj/domain/refrigerator/entity/Refrigerator.java
Outdated
Show resolved
Hide resolved
...minds/gradproj/domain/refrigerator/service/command/RefrigeratorInvitationCommandService.java
Outdated
Show resolved
Hide resolved
| public void registerStompEndpoints(StompEndpointRegistry registry) { | ||
| // 웹소켓 연결 주소: ws://localhost:8080/ws-stomp | ||
| registry.addEndpoint("/ws-stomp") | ||
| .setAllowedOriginPatterns("*") // CORS 허용 |
There was a problem hiding this comment.
.setAllowedOriginPatterns("*")를 사용하면 모든 출처(origin)에서의 웹소켓 연결을 허용하게 됩니다. 개발 중에는 편리할 수 있지만, 프로덕션 환경에서는 보안상 위험할 수 있습니다. 프론트엔드 애플리케이션의 특정 출처만 허용하도록 제한하여, 허가되지 않은 웹사이트가 웹소켓 엔드포인트에 연결하는 것을 방지하는 것이 좋습니다.
| .setAllowedOriginPatterns("*") // CORS 허용 | |
| .setAllowedOriginPatterns("https://your-frontend-domain.com") // TODO: 프로덕션 환경에 맞게 도메인을 제한해주세요. |
| public void rejectInvitation(Member invitee, Long invitationId) { | ||
| // 초대 조회 | ||
| RefrigeratorInvitation invitation = invitationRepository.findById(invitationId) | ||
| .orElseThrow(() -> new GeneralException(ErrorStatus.INVITATION_NOT_FOUND)); | ||
|
|
||
| // 초대받은 사람이 맞는지 확인 | ||
| if (!invitation.getInvitee().getLoginId().equals(invitee.getLoginId())) { | ||
| throw new GeneralException(ErrorStatus.INVITATION_NOT_AUTHORIZED); | ||
| } | ||
|
|
||
| // 이미 처리된 초대인지 확인 | ||
| if (invitation.getStatus() != InvitationStatus.PENDING) { | ||
| throw new GeneralException(ErrorStatus.INVITATION_ALREADY_PROCESSED); | ||
| } | ||
|
|
||
| // 초대 거절 | ||
| invitation.reject(); | ||
| } |
There was a problem hiding this comment.
acceptInvitation, rejectInvitation, cancelInvitation 메소드 전반에 걸쳐 초대 정보를 조회하고 유효성을 검사하는 (존재 여부, 권한, 상태 확인) 로직이 중복되고 있습니다. 이렇게 코드가 중복되면 향후 유지보수가 어려워질 수 있습니다. 이 공통 로직을 별도의 private 헬퍼 메소드로 추출하는 것을 고려해보세요.
예를 들어, 다음과 같은 헬퍼 메소드를 만들 수 있습니다:
private RefrigeratorInvitation findAndValidateInvitation(Long invitationId, Member member, boolean isInvitee) {
RefrigeratorInvitation invitation = invitationRepository.findById(invitationId)
.orElseThrow(() -> new GeneralException(ErrorStatus.INVITATION_NOT_FOUND));
Member principal = isInvitee ? invitation.getInvitee() : invitation.getInviter();
if (!principal.getLoginId().equals(member.getLoginId())) {
throw new GeneralException(ErrorStatus.INVITATION_NOT_AUTHORIZED);
}
if (invitation.getStatus() != InvitationStatus.PENDING) {
throw new GeneralException(ErrorStatus.INVITATION_ALREADY_PROCESSED);
}
return invitation;
}이렇게 하면 rejectInvitation 메소드는 다음과 같이 간결해집니다:
public void rejectInvitation(Member invitee, Long invitationId) {
RefrigeratorInvitation invitation = findAndValidateInvitation(invitationId, invitee, true);
invitation.reject();
}| @PostMapping("/{nickname}/send") | ||
| public ApiResponse<String> sendInvitation( | ||
| @CurrentUser Member member, | ||
| @PathVariable String nickname | ||
| ) { | ||
| invitationCommandService.sendInvitation(member, nickname); | ||
| return ApiResponse.onSuccess("초대를 보냈습니다."); | ||
| } |
There was a problem hiding this comment.
sendInvitation 엔드포인트가 초대받는 사람의 nickname을 URL 경로 변수(@PathVariable)로 받고 있습니다. 이 방식도 동작은 하지만, 리소스(초대)를 생성하는 POST 요청에서는 일반적으로 요청 본문(@RequestBody)을 사용하는 것이 더 표준적인 REST API 설계 방식입니다.
특히 현재 RefrigeratorRequestDTO.InvitationRequest라는 DTO가 정의되어 있지만 사용되지 않고 있습니다. 이 DTO를 활용하여 API의 일관성을 높이는 것이 좋습니다.
엔드포인트를 POST /api/refrigerators/invitations로 변경하고, 메소드 시그니처를 다음과 같이 수정하는 것을 고려해보세요:
@PostMapping
public ApiResponse<String> sendInvitation(
@CurrentUser Member member,
@RequestBody @Valid RefrigeratorRequestDTO.InvitationRequest request
) {
invitationCommandService.sendInvitation(member, request.getInviteeNickname());
return ApiResponse.onSuccess("초대를 보냈습니다.");
}이렇게 하면 API가 더 일관성 있어지고, 나중에 초대 요청에 파라미터가 추가될 경우 확장하기에도 용이합니다.
…ommand/RefrigeratorInvitationCommandService.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…frigerator.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
🚀 변경사항
공유 냉장고
🔗 관련 이슈
✅ 체크리스트
📝 특이사항
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.