Skip to content

Conversation

@chan0831
Copy link
Contributor

@chan0831 chan0831 commented Dec 15, 2025

๐Ÿš€ ๋ณ€๊ฒฝ์‚ฌํ•ญ

๊ณต์œ  ๋ƒ‰์žฅ๊ณ 

๐Ÿ”— ๊ด€๋ จ ์ด์Šˆ

  • Closes

โœ… ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • ๋กœ์ปฌ์—์„œ ํ…Œ์ŠคํŠธ ์™„๋ฃŒ
  • ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์ค€๋น„ ์™„๋ฃŒ

๐Ÿ“ ํŠน์ด์‚ฌํ•ญ

Summary by CodeRabbit

  • New Features

    • Added refrigerator invitation system enabling users to invite followed members to share a refrigerator
    • Added real-time WebSocket notifications for ingredient updates
    • Enhanced follower/following lists to display invitation status and mutual follow details
    • Added invitation management endpoints to accept, reject, or cancel refrigerator invitations
  • Chores

    • Added WebSocket dependency to build configuration

โœ๏ธ Tip: You can customize this high-level summary in your review settings.

@chan0831 chan0831 self-assigned this Dec 15, 2025
@chan0831 chan0831 added the โœจ feature add feature label Dec 15, 2025
@chan0831 chan0831 linked an issue Dec 15, 2025 that may be closed by this pull request
1 task
@coderabbitai
Copy link

coderabbitai bot commented Dec 15, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit 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.

Walkthrough

Implements 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

Cohort / File(s) Summary
Build & WebSocket infra
build.gradle, src/main/java/novaminds/gradproj/config/WebSocketConfig.java, src/main/java/novaminds/gradproj/global/websocket/StompHandler.java, src/main/java/novaminds/gradproj/config/SecurityConfig.java, src/main/java/novaminds/gradproj/domain/member/service/security/auth/ProfileCompletionFilter.java
Added Spring WebSocket starter; new WebSocketConfig enabling STOMP (/ws-stomp), broker prefixes /sub & /pub, SockJS and CORS; StompHandler validates JWT on CONNECT; security and profile filter exempt /ws-stomp/**.
Domain model: Refrigerator โ†” Member
src/main/java/novaminds/gradproj/domain/member/entity/Member.java, src/main/java/novaminds/gradproj/domain/refrigerator/entity/Refrigerator.java
Replaced one-to-one mapping with collection-based relationship: Member now has @ManyToOne refrigerator; Refrigerator holds @OneToMany List<Member> memberList; added add/remove member methods and adjusted setRefrigerator logic; removed unique constraint.
Invitation entity & repo
src/main/java/novaminds/gradproj/domain/refrigerator/entity/RefrigeratorInvitation.java, src/main/java/novaminds/gradproj/domain/refrigerator/repository/RefrigeratorInvitationRepository.java
New RefrigeratorInvitation JPA entity with InvitationStatus (PENDING/ACCEPTED/REJECTED/CANCELED) and lifecycle methods; repository added with query methods to find by inviter/invitee/status and batch queries.
Invitation command/query services
src/main/java/novaminds/gradproj/domain/refrigerator/service/command/RefrigeratorInvitationCommandService.java, src/main/java/novaminds/gradproj/domain/refrigerator/service/query/RefrigeratorInvitationQueryService.java
New services: command service handles send/accept/reject/cancel flows (validations, member transfer, deletion of empty refrigerators); query service returns received/sent pending invitations via repository and converter.
Refrigerator command updates (WebSocket)
src/main/java/novaminds/gradproj/domain/refrigerator/service/command/RefrigeratorCommandService.java
Added SimpMessagingTemplate broadcasts (SocketMessage) to notify /sub/refrigerator/{id} on ingredient changes; removed setting member at creation.
Converter & DTO changes
src/main/java/novaminds/gradproj/domain/refrigerator/converter/RefrigeratorConverter.java, src/main/java/novaminds/gradproj/domain/refrigerator/web/dto/RefrigeratorResponseDTO.java, src/main/java/novaminds/gradproj/domain/refrigerator/web/dto/RefrigeratorRequestDTO.java
Added invitation conversion helpers and InvitationResponse/List DTOs; added refrigeratorId to IngredientResponse and StoredIngredientCount; added InvitationRequest DTO for invite payload.
Repository & onboarding adjustments
src/main/java/novaminds/gradproj/domain/refrigerator/repository/RefrigeratorRepository.java, src/main/java/novaminds/gradproj/domain/member/service/MemberOnboardingService.java
Removed existsByMember from RefrigeratorRepository; MemberOnboardingService no longer depends on RefrigeratorRepository and checks member.getRefrigerator() != null.
Follow repositories & query service
src/main/java/novaminds/gradproj/domain/member/repository/FollowRepository.java, src/main/java/novaminds/gradproj/domain/member/repository/FollowRepositoryCustom.java, src/main/java/novaminds/gradproj/domain/member/repository/FollowRepositoryCustomImpl.java, src/main/java/novaminds/gradproj/domain/member/service/query/FollowQueryService.java
Extended FollowRepository with custom interface and QueryDSL implementation to fetch followers/followings with member and refrigerator via fetch joins; new FollowQueryService computes mutuals, batches pending invitations, and determines invitation status.
Member controller & DTOs
src/main/java/novaminds/gradproj/domain/member/web/controller/MemberController.java, src/main/java/novaminds/gradproj/domain/member/web/dto/MemberResponseDTO.java
MemberController wired with FollowQueryService and exposes GET /api/members/followers and /api/members/followings; added FollowMemberInfo, FollowersResponse, FollowingsResponse DTOs with InvitationStatus enum.
Error codes
src/main/java/novaminds/gradproj/apiPayload/code/status/ErrorStatus.java
Added invitation-related error constants (INVITATION_NOT_FOUND, INVITATION_ALREADY_EXISTS, INVITATION_ALREADY_PROCESSED, INVITATION_NOT_AUTHORIZED, CANNOT_INVITE_SELF, ALREADY_IN_SAME_REFRIGERATOR).
Refrigerator invitation controller
src/main/java/novaminds/gradproj/domain/refrigerator/web/controller/RefrigeratorInvitationController.java
New REST controller /api/refrigerators/invitations with endpoints to send, list received/sent, accept, reject, and cancel invitations; uses command/query services and ApiResponse wrapping.
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}
Loading

Estimated code review effort

๐ŸŽฏ 4 (Complex) | โฑ๏ธ ~50 minutes

  • Areas needing extra attention:
    • Memberโ€“Refrigerator relationship change: cascade, lazy loading, DB schema migration and unique constraint removal.
    • RefrigeratorInvitationCommandService: transaction boundaries, authorization checks, and deletion of empty refrigerators.
    • FollowQueryService & FollowRepositoryCustomImpl: correctness of QueryDSL fetch-joins to avoid N+1 and unintended eager loads.
    • WebSocket security: StompHandler token extraction/validation and security/filter exemptions.
    • Converter/DTO signature changes affecting multiple callers.

Possibly related PRs

  • PR #45: Overlaps converter and RefrigeratorQueryService mapping changes (refrigeratorId parameter and invitation conversion).
  • PR #34: Alters Member โ†” Refrigerator domain model and related servicesโ€”strong overlap with relationship refactor here.
  • PR #41: Modifies ErrorStatus enum with related constants; potential conflicts in error-code additions.

Poem

๐Ÿฐ I hopped in code and made a bridge so wide,
Invitations flutter, followers decide,
STOMP and sockets hum when carrots shift,
Members gather round the shared cold riftโ€”
Hooray, the fridge is full and friends inside! ๐Ÿฅ•๐Ÿฅฌ

โœจ Finishing touches
  • ๐Ÿ“ Generate docstrings
๐Ÿงช Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/58/sharedRefrigerator

๐Ÿ“œ Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 37724ec and 9871677.

๐Ÿ“’ Files selected for processing (26)
  • build.gradle (1 hunks)
  • src/main/java/novaminds/gradproj/apiPayload/code/status/ErrorStatus.java (1 hunks)
  • src/main/java/novaminds/gradproj/config/SecurityConfig.java (1 hunks)
  • src/main/java/novaminds/gradproj/config/WebSocketConfig.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/member/entity/Member.java (2 hunks)
  • src/main/java/novaminds/gradproj/domain/member/repository/FollowRepository.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/member/repository/FollowRepositoryCustom.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/member/repository/FollowRepositoryCustomImpl.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/member/service/MemberOnboardingService.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/member/service/query/FollowQueryService.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/member/service/security/auth/ProfileCompletionFilter.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/member/web/controller/MemberController.java (3 hunks)
  • src/main/java/novaminds/gradproj/domain/member/web/dto/MemberResponseDTO.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/converter/RefrigeratorConverter.java (4 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/entity/Refrigerator.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/entity/RefrigeratorInvitation.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/repository/RefrigeratorInvitationRepository.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/repository/RefrigeratorRepository.java (0 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/service/command/RefrigeratorCommandService.java (6 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/service/command/RefrigeratorInvitationCommandService.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/service/query/RefrigeratorInvitationQueryService.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/service/query/RefrigeratorQueryService.java (2 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/web/controller/RefrigeratorInvitationController.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/web/dto/RefrigeratorRequestDTO.java (1 hunks)
  • src/main/java/novaminds/gradproj/domain/refrigerator/web/dto/RefrigeratorResponseDTO.java (3 hunks)
  • src/main/java/novaminds/gradproj/global/websocket/StompHandler.java (1 hunks)

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @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

  • ๊ณต์œ  ๋ƒ‰์žฅ๊ณ  ๊ธฐ๋Šฅ ๋„์ž…: ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ํ•˜๋‚˜์˜ ๋ƒ‰์žฅ๊ณ ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก Member์™€ Refrigerator ์—”ํ‹ฐํ‹ฐ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ 1:1์—์„œ N:1๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , ๋ƒ‰์žฅ๊ณ  ์ดˆ๋Œ€ ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • WebSocket์„ ํ†ตํ•œ ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ: Spring Boot WebSocket์„ ํ†ตํ•ฉํ•˜์—ฌ ๋ƒ‰์žฅ๊ณ  ์žฌ๋ฃŒ ์ถ”๊ฐ€, ์ˆ˜์ •, ์‚ญ์ œ ์‹œ ๊ณต์œ  ๋ƒ‰์žฅ๊ณ ์˜ ๋ชจ๋“  ๋ฉค๋ฒ„์—๊ฒŒ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์•Œ๋ฆฌ๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ƒ‰์žฅ๊ณ  ์ดˆ๋Œ€ ์‹œ์Šคํ…œ: ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋ฅผ ๋ƒ‰์žฅ๊ณ ์— ์ดˆ๋Œ€ํ•˜๊ณ , ์ดˆ๋Œ€๋ฅผ ์ˆ˜๋ฝ, ๊ฑฐ์ ˆ, ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋Š” ์™„์ „ํ•œ ์ดˆ๋Œ€ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์ƒˆ๋กœ์šด ์—๋Ÿฌ ์ฝ”๋“œ ๋ฐ ๋ณด์•ˆ ์„ค์ •: ๋ƒ‰์žฅ๊ณ  ์ดˆ๋Œ€ ๊ด€๋ จ ์—๋Ÿฌ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , WebSocket ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•œ ๋ณด์•ˆ ์„ค์ •์„ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. โ†ฉ

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

๊ณต์œ  ๋ƒ‰์žฅ๊ณ  ๊ธฐ๋Šฅ ๊ตฌํ˜„์„ ์œ„ํ•œ PR ์ž˜ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ „๋ฐ˜์ ์œผ๋กœ ๊ธฐ๋Šฅ ๊ตฌํ˜„์ด ์ž˜ ์ด๋ฃจ์–ด์ง„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์›น์†Œ์ผ“์„ ์ด์šฉํ•œ ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ์™€ ์ดˆ๋Œ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„์ด ์ธ์ƒ์ ์ž…๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ๊ฐœ์„ ์ ๊ณผ ์ž ์žฌ์ ์ธ ์œ„ํ—˜์— ๋Œ€ํ•ด ๋ฆฌ๋ทฐ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ๋‚จ๊ฒผ์œผ๋‹ˆ ํ™•์ธ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์ฃผ์š” ๋‚ด์šฉ์œผ๋กœ๋Š” Refrigerator ์—”ํ‹ฐํ‹ฐ์˜ CascadeType ์„ค์ •, NullPointerException ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ, ์ฝ”๋“œ ์ค‘๋ณต, ๊ทธ๋ฆฌ๊ณ  API ์—”๋“œํฌ์ธํŠธ ์„ค๊ณ„์— ๋Œ€ํ•œ ์ œ์•ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

public void registerStompEndpoints(StompEndpointRegistry registry) {
// ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ ์ฃผ์†Œ: ws://localhost:8080/ws-stomp
registry.addEndpoint("/ws-stomp")
.setAllowedOriginPatterns("*") // CORS ํ—ˆ์šฉ
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

.setAllowedOriginPatterns("*")๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ์ถœ์ฒ˜(origin)์—์„œ์˜ ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ์„ ํ—ˆ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ ์ค‘์—๋Š” ํŽธ๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ณด์•ˆ์ƒ ์œ„ํ—˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํŠน์ • ์ถœ์ฒ˜๋งŒ ํ—ˆ์šฉํ•˜๋„๋ก ์ œํ•œํ•˜์—ฌ, ํ—ˆ๊ฐ€๋˜์ง€ ์•Š์€ ์›น์‚ฌ์ดํŠธ๊ฐ€ ์›น์†Œ์ผ“ ์—”๋“œํฌ์ธํŠธ์— ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Suggested change
.setAllowedOriginPatterns("*") // CORS ํ—ˆ์šฉ
.setAllowedOriginPatterns("https://your-frontend-domain.com") // TODO: ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ๋„๋ฉ”์ธ์„ ์ œํ•œํ•ด์ฃผ์„ธ์š”.

Comment on lines +108 to +125
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();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

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();
}

Comment on lines +33 to +40
@PostMapping("/{nickname}/send")
public ApiResponse<String> sendInvitation(
@CurrentUser Member member,
@PathVariable String nickname
) {
invitationCommandService.sendInvitation(member, nickname);
return ApiResponse.onSuccess("์ดˆ๋Œ€๋ฅผ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค.");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

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๊ฐ€ ๋” ์ผ๊ด€์„ฑ ์žˆ์–ด์ง€๊ณ , ๋‚˜์ค‘์— ์ดˆ๋Œ€ ์š”์ฒญ์— ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋  ๊ฒฝ์šฐ ํ™•์žฅํ•˜๊ธฐ์—๋„ ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.

chan0831 and others added 2 commits December 15, 2025 18:36
โ€ฆ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>
@chan0831 chan0831 merged commit 670e5fe into release Dec 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

โœจ feature add feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] ๊ณต์œ  ๋ƒ‰์žฅ๊ณ  ๊ธฐ๋Šฅ ์ถ”๊ฐ€

2 participants