Skip to content

[Feature] system messages 구현 - #79

Open
Sehi55 wants to merge 31 commits into
developfrom
feature/chat-system-messages
Open

[Feature] system messages 구현#79
Sehi55 wants to merge 31 commits into
developfrom
feature/chat-system-messages

Conversation

@Sehi55

@Sehi55 Sehi55 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

작업 내용

  • 매칭, 만남인증, 미팅 취소 투표, 프로필 공개 등의 상태 변화를 채팅방 안에 시스템 메시지로 남기는 로직 구현
  • 기존 SSE 알림 로직 삭제
  • 메세지에 실제 행동 사용자의 닉네임 표시

Summary by CodeRabbit

  • 새 기능

    • 매칭·미팅 인증·사진 요청·채팅방 상태를 시스템 메시지로 안내합니다.
    • 미팅 전체 취소 요청, 참여자 투표, 진행 상태 조회 기능을 제공합니다.
    • 취소 요청 및 인증 만료 상태를 자동으로 처리합니다.
    • 채팅 메시지에 시스템 이벤트, 제목, 행위자 및 추가 데이터가 표시됩니다.
  • 개선 사항

    • 비활성 채팅방의 메시지 전송과 입장을 제한합니다.
    • 시스템 메시지를 실시간 전달하고 필요한 경우 푸시 알림으로 보냅니다.
    • 시스템 메시지와 발신자 정보가 없는 메시지도 안정적으로 표시됩니다.
    • 매칭 결과와 미팅 참여 상태가 더욱 정확하게 표시됩니다.

Sehi55 added 20 commits July 16, 2026 23:05
# Conflicts:
#	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/domain/chat/repository/ChatRoomRepository.java
@Sehi55 Sehi55 self-assigned this Jul 22, 2026
@Sehi55 Sehi55 added the enhancement New feature or request label Jul 22, 2026
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Sehi55, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 15 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dca4c163-1590-4329-a6e0-4ac5f53ad020

📥 Commits

Reviewing files that changed from the base of the PR and between e97149c and 8c9a16c.

📒 Files selected for processing (12)
  • manabom/src/main/java/mannabom_server/manabom/application/chat/message/SystemMessageType.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/dto/response/MeetingCancellationResponse.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/application/meeting/service/MeetingVerificationService.java
  • manabom/src/main/java/mannabom_server/manabom/application/notification/service/NotificationService.java
  • manabom/src/main/java/mannabom_server/manabom/global/error/MeetingCancellationExpiredException.java
  • manabom/src/test/java/mannabom_server/manabom/application/chat/message/SystemMessageTypeTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/meeting/MeetingCancellationResponseTest.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
  • manabom/src/test/java/mannabom_server/manabom/application/notification/service/NotificationServiceTest.java

Walkthrough

채팅 시스템 메시지와 푸시 전달이 구조화된 이벤트와 메타데이터를 사용하도록 변경되었습니다. 미팅 취소 투표, 인증 만료 알림, 빠른 매칭 채팅방 라우팅과 상태 전이가 추가되었습니다. 관련 DTO, 저장소, 마이그레이션, 테스트도 추가되었습니다.

Changes

구조화된 채팅 메시지와 알림

Layer / File(s) Summary
시스템 메시지 모델과 전달 흐름
manabom/src/main/java/.../application/chat/*, manabom/src/main/java/.../domain/chat/*
시스템 메시지 이벤트, 렌더링, 구조화된 저장 필드, WebSocket 전달, 푸시 알림이 추가되었습니다.
채팅 동기화와 알림 API
manabom/src/main/java/.../application/notification/*, manabom/src/main/java/.../application/chat/service/ChatService.java
SSE 기반 흐름이 NotificationType과 Push 기반 흐름으로 변경되었습니다. 비활성 채팅방 필터와 시스템 메시지 동기화가 적용되었습니다.

미팅 취소

Layer / File(s) Summary
취소 요청, 투표, 만료 처리
manabom/src/main/java/.../meeting/{entity,enums,repository}/*, manabom/src/main/java/.../application/meeting/*Cancellation*, manabom/src/main/java/.../presentation/meeting/MeetingController.java, manabom/src/main/resources/db/migration/V21__...V24__...
취소 요청과 투표의 상태 전이, API, 잠금 조회, 만료 스케줄링, 데이터베이스 제약이 추가되었습니다.

미팅 인증과 매칭

Layer / File(s) Summary
인증 상태와 만료 알림
manabom/src/main/java/.../application/meeting/*Verification*.java, manabom/src/main/java/.../domain/meeting/entity/MeetingVerification.java, manabom/src/main/resources/db/migration/V25__...V27__...
검증 시작자, 제출·검증 인원, 최종 위치·성별 결과, 실패 알림 상태가 저장됩니다. 관련 이벤트와 스케줄러가 추가되었습니다.
매칭 채팅방과 이벤트 생산자
manabom/src/main/java/.../application/meeting/*, manabom/src/main/java/.../application/matching/*, manabom/src/main/java/.../application/like/*, manabom/src/main/java/.../application/messageRequest/*, manabom/src/main/java/.../domain/meeting/*
빠른 매칭 입장, 매칭 채팅방 참여, 미팅 상태 전이가 변경되었습니다. 매칭, 사진 요청, 좋아요, 메시지 요청 흐름에서 액터 정보와 시스템 이벤트가 전달됩니다.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: kimjuneon

Poem

토끼가 새 이벤트를 심었네
채팅방에 구조화된 메시지가 피어나고
취소 표가 차곡차곡 쌓이고
인증 결과가 저장되네
매칭 방으로 깡충 뛰어가요 🐇

🚥 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 제목이 시스템 메시지 구현이라는 변경의 핵심 내용을 명확하게 요약합니다.
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 feature/chat-system-messages

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.

@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: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
manabom/src/main/java/mannabom_server/manabom/application/chat/service/ChatRoomService.java (1)

212-239: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

1:1 매칭방에서 한쪽이 나가면 상대방은 영구히 "나가기"를 못하게 됩니다.

새로 추가된 room.getChatStatus() == ChatStatus.DISABLED 가드(216-218)가 chatMember 조회/deactivate()보다 먼저 실행됩니다. LOVEVIEW_MATCH/PROFILE_MATCH 케이스(236-238)는 나갈 때 room.deactivate()를 호출해 방을 DISABLED로 만드는데, 이 상태에서 상대방이 뒤늦게 leaveChatRoom을 호출하면 이 가드에서 즉시 IllegalStateException이 발생해 자신의 ChatMember를 정리(deactivate)할 기회조차 얻지 못합니다. 결과적으로 상대방의 멤버십 레코드는 계속 ACTIVATE로 남고, 클라이언트의 "나가기" 요청은 항상 실패합니다.

가드를 멤버십 정리 이후로 옮기면, 자기 멤버십 정리는 항상 성공하고 중복되는 방 상태 변경(삭제/비활성화)만 건너뛸 수 있습니다.

🐛 제안하는 수정
     public void leaveChatRoom(Long roomId, Long userId){
         ChatRoom room = chatRoomRepository.findById(roomId)
                 .orElseThrow(()-> new IllegalArgumentException("채팅방 나가기: 존재하지 않는 채팅방아이디 입니다."));

-        if (room.getChatStatus() == ChatStatus.DISABLED) {
-            throw new IllegalStateException("비활성화된 채팅방에서는 나갈 수 없습니다.");
-        }
-
         ChatMember chatMember = chatMemberRepository.findByRoomIdAndUser_UserIdAndStatus(roomId, userId, ChatMemberStatus.ACTIVATE)
                 .orElseThrow(()-> new IllegalArgumentException("방에 참여중인 유저가 아닙니다."));

         chatMember.deactivate();
+        if (room.getChatStatus() == ChatStatus.DISABLED) {
+            log.info("이미 비활성화된 채팅방의 멤버십만 정리합니다: roomId={}, userId={}", roomId, userId);
+            return;
+        }
         Long referenceId=null;
         switch (room.getType()){
🤖 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/chat/service/ChatRoomService.java`
around lines 212 - 239, Move the ChatStatus.DISABLED guard in leaveChatRoom
after the active ChatMember lookup and chatMember.deactivate() call, so users
can always clean up their membership. Ensure subsequent room deletion or
deactivation logic is skipped when the room is already disabled, while
preserving the existing behavior for active rooms.
🧹 Nitpick comments (4)
manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingService.java (1)

236-253: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

joinMatchingChatRoomIfFastEntryresolveCurrentChatRoomId의 매치 조회 로직 중복

두 메서드가 거의 동일한 meetingMatchRepository.findByMeetingIdAndStatus(meeting.getId(), MatchingStatus.SUCCEEDED).orElseThrow(...) 패턴을 반복하고 있고, 예외 메시지만 다릅니다("빠른 입장 미팅과..." vs "매칭된 미팅과..."). 공통 private 헬퍼로 추출하면 유지보수성이 좋아집니다.

♻️ 리팩터링 제안
+    private MeetingMatch findSucceededMatchOrThrow(Long meetingId, String errorMessage) {
+        return meetingMatchRepository.findByMeetingIdAndStatus(meetingId, MatchingStatus.SUCCEEDED)
+                .orElseThrow(() -> new IllegalStateException(errorMessage));
+    }

     private Long joinMatchingChatRoomIfFastEntry(...) {
         if (!isFastMatchingEntry) {
             return null;
         }
-        var match = meetingMatchRepository.findByMeetingIdAndStatus(
-                        meeting.getId(),
-                        MatchingStatus.SUCCEEDED
-                )
-                .orElseThrow(() -> new IllegalStateException(
-                        "빠른 입장 미팅과 연결된 성사된 매칭을 찾을 수 없습니다."
-                ));
+        var match = findSucceededMatchOrThrow(meeting.getId(), "빠른 입장 미팅과 연결된 성사된 매칭을 찾을 수 없습니다.");
         return chatRoomService.joinMatchingChatRoom(match, user);
     }

Also applies to: 301-315

🤖 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 236 - 253, Extract the duplicated successful-match lookup from
joinMatchingChatRoomIfFastEntry and resolveCurrentChatRoomId into a shared
private helper in MeetingService. Have the helper query findByMeetingIdAndStatus
with MatchingStatus.SUCCEEDED and accept the required context-specific exception
message, then update both callers to use it while preserving their existing
messages and behavior.
manabom/src/main/java/mannabom_server/manabom/application/like/service/LikeService.java (1)

159-176: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

LikeServiceMessageRequestServicecreateChatRoom이 완전히 중복. 두 서비스의 private createChatRoom 메서드는 LikeSource/MessageSource 타입만 다를 뿐 조회·분기·호출 로직이 동일합니다. 공통 헬퍼로 추출해 중복을 제거할 수 있습니다.

  • manabom/src/main/java/mannabom_server/manabom/application/like/service/LikeService.java#L159-L176: createChatRoom 로직을 공용 헬퍼(예: 추천 이력 조회 + actorUserId 전달을 캡슐화하는 별도 컴포넌트)로 위임하도록 리팩터링.
  • manabom/src/main/java/mannabom_server/manabom/application/messageRequest/service/MessageRequestService.java#L160-L177: 동일한 공용 헬퍼를 재사용하도록 리팩터링.
🤖 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/like/service/LikeService.java`
around lines 159 - 176, Extract the duplicated createChatRoom logic from
LikeService.java lines 159-176 and MessageRequestService.java lines 160-177 into
a shared helper component that handles recommendation-history lookup, source
branching, and actorUserId propagation; update both services’ createChatRoom
methods to delegate to it while preserving their existing
LikeSource/MessageSource behavior.
manabom/src/main/resources/db/migration/V26__add_structured_system_message_fields.sql (1)

8-14: 🩺 Stability & Availability | 🔵 Trivial | 🏗️ Heavy lift

운영 중 쓰기 차단 가능성이 있는 DDL을 온라인 배포 방식으로 분리해 주세요.

대규모 운영 테이블에서는 FK/CHECK의 즉시 검증과 일반 인덱스 생성이 전체 스캔 및 쓰기 잠금을 유발할 수 있습니다.

  • manabom/src/main/resources/db/migration/V26__add_structured_system_message_fields.sql#L8-L14: FK는 NOT VALID 후 별도 검증하고 partial index는 concurrent 생성으로 분리해 주세요.
  • manabom/src/main/resources/db/migration/V26__add_structured_system_message_fields.sql#L20-L22: FK 추가의 검증과 잠금 영향을 배포 전략에 반영해 주세요.
  • manabom/src/main/resources/db/migration/V22__move_meeting_cancellation_to_match.sql#L7-L25: FK/CHECK와 두 인덱스의 온라인 생성 및 트랜잭션 분리를 확인해 주세요.
  • manabom/src/main/resources/db/migration/V23__remove_withdrawn_cancellation_status.sql#L4-L11: CHECK 검증을 데이터 정리와 분리해 잠금 시간을 줄여 주세요.
  • manabom/src/main/resources/db/migration/V25__add_meeting_verification_failure_notification.sql#L4-L6: partial index를 CREATE INDEX CONCURRENTLY로 생성할 수 있는지 확인해 주세요.
🤖 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/V26__add_structured_system_message_fields.sql`
around lines 8 - 14, 온라인 배포가 가능하도록 각 마이그레이션의 DDL을 검증·생성 단계와 트랜잭션에서 분리하세요.
manabom/src/main/resources/db/migration/V26__add_structured_system_message_fields.sql#L8-L14의
fk_chat_message_actor는 NOT VALID로 추가 후 별도 검증하고
idx_chat_messages_system_event_type은 CREATE INDEX CONCURRENTLY로 생성하세요. 같은 파일
`#L20-L22의` FK 검증 및 잠금 영향도 동일한 배포 전략에 반영하세요.
manabom/src/main/resources/db/migration/V22__move_meeting_cancellation_to_match.sql#L7-L25의
FK/CHECK와 두 인덱스는 온라인 생성 및 트랜잭션 분리를 적용하고,
manabom/src/main/resources/db/migration/V23__remove_withdrawn_cancellation_status.sql#L4-L11에서는
CHECK 검증을 데이터 정리와 분리하세요.
manabom/src/main/resources/db/migration/V25__add_meeting_verification_failure_notification.sql#L4-L6의
partial index도 CREATE INDEX CONCURRENTLY 사용과 트랜잭션 제약을 반영하세요.

Source: Linters/SAST tools

manabom/src/test/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationExpirationServiceTest.java (1)

38-52: 📐 Maintainability & Code Quality | 🔵 Trivial

발행된 ChatSystemMessageEvent의 내용에 대한 검증이 없습니다.

expiresPendingRequestInItsOwnProcessingStep 테스트는 상태 전이만 검증하고, eventPublisher.publishEvent(...)로 전달되는 이벤트의 타입(MEETING_CANCELLATION_EXPIRED), roomId, recipients, data 내용은 검증하지 않습니다. ArgumentCaptor로 캡처해 검증을 추가하면 회귀를 더 잘 잡을 수 있습니다.

✅ 제안 예시
+        ArgumentCaptor<ChatSystemMessageEvent> captor = ArgumentCaptor.forClass(ChatSystemMessageEvent.class);
+        verify(eventPublisher).publishEvent(captor.capture());
+        assertThat(captor.getValue().getType()).isEqualTo(SystemMessageType.MEETING_CANCELLATION_EXPIRED);
🤖 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/MeetingCancellationExpirationServiceTest.java`
around lines 38 - 52, Update expiresPendingRequestInItsOwnProcessingStep to
capture the ChatSystemMessageEvent passed to eventPublisher.publishEvent(...),
then assert its MEETING_CANCELLATION_EXPIRED type, roomId, recipients, and data
contents alongside the existing status assertions.
🤖 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/SystemMessageService.java`:
- Around line 82-118: Update recordMatchFailure to label both meetings with
MATCH_TIMED_OUT when match2Decision is AUTO_REJECTED, including the opponent
message type selection. Preserve the existing failedMeeting/opponentType
behavior for other decision combinations.

In
`@manabom/src/main/java/mannabom_server/manabom/application/meeting/dto/response/MeetingCancellationResponse.java`:
- Around line 28-54: Update MeetingCancellationResponse.of to count REJECT
decisions from votes and expose that count through a rejectedMemberCount
response field, including the builder mapping and any corresponding DTO
accessors. Preserve the existing agreed, pending, total, and vote-list behavior
so all vote decisions are represented and their counts sum to totalMemberCount.

In
`@manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationExpirationService.java`:
- Around line 42-61: MeetingCancellationExpirationService의
MEETING_CANCELLATION_EXPIRED 발행 로직을
MeetingCancellationService.expireIfNecessary()와 동일하게 맞추세요. recipients는
ChatMember가 아닌 MeetingMember 기준으로 산출하고, data에 기존 requestId/status와 함께 expiresAt을
포함하도록 수정하세요.

In
`@manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationService.java`:
- Around line 225-239: MeetingCancellationService의 expireIfNecessary()가 직접 만료
처리와 이벤트 발행을 수행하지 않도록 수정하고, 중복 로직을 담당하는
MeetingCancellationExpirationService.expire()에 위임하세요. 만료 시 해당 서비스의 단일 처리 경로와 동일한
payload가 사용되도록 기존 recipients 계산 및 publishCancellationEvent 호출을 제거하거나 통합하세요.
- Around line 158-166: In MeetingCancellationService, reorder the approval flow
so publishCancellationEvent with MEETING_CANCELLATION_APPROVED executes before
approveCancellation(request, now), including the equivalent flow referenced
around lines 204–223. Preserve the existing arguments and approval behavior
while ensuring the system message is recorded before chat rooms are disabled.
- Around line 135-142: Update vote() so it checks whether the cancellation
request is expired without mutating state before throwing for a non-PENDING
status. Move expireIfNecessary(request, now) out of the precondition path and
invoke it only when the vote can proceed, preserving the existing expiration
update and event publication without rolling it back due to the
IllegalStateException.

In
`@manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingService.java`:
- Around line 193-198: Update the enterRoomById and enterRoomByCode flows in
MeetingService so chatRoomService.joinChatRoom(meeting, user) is skipped when
isFastMatchingEntry is true, while preserving the existing join behavior for
regular entries and the subsequent matching-room flow.

In
`@manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingVerificationService.java`:
- Around line 254-267: Update the MEETING_VERIFICATION_SUCCEEDED event in
MeetingVerificationService to always use the current request’s userId as
actorUserId. Remove the fallback to verification.getStartedBy(), while
preserving the existing event payload and success flow.

In
`@manabom/src/main/java/mannabom_server/manabom/application/notification/service/NotificationService.java`:
- Around line 28-50: Separate push delivery in
NotificationService.sendNotification from the database transaction that saves
the Notification, ensuring FCM RuntimeException failures do not roll back
notification or chat-message persistence. Keep notificationRepository.save
within the existing transactional flow, and invoke pushService.sendToUser
through an independent after-commit or non-transactional failure-handling path
with logging or retry support.

In
`@manabom/src/main/java/mannabom_server/manabom/presentation/notification/controller/NotificationController.java`:
- Around line 14-29: Remove the unauthenticated sendTestNotification test
endpoint before deployment, or protect it with authentication and an explicit
administrator authorization check before invoking
notificationService.sendNotification. Ensure arbitrary targetUserId values
cannot be used by unauthenticated or non-admin callers.

In
`@manabom/src/main/resources/db/migration/V22__move_meeting_cancellation_to_match.sql`:
- Around line 1-18: Update the V22 migration to preserve existing
meeting_id-based cancellation requests by backfilling meeting_match_id through
the available meeting-to-match relationship, or add the required legacy mapping
so those rows remain discoverable by meetingMatch-based entity, repository, and
service flows. Ensure the migration satisfies chk_cancellation_request_target
and keeps existing requests eligible for cancellation voting and expiration
processing.

In
`@manabom/src/main/resources/db/migration/V23__remove_withdrawn_cancellation_status.sql`:
- Around line 1-11: Update the V23 migration before recreating
chk_cancellation_request_status to handle existing WITHDRAWN rows: convert them
to the policy-approved terminal status or add the required pre-validation that
prevents the constraint from being applied with invalid data. Ensure the
migration succeeds when legacy WITHDRAWN records exist.

In
`@manabom/src/main/resources/db/migration/V24__add_unique_active_chat_member.sql`:
- Around line 1-3: Update the V24 migration to create the partial unique index
with PostgreSQL’s concurrent index creation syntax, and configure Flyway with
spring.flyway.execute-in-transaction=false so this migration runs outside a
transaction.

---

Outside diff comments:
In
`@manabom/src/main/java/mannabom_server/manabom/application/chat/service/ChatRoomService.java`:
- Around line 212-239: Move the ChatStatus.DISABLED guard in leaveChatRoom after
the active ChatMember lookup and chatMember.deactivate() call, so users can
always clean up their membership. Ensure subsequent room deletion or
deactivation logic is skipped when the room is already disabled, while
preserving the existing behavior for active rooms.

---

Nitpick comments:
In
`@manabom/src/main/java/mannabom_server/manabom/application/like/service/LikeService.java`:
- Around line 159-176: Extract the duplicated createChatRoom logic from
LikeService.java lines 159-176 and MessageRequestService.java lines 160-177 into
a shared helper component that handles recommendation-history lookup, source
branching, and actorUserId propagation; update both services’ createChatRoom
methods to delegate to it while preserving their existing
LikeSource/MessageSource behavior.

In
`@manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingService.java`:
- Around line 236-253: Extract the duplicated successful-match lookup from
joinMatchingChatRoomIfFastEntry and resolveCurrentChatRoomId into a shared
private helper in MeetingService. Have the helper query findByMeetingIdAndStatus
with MatchingStatus.SUCCEEDED and accept the required context-specific exception
message, then update both callers to use it while preserving their existing
messages and behavior.

In
`@manabom/src/main/resources/db/migration/V26__add_structured_system_message_fields.sql`:
- Around line 8-14: 온라인 배포가 가능하도록 각 마이그레이션의 DDL을 검증·생성 단계와 트랜잭션에서 분리하세요.
manabom/src/main/resources/db/migration/V26__add_structured_system_message_fields.sql#L8-L14의
fk_chat_message_actor는 NOT VALID로 추가 후 별도 검증하고
idx_chat_messages_system_event_type은 CREATE INDEX CONCURRENTLY로 생성하세요. 같은 파일
`#L20-L22의` FK 검증 및 잠금 영향도 동일한 배포 전략에 반영하세요.
manabom/src/main/resources/db/migration/V22__move_meeting_cancellation_to_match.sql#L7-L25의
FK/CHECK와 두 인덱스는 온라인 생성 및 트랜잭션 분리를 적용하고,
manabom/src/main/resources/db/migration/V23__remove_withdrawn_cancellation_status.sql#L4-L11에서는
CHECK 검증을 데이터 정리와 분리하세요.
manabom/src/main/resources/db/migration/V25__add_meeting_verification_failure_notification.sql#L4-L6의
partial index도 CREATE INDEX CONCURRENTLY 사용과 트랜잭션 제약을 반영하세요.

In
`@manabom/src/test/java/mannabom_server/manabom/application/meeting/service/MeetingCancellationExpirationServiceTest.java`:
- Around line 38-52: Update expiresPendingRequestInItsOwnProcessingStep to
capture the ChatSystemMessageEvent passed to eventPublisher.publishEvent(...),
then assert its MEETING_CANCELLATION_EXPIRED type, roomId, recipients, and data
contents alongside the existing status assertions.
🪄 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: f05ba588-9796-4bf8-b4cc-a2676f38a2d1

📥 Commits

Reviewing files that changed from the base of the PR and between 867151a and 1cf3a7c.

📒 Files selected for processing (75)
  • manabom/src/main/java/mannabom_server/manabom/application/chat/dto/event/ChatSystemMessageEvent.java
  • manabom/src/main/java/mannabom_server/manabom/application/chat/dto/response/ChatMessageEvent.java
  • manabom/src/main/java/mannabom_server/manabom/application/chat/dto/response/ChatMessageResponse.java
  • manabom/src/main/java/mannabom_server/manabom/application/chat/dto/response/ChatRoomListResponse.java
  • manabom/src/main/java/mannabom_server/manabom/application/chat/handler/ChatSystemMessageEventHandler.java
  • manabom/src/main/java/mannabom_server/manabom/application/chat/message/SystemMessageType.java
  • 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/chat/service/SystemMessageService.java
  • manabom/src/main/java/mannabom_server/manabom/application/like/service/LikeService.java
  • manabom/src/main/java/mannabom_server/manabom/application/matching/service/PhotoRequestService.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/scheduler/MeetingVerificationScheduler.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/application/meeting/service/MeetingMatchingService.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingService.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingVerificationExpirationService.java
  • manabom/src/main/java/mannabom_server/manabom/application/meeting/service/MeetingVerificationService.java
  • manabom/src/main/java/mannabom_server/manabom/application/messageRequest/service/MessageRequestService.java
  • manabom/src/main/java/mannabom_server/manabom/application/notification/dto/MatchSuccessEvent.java
  • manabom/src/main/java/mannabom_server/manabom/application/notification/dto/SseData.java
  • manabom/src/main/java/mannabom_server/manabom/application/notification/handler/NotificationEventListener.java
  • manabom/src/main/java/mannabom_server/manabom/application/notification/service/NotificationService.java
  • manabom/src/main/java/mannabom_server/manabom/application/notification/service/SseService.java
  • manabom/src/main/java/mannabom_server/manabom/application/pushService/service/pushSender/FcmPushSender.java
  • manabom/src/main/java/mannabom_server/manabom/domain/chat/entity/ChatMessage.java
  • manabom/src/main/java/mannabom_server/manabom/domain/chat/repository/ChatMemberRepository.java
  • manabom/src/main/java/mannabom_server/manabom/domain/chat/repository/ChatMessageRepository.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/entity/MeetingVerification.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/enums/SseEventName.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/domain/meeting/repository/MeetingVerificationRepository.java
  • manabom/src/main/java/mannabom_server/manabom/domain/notification/entity/Notification.java
  • manabom/src/main/java/mannabom_server/manabom/domain/notification/entity/SseEventCache.java
  • manabom/src/main/java/mannabom_server/manabom/domain/notification/enums/NotificationType.java
  • manabom/src/main/java/mannabom_server/manabom/domain/notification/repository/EmitterRepository.java
  • manabom/src/main/java/mannabom_server/manabom/domain/notification/repository/SseEventCacheRepository.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/java/mannabom_server/manabom/presentation/meeting/controller/MeetingMatchingController.java
  • manabom/src/main/java/mannabom_server/manabom/presentation/notification/controller/NotificationController.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/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/main/resources/db/migration/V25__add_meeting_verification_failure_notification.sql
  • manabom/src/main/resources/db/migration/V26__add_structured_system_message_fields.sql
  • manabom/src/main/resources/db/migration/V27__persist_meeting_verification_result.sql
  • manabom/src/test/java/mannabom_server/manabom/application/chat/dto/response/ChatMessageResponseTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/chat/handler/ChatSystemMessageEventHandlerTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/chat/message/SystemMessageTypeTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/chat/service/ChatRoomServiceTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/chat/service/ChatServiceTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/chat/service/SystemMessageServiceTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/matching/service/PhotoRequestServiceTest.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
  • manabom/src/test/java/mannabom_server/manabom/application/meeting/service/MeetingVerificationExpirationServiceTest.java
  • manabom/src/test/java/mannabom_server/manabom/application/notification/service/NotificationServiceTest.java
  • manabom/src/test/java/mannabom_server/manabom/domain/meeting/MeetingCancellationDomainTest.java
  • manabom/src/test/java/mannabom_server/manabom/domain/meeting/MeetingMemberLeaveStatusTest.java
  • manabom/src/test/java/mannabom_server/manabom/domain/meeting/MeetingVerificationTest.java
💤 Files with no reviewable changes (8)
  • manabom/src/main/java/mannabom_server/manabom/application/notification/dto/SseData.java
  • manabom/src/main/java/mannabom_server/manabom/domain/notification/entity/SseEventCache.java
  • manabom/src/main/java/mannabom_server/manabom/presentation/meeting/controller/MeetingMatchingController.java
  • manabom/src/main/java/mannabom_server/manabom/domain/notification/repository/SseEventCacheRepository.java
  • manabom/src/main/java/mannabom_server/manabom/domain/meeting/enums/SseEventName.java
  • manabom/src/main/java/mannabom_server/manabom/application/notification/handler/NotificationEventListener.java
  • manabom/src/main/java/mannabom_server/manabom/domain/notification/repository/EmitterRepository.java
  • manabom/src/main/java/mannabom_server/manabom/application/notification/service/SseService.java

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant