diff --git a/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md b/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md index 419a5f9b..b87f36d2 100644 --- a/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md +++ b/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md @@ -525,7 +525,7 @@ spring: ### Phase 4: WebSocket handler와 메시지 저장/전달 -- [ ] **Task 4.1: JOIN_ROOM 처리** +- [x] **Task 4.1: JOIN_ROOM 처리** - Files: - Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/websocket/UserCreatorChatWebSocketHandler.kt` - Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/service/UserCreatorChatService.kt` @@ -540,8 +540,16 @@ spring: - Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketHandlerTest` - Expected: `BUILD SUCCESSFUL` - REFACTOR: 기존 private `requireParticipant` 재사용이 필요하면 public/internal 검증 method로 최소 노출한다. + - 검증 기록: + - 무엇: WebSocket handler의 `JOIN_ROOM` dispatch, service 참여자 검증 method, local session registry 등록, Redis presence 등록, `JOINED`/`ERROR` envelope 응답을 추가했다. + - 왜: 채팅방 화면 진입 시 인증 member가 해당 room 참여자인지 확인한 뒤 현재 서버 session과 Redis presence를 등록해야 하기 때문이다. + - RED: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketHandlerTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest` 실행 시 `validateParticipant`, handler constructor dependency, dispatch 부재로 `compileTestKotlin` 실패를 확인했다. + - GREEN: 같은 focused 명령 재실행 결과 `BUILD SUCCESSFUL in 1m 1s`로 통과했다. + - 인접 검증: `UserCreatorChatWebSocketConfigTest`, `UserCreatorChatPresenceServiceTest`, `UserCreatorChatRoomMessageBrokerTest` 포함 명령이 `BUILD SUCCESSFUL in 1m`로 통과했고, 이후 focused+인접 통합 명령이 `BUILD SUCCESSFUL in 3m 28s`로 통과했다. + - Reviewer 보강 RED: 같은 session이 다른 room으로 다시 `JOIN_ROOM`할 때 기존 Redis presence가 제거되지 않고, WebSocket close 시 local session/Redis presence가 정리되지 않는 테스트가 기존 구현에서 실패함을 확인했다. + - Reviewer 보강 GREEN: session attribute에 joined room을 저장하고, 재JOIN/close 시 `presenceService.markLeft`와 `sessionRegistry.remove`를 호출하도록 수정했다. `UserCreatorChatWebSocketHandlerTest`가 `BUILD SUCCESSFUL in 1m`로 통과했고, focused+인접 WebSocket 테스트 묶음이 `BUILD SUCCESSFUL in 15s`로 통과했다. -- [ ] **Task 4.2: SEND_TEXT 저장, sender ack, 수신자 WebSocket 전달** +- [x] **Task 4.2: SEND_TEXT 저장, sender ack, 수신자 WebSocket 전달** - Files: - Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/service/UserCreatorChatService.kt` - Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/websocket/UserCreatorChatWebSocketHandler.kt` @@ -557,6 +565,14 @@ spring: - Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketHandlerTest` - Expected: `BUILD SUCCESSFUL` - REFACTOR: 기존 REST text endpoint 제거 전까지 중복 저장 로직이 생기지 않도록 private save method로만 분리한다. + - 검증 기록: + - 무엇: WebSocket 전용 `sendTextMessageByWebSocket`을 추가해 기존 텍스트 저장 로직을 private `saveTextMessage`로 재사용하고, 상대방 presence가 있으면 `UserCreatorChatRoomMessageBroker.publish`로 `MESSAGE` envelope를 발행하며 sender에게는 handler가 `SEND_ACK`를 응답하도록 했다. + - 왜: REST text endpoint 제거 전까지 중복 저장 로직을 만들지 않고, WebSocket 송신 경로에서 저장/ack/수신자 전달을 처리하기 위해서다. + - 범위: 상대방 미접속 시 push payload 보강과 `chat_type` 추가는 Task 4.3 범위라 이번 task에서는 변경하지 않았다. + - RED: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketHandlerTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest` 실행 시 `sendTextMessageByWebSocket`, service WebSocket dependency, handler `SEND_TEXT` dispatch 부재로 `compileTestKotlin` 실패를 확인했다. + - GREEN: focused 명령 재실행 결과 `BUILD SUCCESSFUL in 1m 1s`로 통과했다. 이후 `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketHandlerTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketConfigTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatPresenceServiceTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatRoomMessageBrokerTest`가 `BUILD SUCCESSFUL in 3m 28s`로 통과했다. + - Reviewer 보강 RED: `JOIN_ROOM` 완료 전 `SEND_TEXT`를 보내도 메시지 저장 경로로 들어갈 수 있다는 테스트가 기존 구현에서 실패함을 확인했다. + - Reviewer 보강 GREEN: `SEND_TEXT` 처리 전 session의 joined room id가 요청 `roomId`와 일치하는지 검증하고, 미JOIN/다른 room이면 `chat.room.join_required` `ERROR`를 응답하도록 수정했다. `UserCreatorChatWebSocketHandlerTest`가 `BUILD SUCCESSFUL in 1m`로 통과했고, focused+인접 WebSocket 테스트 묶음이 `BUILD SUCCESSFUL in 15s`로 통과했다. - [ ] **Task 4.3: 상대방 미접속 시 푸시 발송** - Files: