Skip to content

[FIX] 그룹 채팅 멤버 퇴장/추방 시 미읽음 카운트 집계 오류 #86

@ydking0911

Description

@ydking0911

버그 설명

그룹 채팅에서 메시지 전송 시 unreadCount = 멤버 수 - 1로 초기화된다. 이후 멤버가 읽으면 decreaseUnreadCount() Bulk UPDATE로 카운트를 감소시키는 구조이다.

그러나 멤버가 메시지를 읽지 않은 채로 퇴장하거나 추방되면, 해당 멤버는 이후 MarkChatRoomReadUseCase를 호출할 수 없으므로 그 멤버 몫의 카운트가 영구적으로 남는다.


재현 시나리오

  1. 4명(A, B, C, D)이 그룹 채팅방에 참여한다.
  2. A가 메시지를 전송한다 → unreadCount = 3 (B, C, D가 읽어야 함)
  3. D가 메시지를 읽지 않은 상태로 퇴장하거나 추방된다.
  4. B가 읽음 처리 → unreadCount = 2
  5. C가 읽음 처리 → unreadCount = 1
  6. 남은 멤버(A, B, C)가 모두 읽었음에도 메시지 목록에서 unreadCount = 1이 표시된다.

기대 동작

멤버가 퇴장 또는 추방될 때, 해당 멤버가 아직 읽지 않은 메시지들의 unreadCount가 함께 감소해야 한다.


실제 동작

퇴장/추방된 멤버의 미읽음 카운트가 감소되지 않아, 남은 모든 멤버가 읽은 이후에도 unreadCount > 0 상태가 고착된다. 이 값은 LoadChatMessagesUseCase에서 클라이언트에 반환되므로, 메시지 옆 "N명이 읽지 않음" 뱃지가 잘못 표시된다.


원인 분석

SendGroupChatMessageUseCase.java:48

int unreadCount = members.size() - 1;

메시지 저장 시점의 멤버 수로 unreadCount를 초기화한다.

MarkChatRoomReadUseCase.java

chatMessageService.decreaseUnreadCount(chatRoomNo, fromTime, userNo);

읽음 처리는 반드시 멤버가 직접 호출해야만 카운트가 감소한다.

LeaveChatRoomUseCase.java:50, RoommateKickedEventListener.java:43

chatRoomMemberService.leave(member);
// decreaseUnreadCount() 호출 없음

퇴장/추방 시 ChatRoomMember 행은 삭제되지만, 해당 멤버가 읽지 않은 메시지들의 unreadCount는 보정되지 않는다.


영향 범위

경로 | 설명 -- | -- LeaveChatRoomUseCase.execute() | 자발적 퇴장 시 미보정 RoommateKickedEventListener.handle() | 추방 시 미보정

LoadChatMessagesUseCase에서 unreadCount를 클라이언트에 직접 반환하므로 UI에 즉시 영향을 미친다.


제안하는 수정 방향

퇴장/추방 처리 시 leave() 호출 직전, 해당 멤버가 읽지 않은 메시지에 대해 decreaseUnreadCount()를 실행한다.

// 퇴장 처리 전에 추가
LocalDateTime fromTime = member.getLastReadAt() != null
        ? member.getLastReadAt()
        : member.getJoinedAt();
chatMessageService.decreaseUnreadCount(chatRoomNo, fromTime, member.getUserNo());

// 기존 로직
chatRoomMemberService.leave(member);

LeaveChatRoomUseCaseRoommateKickedEventListener 두 곳 모두 수정이 필요하다.
단, memberCount == 1인 경우(마지막 멤버 퇴장)는 어차피 메시지 전체를 삭제하므로 보정 불필요.


관련 파일

  • LeaveChatRoomUseCase.java
  • RoommateKickedEventListener.java
  • ChatMessageService.java

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions