docs(user-creator-chat): WebSocket Phase 2 기록을 갱신한다

This commit is contained in:
2026-06-18 17:06:59 +09:00
parent af1e9b565a
commit afa57b70de
2 changed files with 40 additions and 3 deletions

View File

@@ -403,7 +403,7 @@ spring:
### Phase 2: 메시지 프로토콜과 local session registry 추가
- [ ] **Task 2.1: WebSocket message envelope 정의**
- [x] **Task 2.1: WebSocket message envelope 정의**
- Files:
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/websocket/UserCreatorChatWebSocketMessage.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/websocket/UserCreatorChatWebSocketMessageTest.kt`
@@ -416,8 +416,14 @@ spring:
- Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketMessageTest`
- Expected: `BUILD SUCCESSFUL`
- REFACTOR: payload는 초기 구현에서 `JsonNode`로 받고, 타입별 request DTO 변환은 handler dispatch에서 수행한다.
- 검증 기록:
- 무엇: WebSocket request/response envelope와 message type enum을 추가했다.
- 왜: Phase 4 handler dispatch에서 raw JSON 메시지를 공통 계약으로 역직렬화하기 위해서다.
- 어떻게: `UserCreatorChatWebSocketMessage``type`, `requestId`, `roomId`, `payload: JsonNode`를 갖는 data class로 두고, `UserCreatorChatWebSocketMessageType``JOIN_ROOM`, `SEND_TEXT`, `LEAVE_ROOM`, `PING`, `JOINED`, `MESSAGE`, `SEND_ACK`, `ERROR`, `PONG`을 정의했다.
- RED: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketMessageTest` 실행 시 `UserCreatorChatWebSocketMessageType`, `UserCreatorChatWebSocketMessage` unresolved reference로 `compileTestKotlin` 실패를 확인했다.
- 결과: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketMessageTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketSessionRegistryTest``BUILD SUCCESSFUL in 4m 30s`로 통과했다.
- [ ] **Task 2.2: local WebSocket session registry 추가**
- [x] **Task 2.2: local WebSocket session registry 추가**
- Files:
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/websocket/UserCreatorChatWebSocketSessionRegistry.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/websocket/UserCreatorChatWebSocketSessionRegistryTest.kt`
@@ -430,6 +436,15 @@ spring:
- Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketSessionRegistryTest`
- Expected: `BUILD SUCCESSFUL`
- REFACTOR: registry는 local session만 관리하고 Redis를 직접 호출하지 않는다.
- 검증 기록:
- 무엇: local WebSocket session registry를 추가했다.
- 왜: 다중 인스턴스 구조에서 현재 서버에 붙은 session만 roomId/memberId/sessionId 기준으로 관리하기 위해서다.
- 어떻게: `ConcurrentHashMap`으로 room/member별 session map과 sessionId index를 관리하고, 같은 session이 다른 room으로 등록되면 기존 room mapping을 제거하도록 했다. 동시 같은 session room 전환은 sessionId hash 기반 고정 striped lock으로 `register`/`remove`를 직렬화했다. Redis 호출은 포함하지 않았다.
- RED: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketSessionRegistryTest` 실행 시 `UserCreatorChatWebSocketSessionRegistry` unresolved reference로 `compileTestKotlin` 실패를 확인했다.
- RED: reviewer 지적 후 추가한 동시 같은 session room 전환 테스트가 기존 구현에서 `Expected concurrent same-session room switch to leave exactly one active room mapping` assertion으로 실패함을 확인했다.
- RED: 운영 트래픽에서 sessionId별 lock map이 누적될 수 있다는 리뷰를 반영해 추가한 `sessionId별 lock map을 유지하지 않는다` 테스트가 기존 구현에서 실패함을 확인했다.
- 결과: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketSessionRegistryTest``BUILD SUCCESSFUL in 3m 41s`로 통과했다.
- 결과: 실제 실행한 Phase 2 focused 명령 `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketMessageTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketSessionRegistryTest``BUILD SUCCESSFUL in 1m 46s`로 통과했다.
---
@@ -640,6 +655,9 @@ spring:
## 5. 구현 후 검증 기록
- Phase 2:
- Run: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketMessageTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.websocket.UserCreatorChatWebSocketSessionRegistryTest`
- Result: `BUILD SUCCESSFUL in 1m 46s`; message envelope enum/JsonNode 역직렬화 테스트 3개와 local session registry 등록/조회/제거/room 전환/동시 같은 session 전환/session lock map 비유지 테스트 6개가 통과했다.
- Phase 0:
- Run: `rg -n "open-in-view|spring.jpa" src/main/resources src/test/resources`
- Result: main/test 설정의 `spring.jpa.open-in-view=false` 명시를 확인했다.