From 84e9c18ae19cce1c4e019e25991e3f6c159111d8 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 19 Jun 2026 02:45:34 +0900 Subject: [PATCH] =?UTF-8?q?docs(user-creator-chat):=20WebSocket=20Phase=20?= =?UTF-8?q?5=20=EA=B8=B0=EB=A1=9D=EC=9D=84=20=EA=B0=B1=EC=8B=A0=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plan-task.md | 56 +++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md b/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md index 1abe01ac..12c53af7 100644 --- a/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md +++ b/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md @@ -645,7 +645,7 @@ spring: ### Phase 5: 기존 SSE 제거와 REST 경계 정리 -- [ ] **Task 5.1: SSE controller endpoint 제거** +- [x] **Task 5.1: SSE controller endpoint 제거** - Files: - Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/controller/UserCreatorChatController.kt` - Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceTest.kt` @@ -658,8 +658,13 @@ spring: - Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest` - Expected: `BUILD SUCCESSFUL` - REFACTOR: 사용하지 않는 `MediaType.TEXT_EVENT_STREAM_VALUE` import를 제거한다. + - 검증 기록: + - 무엇: `/events`, `/events/disconnect`, `/messages/text` REST endpoint를 controller에서 제거하고, 제거된 경로가 더 이상 매핑되지 않는 테스트를 추가했다. + - 왜: 텍스트 메시지 송수신과 presence lifecycle을 WebSocket으로만 처리하기 위해서다. + - RED: `UserCreatorChatControllerMappingTest.shouldReturnNotFoundForRemovedSseAndTextMessageEndpoints` 추가 후 기존 코드에서 매핑이 실행되어 `NestedServletException`으로 실패함을 확인했다. + - GREEN: endpoint 제거 후 `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatControllerMappingTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceIntegrationTest`가 `BUILD SUCCESSFUL in 56s`로 통과했다. -- [ ] **Task 5.2: `UserCreatorChatRealtimeService` 제거** +- [x] **Task 5.2: `UserCreatorChatRealtimeService` 제거** - Files: - Delete: `src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/service/UserCreatorChatRealtimeService.kt` - Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/service/UserCreatorChatService.kt` @@ -673,8 +678,14 @@ spring: - Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest` - Expected: `BUILD SUCCESSFUL` - REFACTOR: `rg -n "SseEmitter|connectEvents|disconnectRealtime|TEXT_EVENT_STREAM|UserCreatorChatRealtimeService" src/main src/test`로 잔여 참조가 없는지 확인한다. + - 검증 기록: + - 무엇: `UserCreatorChatRealtimeService` 파일과 `UserCreatorChatService`의 SSE 의존성, `connect`, `disconnectRealtime`, REST text service method를 제거했다. 음성 REST 전송은 유지하되 상대방 presence가 있으면 WebSocket broker로 `MESSAGE`를 발행하고, presence가 없으면 기존 푸시 이벤트를 발행하도록 정리했다. + - 왜: 기존 SSE 구현을 완전히 제거하면서도 유지 대상인 음성 업로드 API의 실시간/푸시 분기 동작을 보존하기 위해서다. + - RED: 제거 전 `rg -n "SseEmitter|TEXT_EVENT_STREAM|connectEvents|disconnectRealtime|UserCreatorChatRealtimeService" src/main src/test`에서 `UserCreatorChatRealtimeService`, controller SSE method, service/test 참조가 확인되었다. + - GREEN: `UserCreatorChatServiceTest`의 WebSocket text, voice REST WebSocket broker, voice REST push 분기 테스트가 포함된 focused 명령이 `BUILD SUCCESSFUL in 56s`로 통과했다. + - 정적 확인: `rg -n "SseEmitter|TEXT_EVENT_STREAM|connectEvents|disconnectRealtime|UserCreatorChatRealtimeService" src/main src/test` 결과가 없음을 확인했다. -- [ ] **Task 5.3: 클라이언트 연동 문서 갱신** +- [x] **Task 5.3: 클라이언트 연동 문서 갱신** - Files: - Modify: `docs/plan-task/20260513_유저크리에이터채팅방개편.md` - Modify: `docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md` @@ -686,8 +697,12 @@ spring: - 통과 확인: - Run: `./gradlew tasks --all` - Expected: `BUILD SUCCESSFUL` + - 검증 기록: + - 무엇: `docs/plan-task/20260513_유저크리에이터채팅방개편.md`의 클라이언트 연동 프롬프트를 SSE 연결/해제/REST text 전송에서 WebSocket `JOIN_ROOM`, `SEND_TEXT`, `MESSAGE`, `SEND_ACK`, `LEAVE_ROOM` 기준으로 갱신했다. + - 왜: 과거 SSE 기준 연동 프롬프트가 현재 서버 구현과 충돌하지 않도록 클라이언트 안내를 최신 계약으로 맞추기 위해서다. + - 어떻게: 유지 REST API는 방 생성/open/messages/voice로 남기고, 제거된 `/events`, `/events/disconnect`, `/messages/text` 호출과 SSE reconnect 처리 코드를 제거 대상 목록에 명시했다. -- [ ] **Task 5.4: iOS/Android 앱 반영 체크리스트 확인** +- [x] **Task 5.4: iOS/Android 앱 반영 체크리스트 확인** - Files: - Modify: `docs/20260618_유저크리에이터채팅_WebSocket전환/prd.md` - Modify: `docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md` @@ -699,6 +714,10 @@ spring: - 통과 확인: - Run: `./gradlew tasks --all` - Expected: `BUILD SUCCESSFUL` + - 검증 기록: + - 무엇: PRD와 plan-task에 iOS/Android 진입, 전송, 수신, 이탈, 재연결, 토큰 갱신, 푸시 이동, 제거 대상 API가 유지되는지 확인했다. + - 왜: 서버 저장소에는 앱 코드가 없으므로 앱 반영 범위는 문서 계약으로 추적해야 하기 때문이다. + - 결과: PRD는 기존 SSE 사용 현황과 WebSocket 전환 요구사항을 유지하고, plan-task는 앱 변경 체크리스트와 제거 대상 호출 목록을 유지한다. --- @@ -750,6 +769,35 @@ spring: - Fresh 정적 확인 Run: `rg -n "spring-boot-starter-websocket|/ws/v2/user-creator-chat|chat_type|USER_CREATOR" build.gradle.kts src/main src/test` - Fresh 정적 확인 Result: WebSocket 의존성, endpoint, FCM `chat_type=USER_CREATOR` 구현과 테스트를 확인했다. - Fresh 코드 리뷰 메모: `JOIN_ROOM`/`SEND_TEXT`/`LEAVE_ROOM`/`PING`, 미JOIN/다른 room 차단, malformed/unknown message error, 상대방 presence 유무에 따른 WebSocket publish/FCM push 분기, handshake slice 테스트 범위를 대조했다. Phase 4 범위에서 즉시 수정이 필요한 production 코드 결함은 발견하지 못했다. +- Phase 5: + - Run: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatControllerMappingTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceIntegrationTest` + - RED Result: `UserCreatorChatControllerMappingTest.shouldReturnNotFoundForRemovedSseAndTextMessageEndpoints` 추가 후 기존 코드에서는 제거 대상 endpoint가 아직 매핑되어 controller method가 실행되면서 `NestedServletException`으로 실패했다. + - GREEN Result: endpoint/service 제거와 voice delivery WebSocket 전환 후 같은 focused 명령이 `BUILD SUCCESSFUL in 56s`로 통과했다. + - Run: `rg -n "SseEmitter|TEXT_EVENT_STREAM|connectEvents|disconnectRealtime|UserCreatorChatRealtimeService|SendUserCreatorTextMessageRequest" src/main src/test` + - Result: 검색 결과 없음. SSE runtime 구현, REST text request DTO, 관련 테스트 참조가 제거되었음을 확인했다. + - Run: `./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.websocket.UserCreatorChatPresenceServiceTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatRoomMessageBrokerTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketHandshakeIntegrationTest --tests kr.co.vividnext.sodalive.fcm.FcmServiceTest` + - Result: `BUILD SUCCESSFUL in 5m 24s`; WebSocket handler/presence/broker/handshake와 FCM payload 인접 회귀가 통과했다. + - Run: `rg -n "GET /api/v2/user-creator-chat/rooms/\\{roomId\\}/events|events/disconnect|messages/text|JOIN_ROOM|SEND_TEXT|LEAVE_ROOM|chat_type" docs/20260618_유저크리에이터채팅_WebSocket전환 docs/plan-task/20260513_유저크리에이터채팅방개편.md` + - Result: 제거 대상 API와 신규 WebSocket/푸시 계약이 문서에 함께 명시되어 있음을 확인했다. + - Run: `./gradlew --no-daemon ktlintCheck` + - Result: import 정렬 수정 후 `BUILD SUCCESSFUL in 29s`. + - Run: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process` + - Result: `BUILD SUCCESSFUL in 3m 21s`; 전체 테스트 suite가 통과했다. + - Fresh 코드 리뷰 메모: SSE controller endpoint 제거, `UserCreatorChatRealtimeService` 삭제, REST text request DTO 제거, 음성 REST 전송의 WebSocket broker/FCM push 분기, 클라이언트 연동 문서 갱신 범위를 대조했다. Phase 5 범위에서 즉시 수정이 필요한 production 코드 결함은 발견하지 못했다. + - Fresh 정적 확인 Run: `rg -n "SseEmitter|TEXT_EVENT_STREAM|connectEvents|disconnectRealtime|UserCreatorChatRealtimeService|SendUserCreatorTextMessageRequest" src/main src/test` + - Fresh 정적 확인 Result: 검색 결과 없음. `src/main`/`src/test`에 SSE runtime 구현, REST text request DTO, 관련 참조가 남아 있지 않다. + - Fresh 정적 확인 Run: `rg -n "spring-boot-starter-websocket|/ws/v2/user-creator-chat|chat_type|USER_CREATOR" build.gradle.kts src/main src/test` + - Fresh 정적 확인 Result: WebSocket 의존성, endpoint, FCM `chat_type=USER_CREATOR` 구현과 테스트를 확인했다. + - Fresh 문서 확인 Run: `rg -n "GET /api/v2/user-creator-chat/rooms/\\{roomId\\}/events|events/disconnect|messages/text|JOIN_ROOM|SEND_TEXT|LEAVE_ROOM|chat_type" docs/20260618_유저크리에이터채팅_WebSocket전환 docs/plan-task/20260513_유저크리에이터채팅방개편.md` + - Fresh 문서 확인 Result: 제거 대상 API와 신규 WebSocket/푸시 계약이 문서에 함께 명시되어 있음을 확인했다. + - Fresh focused 검증 Run: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatControllerMappingTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceIntegrationTest` + - Fresh focused 검증 Result: `BUILD SUCCESSFUL in 44s`. + - Fresh 인접 회귀 Run: `./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.websocket.UserCreatorChatPresenceServiceTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatRoomMessageBrokerTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketHandshakeIntegrationTest --tests kr.co.vividnext.sodalive.fcm.FcmServiceTest` + - Fresh 인접 회귀 Result: `BUILD SUCCESSFUL in 16s`. + - Fresh lint Run: `./gradlew --no-daemon ktlintCheck` + - Fresh lint Result: `BUILD SUCCESSFUL in 7s`. + - Fresh 전체 검증 Run: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process` + - Fresh 전체 검증 Result: `BUILD SUCCESSFUL in 1m 52s`. - Phase 3: - Run: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatRedisIntegrationTest` - RED Result: 테스트 파일 부재 상태에서 `No tests found for given includes`로 실패했다.