diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index fd7a9a4..120b462 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -25,6 +25,11 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + # Docker Buildx 설정 추가 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Dockerfile을 사용하여 이미지를 빌드하고 Docker Hub에 푸시합니다. - name: Build and push Docker image uses: docker/build-push-action@v6.16.0 diff --git a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapSseService.java b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapSseService.java index f52dd44..fdcad7a 100644 --- a/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapSseService.java +++ b/src/main/java/com/teamEWSN/gitdeun/mindmap/service/MindmapSseService.java @@ -45,19 +45,26 @@ public SseEmitter createConnection(Long mapId, CustomUserDetails userDetails) { connectionsByMapId.computeIfAbsent(mapId, k -> new CopyOnWriteArrayList<>()).add(connection); - // 연결 종료 시 정리 (기존 로직 개선) - emitter.onCompletion(() -> removeConnection(mapId, connection)); - emitter.onTimeout(() -> removeConnection(mapId, connection)); + emitter.onCompletion(() -> { + removeConnection(mapId, connection); + broadcastUserListUpdate(mapId); + }); + emitter.onTimeout(() -> { + removeConnection(mapId, connection); + broadcastUserListUpdate(mapId); + }); emitter.onError(throwable -> { log.error("SSE 연결 오류 - 마인드맵 ID: {}, 사용자 ID: {}", mapId, userDetails.getId(), throwable); removeConnection(mapId, connection); + broadcastUserListUpdate(mapId); }); // 연결 확인용 초기 메시지 sendToEmitter(emitter, "마인드맵 " + mapId + " 실시간 연결 성공"); - log.info("SSE 연결 생성 - 마인드맵 ID: {}, 사용자 ID: {}", mapId, userDetails.getId()); + + broadcastUserListUpdate(mapId); return emitter; } @@ -158,9 +165,17 @@ private void removeConnection(Long mapId, SseConnection connection) { connectionsByMapId.remove(mapId); log.info("마인드맵 ID {} 의 모든 구독자 연결 종료", mapId); } + broadcastUserListUpdate(mapId); } } + // 사용자 목록 변경을 모든 클라이언트에게 브로드캐스트 + public void broadcastUserListUpdate(Long mapId) { + // 현재 접속자 목록 + List connectedUsers = getConnectedUsers(mapId); + // "user-list-updated" 라는 이벤트 이름으로 현재 접속자 목록을 전송 + sendToMapSubscribers(mapId, "user-list-updated", connectedUsers); + } // 접속된 사용자 수 조회 public int getConnectionCount(Long mapId) { diff --git a/src/main/java/com/teamEWSN/gitdeun/notification/controller/NotificationController.java b/src/main/java/com/teamEWSN/gitdeun/notification/controller/NotificationController.java index a122231..2093d46 100644 --- a/src/main/java/com/teamEWSN/gitdeun/notification/controller/NotificationController.java +++ b/src/main/java/com/teamEWSN/gitdeun/notification/controller/NotificationController.java @@ -46,6 +46,14 @@ public ResponseEntity markNotificationAsRead( return ResponseEntity.noContent().build(); } + // 모든 알림 읽음 처리 + @PatchMapping("/read-all") + public ResponseEntity markAllNotificationsAsRead( + @AuthenticationPrincipal CustomUserDetails userDetails) { + notificationService.markAllAsRead(userDetails.getId()); + return ResponseEntity.noContent().build(); + } + // 알림 삭제 @DeleteMapping("/{notificationId}") public ResponseEntity deleteNotification( diff --git a/src/main/java/com/teamEWSN/gitdeun/notification/repository/NotificationRepository.java b/src/main/java/com/teamEWSN/gitdeun/notification/repository/NotificationRepository.java index bfd820f..823cd9e 100644 --- a/src/main/java/com/teamEWSN/gitdeun/notification/repository/NotificationRepository.java +++ b/src/main/java/com/teamEWSN/gitdeun/notification/repository/NotificationRepository.java @@ -5,6 +5,9 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.Optional; @@ -20,4 +23,9 @@ public interface NotificationRepository extends JpaRepository findByIdAndUser(Long id, User user); + + // 특정 사용자의 모든 읽지 않은 알림을 읽음으로 처리하는 메서드 + @Modifying + @Query("UPDATE Notification n SET n.read = true WHERE n.user = :user AND n.read = false") + void markAllAsReadByUser(@Param("user") User user); } \ No newline at end of file diff --git a/src/main/java/com/teamEWSN/gitdeun/notification/service/NotificationService.java b/src/main/java/com/teamEWSN/gitdeun/notification/service/NotificationService.java index c430aa2..777e6c6 100644 --- a/src/main/java/com/teamEWSN/gitdeun/notification/service/NotificationService.java +++ b/src/main/java/com/teamEWSN/gitdeun/notification/service/NotificationService.java @@ -240,6 +240,18 @@ public void markAsRead(Long notificationId, Long userId) { } } + /** + * 사용자의 모든 알림을 읽음으로 처리 + */ + @Transactional + public void markAllAsRead(Long userId) { + User user = getUserById(userId); + notificationRepository.markAllAsReadByUser(user); + + // 변경된 '읽지 않은 알림 개수'(0)를 실시간으로 전송 + notificationSseService.sendUnreadCount(user.getId(), 0); + } + /** * 알림 삭제 */