Skip to content

[Fix] DIRECT 채팅방 재입장 및 메시지 전송 시 ChatPart 복구#171

Merged
dppfls merged 1 commit into
mainfrom
fix/chat-170-direct-chat-restore
Jun 3, 2026
Merged

[Fix] DIRECT 채팅방 재입장 및 메시지 전송 시 ChatPart 복구#171
dppfls merged 1 commit into
mainfrom
fix/chat-170-direct-chat-restore

Conversation

@dppfls

@dppfls dppfls commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

🔗 관련 이슈

관련된 이슈 번호를 적어주세요.

closes #170

📌 작업 내용

이번 PR에서 작업한 내용을 간략히 설명해주세요.

  • DIRECT 채팅방 재입장 및 메시지 전송 시 ChatPart 복구

🧪 테스트 결과

Postman 스크린샷, 테스트 통과 여부 등을 첨부해주세요.

📸 스크린샷 (선택)

필요시 스크린샷을 첨부해주세요.

📎 참고 사항 (선택)

리뷰어에게 전달할 내용이 있다면 작성해주세요.

Summary by CodeRabbit

릴리스 노트

  • 버그 수정

    • 1:1 채팅에서 삭제된 채팅방이 메시지 수신 시 자동으로 복구되도록 개선
  • 개선사항

    • 채팅방 진입 시 상대방의 삭제된 채팅 참여 정보를 복구하는 로직 추가
    • 삭제된 상태의 상대방 정보도 정상적으로 조회할 수 있도록 개선

@dppfls dppfls self-assigned this Jun 3, 2026
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

📋 대략적 요약

DIRECT 채팅에서 상대 사용자가 나간(ChatPart 삭제) 상태였을 때, 채팅방에 재진입하거나 메시지를 보낼 때 자동으로 상대의 ChatPart를 복구하는 기능을 구현합니다. 저장소 메서드 변경으로 삭제된 상대도 조회 가능하게 하고, 진입/메시지 송신 시점에 복구를 수행합니다.

🔄 변경 사항

DIRECT 채팅 참여자 복구 흐름

Layer / File(s) 요약
삭제된 상대 조회 저장소 계약
src/main/java/com/capstone/pickIt/domain/chat/repository/ChatPartRepository.java
findOpponent 메서드를 findOpponentIncludingDeleted로 변경하고, 쿼리에서 삭제 제외 조건(cp.deletedAt IS NULL)을 제거하여 삭제 상태의 상대 ChatPart도 조회 결과에 포함시킵니다.
쿼리 서비스에서 삭제된 상대 포함 조회
src/main/java/com/capstone/pickIt/api/chat/service/ChatRoomQueryServiceImpl.java
getOpponentOrNull(...)이 새로운 findOpponentIncludingDeleted 메서드를 호출하도록 변경되어 상대가 삭제 상태이더라도 ChatPart 정보를 조회할 수 있습니다.
채팅방 진입 및 메시지 송신 시 ChatPart 복구
src/main/java/com/capstone/pickIt/api/chat/service/ChatRoomCommandServiceImpl.java, src/main/java/com/capstone/pickIt/api/chat/service/ChatMessageCommandServiceImpl.java
restoreAndConvert에서 채팅방 진입 시 대상 사용자의 삭제된 ChatPart를 복구하고, sendMessage에서 DIRECT 채팅일 때 메시지 송신 후 상대의 삭제된 ChatPart를 찾아 복구합니다.

📌 검토 포인트

  • 저장소 계약 변경의 영향: findOpponentIncludingDeleted 메서드 도입으로 모든 상대 조회가 삭제 상태를 포함하는지 확인. 의도하지 않은 곳에서 삭제된 데이터가 노출되지 않는지 검증 필요합니다.
  • 복구 타이밍의 일관성: 진입 시와 메시지 송신 시 두 곳에서 복구가 발생하는데, 중복 복구나 경합(race condition)이 없는지 확인해야 합니다.
  • 예외 처리: ChatRoomCommandServiceImpl.restoreAndConvert에서 대상 ChatPart가 없을 때 CHAT_PART_NOT_FOUND 예외를 던지는데, 이것이 의도된 동작인지 확인하세요. (DIRECT 채팅 상대가 아예 없는 경우와 삭제된 경우의 구분)
  • 쿼리 성능: 추가 조회와 복구 로직이 메시지 송신 경로에 들어가므로, N+1 쿼리 문제나 성능 영향을 모니터링하세요.

🎯 리뷰 난도

🎯 2 (Simple) | ⏱️ ~10 분

소규모 변경이지만 저장소 계약 변경이 포함되어 있으므로, 다른 코드 경로에서 의도하지 않은 영향을 주지 않는지 신중히 검토하세요.

🔗 관련 PR

  • capstone-pick-it/Backend#159: DIRECT/채팅방에서 상대 ChatPart 조회·처리 로직을 ChatPartRepository 및 채팅 서비스 레벨에서 함께 수정하는 코드 수준의 연관성이 있습니다.
  • capstone-pick-it/Backend#153: ChatMessageCommandServiceImpl#sendMessage에서 메시지 송신 시 참가자/알림 흐름을 추가/수정하므로, 같은 코드 경로를 건드리는 점에서 연관됩니다.
  • capstone-pick-it/Backend#47: DIRECT 채팅 재진입/복구 변경이 1:1 채팅방 생성/재진입 흐름 위에서 ChatPart.deletedAt를 통한 나간 참여자 복구를 구현하는 기반을 제공합니다.

🎭 격려의 말

🚀 조용히 그리고 우아하게,
나간 이들을 다시 불러내고,
DIRECT 채팅은 다시 빛나리라—
메시지 한 줄이, 모든 것을 회복한다. ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning 기본 정보(관련 이슈, 작업 내용)는 작성되었으나 필수 섹션인 테스트 결과가 완전히 비어있어 불완전합니다. 테스트 결과 섹션을 채우고 Postman 테스트 스크린샷이나 단위/통합 테스트 통과 여부를 명시하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경의 핵심(DIRECT 채팅방에서 ChatPart 복구)을 명확히 요약하고 있어 충분히 설명력 있습니다.
Linked Issues check ✅ Passed 코드 변경사항이 이슈 #170의 두 가지 목표(재입장 시 복구, 메시지 전송 시 복구)를 모두 충족하는 구현을 포함합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 DIRECT 채팅 ChatPart 복구라는 명확한 범위 내에 있으며 관련 없는 수정은 없습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 fix/chat-170-direct-chat-restore

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.

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

Caution

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

⚠️ Outside diff range comments (1)
src/main/java/com/capstone/pickIt/api/chat/service/ChatMessageCommandServiceImpl.java (1)

108-162: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

DIRECT에서 상대 ChatPart 복구가 “루프 밖”에서 실행되도록 위치/순서 수정 필요

findActiveParticipantsWithUserByChatRoomIdcp.deletedAt IS NULL(및 현재 사용자 제외 조건)로 조회합니다. 그래서 DIRECT에서 상대가 이미 나가(deletedAt != null) 있으면 participants가 비어 for 루프가 돌지 않고, 현재 루프 내부의 findOpponentIncludingDeleted(...).ifPresent(ChatPart::restore)가 호출되지 않습니다(=복구/재노출 기능이 데드 패스).

  • restore는 루프 밖으로 빼서 participants(및 unreadCountMap) 조회 이전에 실행되게 변경하세요.
  • JPA에서는 변경 후 같은 트랜잭션 내 조회 반영이 중요하므로(dirty checking/flush 타이밍), 순서만 바꾸어도 해결되고, 필요 시 flush/저장 명시로 조회 일관성을 맞추는 방향을 권장합니다(Spring @Transactional, JPA flush/dirty checking 개념 참고).
권장 diff (복구 블록을 participants 조회 이전으로 이동)
         eventPublisher.publishEvent(
                 new ChatRoomBroadcastEvent(chatRoom.getId(), response)
         );
 
+        // DIRECT 채팅 상대방이 나간 상태라면 채팅방 재노출을 위해 복구
+        // (참여자 조회 이전에 수행하여 복구된 상대도 알림 대상에 포함되도록 함)
+        if (chatRoom.getChatType() == ChatType.DIRECT) {
+            chatPartRepository.findOpponentIncludingDeleted(chatRoom.getId(), currentUserId)
+                    .ifPresent(ChatPart::restore);
+        }
+
         /*
          * 채팅방 참여자별 채팅 목록 갱신 알림 이벤트 발행
          */
         List<ChatPart> participants =
                 chatPartRepository.findActiveParticipantsWithUserByChatRoomId(chatRoom.getId());
-            // DIRECT 채팅 상대방이 나간 상태라면 채팅방 재노출을 위해 복구
-            if (chatRoom.getChatType() == ChatType.DIRECT) {
-                chatPartRepository.findOpponentIncludingDeleted(chatRoom.getId(), currentUserId)
-                        .ifPresent(ChatPart::restore);
-            }
-
             // 채팅 목록(lastMessage, unreadCount) 갱신용 개인 알림 이벤트 발행
             eventPublisher.publishEvent(
                     new ChatUserNotificationEvent(receiverId, notification)
             );
🤖 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
`@src/main/java/com/capstone/pickIt/api/chat/service/ChatMessageCommandServiceImpl.java`
around lines 108 - 162, The DIRECT-chat opponent restore logic must run before
you fetch participants/unreadCountMap because
findActiveParticipantsWithUserByChatRoomId excludes deleted ChatPart rows,
causing the for-loop to skip restoration; move the call to
chatPartRepository.findOpponentIncludingDeleted(chatRoom.getId(),
currentUserId).ifPresent(ChatPart::restore) to execute prior to calling
findActiveParticipantsWithUserByChatRoomId(...) and
countUnreadMessagesByUsersInChatRoom(...), and ensure the transaction will flush
the change (e.g., rely on `@Transactional` or call save/flush if necessary) so
subsequent queries see the restored ChatPart.
🤖 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.

Outside diff comments:
In
`@src/main/java/com/capstone/pickIt/api/chat/service/ChatMessageCommandServiceImpl.java`:
- Around line 108-162: The DIRECT-chat opponent restore logic must run before
you fetch participants/unreadCountMap because
findActiveParticipantsWithUserByChatRoomId excludes deleted ChatPart rows,
causing the for-loop to skip restoration; move the call to
chatPartRepository.findOpponentIncludingDeleted(chatRoom.getId(),
currentUserId).ifPresent(ChatPart::restore) to execute prior to calling
findActiveParticipantsWithUserByChatRoomId(...) and
countUnreadMessagesByUsersInChatRoom(...), and ensure the transaction will flush
the change (e.g., rely on `@Transactional` or call save/flush if necessary) so
subsequent queries see the restored ChatPart.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 85f349d2-ae29-4ab3-b443-3b7cab421a5c

📥 Commits

Reviewing files that changed from the base of the PR and between d573a17 and 53be465.

📒 Files selected for processing (4)
  • src/main/java/com/capstone/pickIt/api/chat/service/ChatMessageCommandServiceImpl.java
  • src/main/java/com/capstone/pickIt/api/chat/service/ChatRoomCommandServiceImpl.java
  • src/main/java/com/capstone/pickIt/api/chat/service/ChatRoomQueryServiceImpl.java
  • src/main/java/com/capstone/pickIt/domain/chat/repository/ChatPartRepository.java

@dppfls dppfls merged commit 1a3a596 into main Jun 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Fix] DIRECT 채팅방 재입장 및 메시지 전송 시 ChatPart 복구

1 participant