77import com .back .domain .user .repository .UserRepository ;
88import com .back .global .exception .CustomException ;
99import com .back .global .exception .ErrorCode ;
10+ import com .back .global .websocket .service .RoomParticipantService ;
1011import lombok .RequiredArgsConstructor ;
1112import lombok .extern .slf4j .Slf4j ;
1213import org .springframework .data .domain .Page ;
@@ -41,7 +42,8 @@ public class RoomService {
4142 private final RoomMemberRepository roomMemberRepository ;
4243 private final UserRepository userRepository ;
4344 private final StudyRoomProperties properties ;
44- private final RoomRedisService roomRedisService ;
45+ private final RoomParticipantService roomParticipantService ;
46+ private final org .springframework .messaging .simp .SimpMessagingTemplate messagingTemplate ;
4547
4648 /**
4749 * 방 생성 메서드
@@ -109,7 +111,7 @@ public RoomMember joinRoom(Long roomId, String password, Long userId) {
109111 }
110112
111113 // Redis에서 현재 온라인 사용자 수 조회
112- long currentOnlineCount = roomRedisService . getRoomUserCount (roomId );
114+ long currentOnlineCount = roomParticipantService . getParticipantCount (roomId );
113115
114116 // 정원 확인 (Redis 기반)
115117 if (currentOnlineCount >= room .getMaxParticipants ()) {
@@ -133,7 +135,7 @@ public RoomMember joinRoom(Long roomId, String password, Long userId) {
133135 RoomMember member = existingMember .get ();
134136
135137 // Redis에 온라인 등록
136- roomRedisService .enterRoom (userId , roomId );
138+ roomParticipantService .enterRoom (userId , roomId );
137139
138140 log .info ("기존 멤버 재입장 - RoomId: {}, UserId: {}, Role: {}" ,
139141 roomId , userId , member .getRole ());
@@ -145,7 +147,7 @@ public RoomMember joinRoom(Long roomId, String password, Long userId) {
145147 RoomMember visitorMember = RoomMember .createVisitor (room , user );
146148
147149 // Redis에만 온라인 등록
148- roomRedisService .enterRoom (userId , roomId );
150+ roomParticipantService .enterRoom (userId , roomId );
149151
150152 log .info ("신규 입장 (VISITOR) - RoomId: {}, UserId: {}, DB 저장 안함" , roomId , userId );
151153
@@ -172,7 +174,7 @@ public void leaveRoom(Long roomId, Long userId) {
172174 .orElseThrow (() -> new CustomException (ErrorCode .ROOM_NOT_FOUND ));
173175
174176 // Redis에서 퇴장 처리 (모든 사용자)
175- roomRedisService .exitRoom (userId , roomId );
177+ roomParticipantService .exitRoom (userId , roomId );
176178
177179 log .info ("방 퇴장 완료 - RoomId: {}, UserId: {}" , roomId , userId );
178180 }
@@ -234,9 +236,9 @@ public void terminateRoom(Long roomId, Long userId) {
234236 room .terminate ();
235237
236238 // Redis에서 모든 온라인 사용자 제거
237- Set <Long > onlineUserIds = roomRedisService . getRoomUsers (roomId );
239+ Set <Long > onlineUserIds = roomParticipantService . getParticipants (roomId );
238240 for (Long onlineUserId : onlineUserIds ) {
239- roomRedisService .exitRoom (onlineUserId , roomId );
241+ roomParticipantService .exitRoom (onlineUserId , roomId );
240242 }
241243
242244 log .info ("방 종료 완료 - RoomId: {}, UserId: {}, 퇴장 처리: {}명" ,
@@ -275,7 +277,10 @@ public void changeUserRole(Long roomId, Long targetUserId, RoomRole newRole, Lon
275277
276278 // 3. 대상자 확인 (DB 조회 - VISITOR는 DB에 없을 수 있음)
277279 Optional <RoomMember > targetMemberOpt = roomMemberRepository .findByRoomIdAndUserId (roomId , targetUserId );
278-
280+
281+ // 변경 전 역할 저장 (알림용)
282+ RoomRole oldRole = targetMemberOpt .map (RoomMember ::getRole ).orElse (RoomRole .VISITOR );
283+
279284 // 4. HOST로 변경하는 경우 - 기존 방장 강등
280285 if (newRole == RoomRole .HOST ) {
281286 // 기존 방장을 MEMBER로 강등
@@ -306,6 +311,28 @@ public void changeUserRole(Long roomId, Long targetUserId, RoomRole newRole, Lon
306311 log .info ("VISITOR 승격 (DB 저장) - RoomId: {}, UserId: {}, NewRole: {}" ,
307312 roomId , targetUserId , newRole );
308313 }
314+
315+ // 6. WebSocket으로 역할 변경 알림 브로드캐스트
316+ User targetUser = userRepository .findById (targetUserId )
317+ .orElseThrow (() -> new CustomException (ErrorCode .USER_NOT_FOUND ));
318+
319+ com .back .domain .studyroom .dto .RoleChangedNotification notification =
320+ com .back .domain .studyroom .dto .RoleChangedNotification .of (
321+ roomId ,
322+ targetUserId ,
323+ targetUser .getNickname (),
324+ targetUser .getProfileImageUrl (),
325+ oldRole ,
326+ newRole
327+ );
328+
329+ messagingTemplate .convertAndSend (
330+ "/topic/room/" + roomId + "/role-changed" ,
331+ notification
332+ );
333+
334+ log .info ("역할 변경 알림 전송 완료 - RoomId: {}, UserId: {}, {} → {}" ,
335+ roomId , targetUserId , oldRole , newRole );
309336 }
310337
311338 /**
@@ -332,7 +359,7 @@ public List<RoomMember> getRoomMembers(Long roomId, Long userId) {
332359 }
333360
334361 // 1. Redis에서 온라인 사용자 ID 조회
335- Set <Long > onlineUserIds = roomRedisService . getRoomUsers (roomId );
362+ Set <Long > onlineUserIds = roomParticipantService . getParticipants (roomId );
336363
337364 if (onlineUserIds .isEmpty ()) {
338365 return List .of ();
@@ -412,7 +439,7 @@ public void kickMember(Long roomId, Long targetUserId, Long requesterId) {
412439 }
413440
414441 // Redis에서 제거 (강제 퇴장)
415- roomRedisService .exitRoom (targetUserId , roomId );
442+ roomParticipantService .exitRoom (targetUserId , roomId );
416443
417444 log .info ("멤버 추방 완료 - RoomId: {}, TargetUserId: {}, RequesterId: {}" ,
418445 roomId , targetUserId , requesterId );
@@ -424,7 +451,7 @@ public void kickMember(Long roomId, Long targetUserId, Long requesterId) {
424451 * RoomResponse 생성 (Redis에서 실시간 참가자 수 조회)
425452 */
426453 public com .back .domain .studyroom .dto .RoomResponse toRoomResponse (Room room ) {
427- long onlineCount = roomRedisService . getRoomUserCount (room .getId ());
454+ long onlineCount = roomParticipantService . getParticipantCount (room .getId ());
428455 return com .back .domain .studyroom .dto .RoomResponse .from (room , onlineCount );
429456 }
430457
@@ -435,8 +462,12 @@ public java.util.List<com.back.domain.studyroom.dto.RoomResponse> toRoomResponse
435462 java .util .List <Long > roomIds = rooms .stream ()
436463 .map (Room ::getId )
437464 .collect (java .util .stream .Collectors .toList ());
438-
439- java .util .Map <Long , Long > participantCounts = roomRedisService .getBulkRoomOnlineUserCounts (roomIds );
465+
466+ java .util .Map <Long , Long > participantCounts = roomIds .stream ()
467+ .collect (java .util .stream .Collectors .toMap (
468+ roomId -> roomId ,
469+ roomId -> roomParticipantService .getParticipantCount (roomId )
470+ ));
440471
441472 return rooms .stream ()
442473 .map (room -> com .back .domain .studyroom .dto .RoomResponse .from (
@@ -452,7 +483,7 @@ public java.util.List<com.back.domain.studyroom.dto.RoomResponse> toRoomResponse
452483 public com .back .domain .studyroom .dto .RoomDetailResponse toRoomDetailResponse (
453484 Room room ,
454485 java .util .List <com .back .domain .studyroom .entity .RoomMember > members ) {
455- long onlineCount = roomRedisService . getRoomUserCount (room .getId ());
486+ long onlineCount = roomParticipantService . getParticipantCount (room .getId ());
456487
457488 java .util .List <com .back .domain .studyroom .dto .RoomMemberResponse > memberResponses = members .stream ()
458489 .map (com .back .domain .studyroom .dto .RoomMemberResponse ::from )
@@ -465,7 +496,7 @@ public com.back.domain.studyroom.dto.RoomDetailResponse toRoomDetailResponse(
465496 * MyRoomResponse 생성 (Redis에서 실시간 참가자 수 조회)
466497 */
467498 public com .back .domain .studyroom .dto .MyRoomResponse toMyRoomResponse (Room room , RoomRole myRole ) {
468- long onlineCount = roomRedisService . getRoomUserCount (room .getId ());
499+ long onlineCount = roomParticipantService . getParticipantCount (room .getId ());
469500 return com .back .domain .studyroom .dto .MyRoomResponse .of (room , onlineCount , myRole );
470501 }
471502
@@ -478,8 +509,12 @@ public java.util.List<com.back.domain.studyroom.dto.MyRoomResponse> toMyRoomResp
478509 java .util .List <Long > roomIds = rooms .stream ()
479510 .map (Room ::getId )
480511 .collect (java .util .stream .Collectors .toList ());
481-
482- java .util .Map <Long , Long > participantCounts = roomRedisService .getBulkRoomOnlineUserCounts (roomIds );
512+
513+ java .util .Map <Long , Long > participantCounts = roomIds .stream ()
514+ .collect (java .util .stream .Collectors .toMap (
515+ roomId -> roomId ,
516+ roomId -> roomParticipantService .getParticipantCount (roomId )
517+ ));
483518
484519 return rooms .stream ()
485520 .map (room -> {
0 commit comments