Skip to content

[Feature] 미팅 전체 취소 api 구현 및 미팅 정책 위반 로직 수정 - #78

Open
Sehi55 wants to merge 14 commits into
developfrom
feat/meeting-cancellation
Open

[Feature] 미팅 전체 취소 api 구현 및 미팅 정책 위반 로직 수정#78
Sehi55 wants to merge 14 commits into
developfrom
feat/meeting-cancellation

Conversation

@Sehi55

@Sehi55 Sehi55 commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

변경 사항

  • meeting match 기준 전체 미팅 취소 구현
  • 취소 투표 중 참여자 고정 로직 추가
  • 매칭 방 퇴장후 fastmatching 전환
  • 빠른 입장 시 미팅 매칭방에 연결
  • matched와 fastmatching 상태일 때 조회 시 meeting_match 의 채팅방 아이디 반환
  • 매칭 성사 후 동성 채팅방 비활성화

Summary by CodeRabbit

  • 신규 기능
    • 미팅 전체 취소 요청 생성/투표/현재 요청 조회 API를 추가했습니다.
    • 취소 요청 만료, 승인, 거절 흐름과 만료 스케줄러를 추가했습니다.
    • 동성(매칭 기반) 채팅방 입장 연계를 강화했습니다.
  • 개선
    • 비활성화 채팅방의 메시지 전송, 입장, 동기화를 차단합니다(활성 참여 기준).
    • 빠른 매칭에서 전용 채팅방으로 자동 연결되도록 했습니다.
    • WebSocket 구독 권한을 “활성 채팅방” 기준으로 검증합니다.
  • 테스트/마이그레이션
    • 취소 도메인/서비스 및 만료 동작을 검증하는 테스트와 테이블 구성을 반영했습니다.

@Sehi55 Sehi55 self-assigned this Jul 21, 2026
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

미팅 전체 취소 요청·투표·만료 처리를 추가하고, 승인 결과에 따라 미팅과 매칭 채팅방을 비활성화하도록 변경했습니다. 빠른 매칭 입장·퇴장 시 채팅방 연결과 미팅 상태 전이를 보강했으며, 비활성 채팅방 접근을 제한했습니다.

Changes

미팅 취소 및 매칭 흐름

Layer / File(s) Summary
취소 상태 모델과 저장 구조
manabom/.../domain/meeting/{entity,enums,repository}/*, manabom/.../db/migration/V21__*.sql, V22__*.sql, V23__*.sql
취소 요청·투표 엔티티, 상태 enum, 리포지토리와 요청·투표 테이블 및 제약 조건을 추가했습니다.
취소 요청·투표 서비스와 API
manabom/.../application/meeting/{service,scheduler}/*, manabom/.../application/meeting/dto/*, manabom/.../presentation/meeting/MeetingController.java, manabom/.../test/.../MeetingCancellation*
취소 생성·투표·조회·만료·승인 처리와 세 API, 만료 스케줄러 및 관련 테스트를 추가했습니다.
매칭 채팅방 생명주기와 접근 제어
manabom/.../application/chat/service/*, manabom/.../domain/chat/repository/*, manabom/.../infrastructure/security/websocket/*
매칭 채팅방 참여·조회·비활성화와 비활성 방의 메시지 전송, 동기화, WebSocket 구독을 제한했습니다.
미팅 매칭·입장·퇴장 상태 전이
manabom/.../application/meeting/service/*, manabom/.../domain/meeting/entity/Meeting.java, manabom/.../test/.../MeetingMemberLeaveStatusTest.java
빠른 매칭 입장 시 매칭 채팅방을 연결하고, 매칭 성공 및 멤버 퇴장에 따른 미팅 상태 전이를 추가했습니다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant MeetingController
  participant MeetingCancellationService
  participant MeetingCancellationVoteRepository
  participant ChatRoomService
  participant Meeting
  Client->>MeetingController: 취소 요청 또는 투표
  MeetingController->>MeetingCancellationService: 취소 처리 위임
  MeetingCancellationService->>MeetingCancellationVoteRepository: 투표 저장 및 집계
  MeetingCancellationService->>ChatRoomService: 채팅방 및 멤버 비활성화
  MeetingCancellationService->>Meeting: 취소 상태 반영
  MeetingCancellationService-->>MeetingController: 취소 응답 반환
Loading

Possibly related PRs

Suggested reviewers: kimjuneon

Poem

깡충 rabbit, 취소표를 세고
매칭 방 문을 살며시 닫네.
동의가 모이면 미팅도 쉬고,
새 상태 길을 열어 두네.
채팅은 enabled일 때만 톡톡!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 미팅 전체 취소 API 구현과 관련 정책 위반 처리 수정이라는 핵심 변경점을 잘 요약합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/meeting-cancellation

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.

@Sehi55 Sehi55 added bug Something isn't working enhancement New feature or request labels Jul 21, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
manabom/src/test/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationServiceTest.java (1)

124-156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

채팅방/멤버 비활성화 경로에 대한 검증 보강 권장

unanimousApprovalCancelsBothMatchedTeamsmeeting1/meeting2cancelByAgreement() 호출만 검증합니다. approveCancellation()이 함께 수행하는 chatRoomRepository.findByMatch/findByMeeting 조회 결과에 대한 deactivateChatRoomAndMembers 호출(채팅방/멤버 비활성화)은 이 테스트에서 커버되지 않습니다. 이번 PR의 목표 중 하나가 "매칭 성사 후 채팅방 비활성화"이므로, 관련 verify를 추가해 회귀를 방지하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@manabom/src/test/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationServiceTest.java`
around lines 124 - 156, 보 unanimousApprovalCancelsBothMatchedTeams 테스트가 meeting
취소뿐 아니라 채팅방과 멤버 비활성화 경로도 검증하도록 보강하세요. approveCancellation()에서 사용하는
chatRoomRepository의 매칭/회의 조회 결과를 설정하고, deactivateChatRoomAndMembers 호출이 두 매칭 팀에
대해 수행되는지 검증하세요.
manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingService.java (1)

184-200: 🎯 Functional Correctness | 🔵 Trivial

enterRoomByCode/enterRoomById 로직 중복 및 saveAndFlush 처리 불일치.

두 메서드가 취소 대기 검증 → 입장 검증 → isFastMatchingEntry 계산 → addMember → 채팅방 조인 → 빠른 입장 매칭방 연결 → 응답 생성까지 거의 동일한 로직을 반복하고 있습니다. 공통 private 메서드로 추출하면 유지보수성이 개선되고, 두 진입점이 항상 동일하게 동작함을 보장할 수 있습니다.

추가로 enterRoomByCode(Line 188)에만 meetingRepository.saveAndFlush(meeting) 호출과 "왜 addMember가 반영이 안되지" 주석이 있는데, enterRoomById에는 동일한 flush가 없습니다. 원래 flush가 필요했던 이유(더티 체킹이 반영되지 않는 문제)가 실재한다면 enterRoomById에도 동일한 문제가 잠재해 있을 수 있습니다. 두 진입점에서 flush 필요 여부를 명확히 하고 일관되게 처리해 주세요.

Also applies to: 215-249

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingService.java`
around lines 184 - 200, Extract the shared flow from enterRoomByCode and
enterRoomById into one private helper covering cancellation validation, join
validation, fast-matching detection, member addition, chat-room joins, and
response construction. Ensure both entry points delegate to this helper and use
the same meeting persistence behavior, explicitly deciding whether saveAndFlush
is required and applying that decision consistently; remove the temporary
comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@manabom/src/main/java/mannabom_server/manabom/application/chat/service/ChatRoomService.java`:
- Around line 139-155: Update joinMatchingChatRoom to check duplicate membership
using the member status, limiting the existsBy query to
ChatMemberStatus.ACTIVATE so users with DEACTIVATED membership history can
rejoin; preserve the existing active-member exception and save flow, and add a
database uniqueness safeguard if required to prevent concurrent duplicate
inserts.

In
`@manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationService.java`:
- Around line 155-165: Update expirePendingRequests() so each expired request is
processed in an independent transaction, preventing an OptimisticLockException
for one request from rolling back other requests. Move the per-request expire
operation into a transactional boundary that can commit or roll back
independently, while preserving the existing count and expiration timestamp
behavior.

In
`@manabom/src/main/java/mannabom_server/manabom/domain/meeting/enums/MeetingCancellationStatus.java`:
- Around line 3-8: Synchronize MeetingCancellationStatus with the
chk_cancellation_request_status database constraint by adding the missing
WITHDRAWN enum value, unless the schema is intentionally changed to remove it;
ensure the JPA enum values and allowed database statuses remain consistent.

---

Nitpick comments:
In
`@manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingService.java`:
- Around line 184-200: Extract the shared flow from enterRoomByCode and
enterRoomById into one private helper covering cancellation validation, join
validation, fast-matching detection, member addition, chat-room joins, and
response construction. Ensure both entry points delegate to this helper and use
the same meeting persistence behavior, explicitly deciding whether saveAndFlush
is required and applying that decision consistently; remove the temporary
comment.

In
`@manabom/src/test/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationServiceTest.java`:
- Around line 124-156: 보 unanimousApprovalCancelsBothMatchedTeams 테스트가 meeting
취소뿐 아니라 채팅방과 멤버 비활성화 경로도 검증하도록 보강하세요. approveCancellation()에서 사용하는
chatRoomRepository의 매칭/회의 조회 결과를 설정하고, deactivateChatRoomAndMembers 호출이 두 매칭 팀에
대해 수행되는지 검증하세요.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: de0f7f96-38d9-4777-899a-18c3ec06efb0

📥 Commits

Reviewing files that changed from the base of the PR and between 867151a and 13c910d.

📒 Files selected for processing (27)
  • manabom/src/main/java/mannabom_server/manabom/application/chat/service/ChatRoomService.java
  • manabom/src/main/java/mannabom_server/manabom/application/chat/service/ChatService.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/dto/request/MeetingCancellationVoteRequest.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/dto/response/MeetingCancellationResponse.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/dto/response/MeetingCancellationVoteResponse.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/scheduler/MeetingCancellationScheduler.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationService.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingMatchingService.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingService.java
  • manabom/src/main/java/mannabom_server/manabom/domain/chat/repository/ChatMemberRepository.java
  • manabom/src/main/java/mannabom_server/manabom/domain/chat/repository/ChatRoomRepository.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/entity/Meeting.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/entity/MeetingCancellationRequest.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/entity/MeetingCancellationVote.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/enums/CancellationVoteDecision.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/enums/MeetingCancellationStatus.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/enums/MeetingStatus.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/repository/MeetingCancellationRequestRepository.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/repository/MeetingCancellationVoteRepository.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/repository/MeetingMatchRepository.java
  • manabom/src/main/java/mannabom_server/manabom/infrastructure/security/websocket/StompAuthChannelInterceptor.java
  • manabom/src/main/java/mannabom_server/manabom/presentation/meeting/controller/MeetingController.java
  • manabom/src/main/resources/db/migration/V21__add_meeting_cancellation_tables.sql
  • manabom/src/main/resources/db/migration/V22__move_meeting_cancellation_to_match.sql
  • manabom/src/test/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationServiceTest.java
  • manabom/src/test/java/mannabom_server/manabom/domain/meeting/MeetingCancellationDomainTest.java
  • manabom/src/test/java/mannabom_server/manabom/domain/meeting/MeetingMemberLeaveStatusTest.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
manabom/src/main/resources/db/migration/V23__remove_withdrawn_cancellation_status.sql (1)

4-11: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

테이블 락(Table Lock) 방지를 위한 NOT VALID 활용 권장

운영 환경에서 제약 조건을 추가할 때 테이블 전체를 스캔하는 동안 쓰기 작업이 차단(Lock)될 수 있습니다. 이를 방지하기 위해 NOT VALID로 제약 조건을 먼저 추가한 뒤 VALIDATE CONSTRAINT를 통해 비동기적으로 검증하는 방식을 권장합니다.

💡 제안하는 마이그레이션 스크립트 수정안
 ALTER TABLE meeting_cancellation_requests
     ADD CONSTRAINT chk_cancellation_request_status
         CHECK (status IN (
                           'PENDING',
                           'APPROVED',
                           'REJECTED',
                           'EXPIRED'
-            ));
+            )) NOT VALID;
+
+ALTER TABLE meeting_cancellation_requests
+    VALIDATE CONSTRAINT chk_cancellation_request_status;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@manabom/src/main/resources/db/migration/V23__remove_withdrawn_cancellation_status.sql`
around lines 4 - 11, Update the chk_cancellation_request_status constraint in
the migration to add it with NOT VALID, then separately validate it using
VALIDATE CONSTRAINT so constraint creation does not scan and lock the entire
table during the initial ALTER TABLE operation.

Source: Linters/SAST tools

manabom/src/main/resources/db/migration/V24__add_unique_active_chat_member.sql (1)

1-3: 🩺 Stability & Availability | 🔵 Trivial

인덱스 생성 시 테이블 락(Lock) 발생 주의

운영 환경에서 데이터가 많은 테이블에 일반적인 방식으로 인덱스를 생성하면, 인덱스 생성이 완료될 때까지 해당 테이블의 쓰기 작업(Update, Insert, Delete)이 차단되어 서비스 지연 및 가용성 저하가 발생할 수 있습니다.

서비스에 미치는 영향을 최소화하려면 CONCURRENTLY 옵션을 사용하여 쓰기 락을 방지하는 것을 고려해 보세요.
단, Flyway와 같은 데이터베이스 마이그레이션 도구는 기본적으로 트랜잭션 내에서 스크립트를 실행합니다. CONCURRENTLY 키워드는 트랜잭션 내부에서 사용할 수 없으므로, 이를 적용하려면 해당 마이그레이션 파일이 트랜잭션 없이(Non-transactional) 실행되도록 별도의 설정이나 파일명 변경이 필요할 수 있습니다.

CREATE UNIQUE INDEX CONCURRENTLY uk_chat_members_active_room_user
    ON chat_members (room_id, user_id)
    WHERE status = 'ACTIVATE';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@manabom/src/main/resources/db/migration/V24__add_unique_active_chat_member.sql`
around lines 1 - 3, Update the uk_chat_members_active_room_user migration to
create the partial unique index with the CONCURRENTLY option, and configure this
migration to run non-transactionally as required by Flyway. Preserve the
existing index name, columns, uniqueness, and status filter.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@manabom/src/main/resources/db/migration/V23__remove_withdrawn_cancellation_status.sql`:
- Around line 4-11: Update the chk_cancellation_request_status constraint in the
migration to add it with NOT VALID, then separately validate it using VALIDATE
CONSTRAINT so constraint creation does not scan and lock the entire table during
the initial ALTER TABLE operation.

In
`@manabom/src/main/resources/db/migration/V24__add_unique_active_chat_member.sql`:
- Around line 1-3: Update the uk_chat_members_active_room_user migration to
create the partial unique index with the CONCURRENTLY option, and configure this
migration to run non-transactionally as required by Flyway. Preserve the
existing index name, columns, uniqueness, and status filter.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: abf70e11-ce53-4f00-b90e-4e6999b03786

📥 Commits

Reviewing files that changed from the base of the PR and between 13c910d and fa62312.

📒 Files selected for processing (9)
  • manabom/src/main/java/mannabom_server/manabom/application/chat/service/ChatRoomService.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationExpirationService.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationService.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/repository/MeetingCancellationRequestRepository.java
  • manabom/src/main/resources/db/migration/V23__remove_withdrawn_cancellation_status.sql
  • manabom/src/main/resources/db/migration/V24__add_unique_active_chat_member.sql
  • manabom/src/test/java/mannabom_server/manabom/application/chat/service/ChatRoomServiceTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationExpirationServiceTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/repository/MeetingCancellationRequestRepository.java
  • manabom/src/main/java/mannabom_server/manabom/application/chat/service/ChatRoomService.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationService.java

@kimjuneon kimjuneon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

확인했습니다 아래 부분만 한번 확인해주시면 좋을 것 같아요

Comment on lines +126 to +130
expireIfNecessary(request, now);

if (request.getStatus() != MeetingCancellationStatus.PENDING) {
throw new IllegalStateException("이미 종료된 미팅 취소 요청입니다.");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이미 만료된 요청은 expireIfNecessary()에서 EXPIRED로 변경되지만 바로 다음 상태 검사에서 PENDING 상태인지를 확인합니다. 이렇게 되면 IllegalStateException이 발생하고 @transactional이 걸려있어 EXPIRED로 변경이 롤백될 것 같습니다!

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

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants