feat(dm): 메시지 전송 pending을 requestId로 관리한다
This commit is contained in:
@@ -612,7 +612,7 @@
|
||||
- 검증 기록:
|
||||
- 2026-06-18: `DmChatRoomViewModelTest`에 `JOINED` 전 `isRealtimeConnected=false`, `JOINED` 후 `true`, 중복 `connectRealtime()` 시 socket connect와 `JOIN_ROOM`이 1회만 수행되는 검증을 추가했다. 수정 전 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomViewModelTest" --max-workers=1` 실행 결과 `DmChatRoomViewModelTest.kt:326` assertion failure로 RED를 확인했다. 이후 `DmChatRoomViewModel`에 `isRealtimeJoining`/`currentRealtimeRoomId`를 추가하고 `JOINED` 수신 시점에만 connected로 전환하도록 변경했다. 재실행 결과 같은 ViewModel 테스트가 PASS했고, `./gradlew :app:compileDebugKotlin --max-workers=1`, `./gradlew :app:ktlintCheck --max-workers=1`, `git diff --check`도 PASS했다. `ktlintCheck`에서는 기존 `.editorconfig`의 `disabled_rules` deprecation warning만 출력됐다.
|
||||
|
||||
- [ ] **Task 10.2: MESSAGE 수신 반영으로 교체**
|
||||
- [x] **Task 10.2: MESSAGE 수신 반영으로 교체**
|
||||
- Files:
|
||||
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModel.kt`
|
||||
- Modify: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModelTest.kt`
|
||||
@@ -625,8 +625,10 @@
|
||||
- 검증:
|
||||
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomViewModelTest" --max-workers=1`
|
||||
- Expected: `MESSAGE` append, 중복 `messageId` 제거, 잘못된 payload 무시 테스트가 PASS.
|
||||
- 검증 기록:
|
||||
- 2026-06-18: 기존 `socketFactory.emitMessage()` 기반 WebSocket `MESSAGE` callback이 `handleSocketEvent()`에서 `onRealtimeMessage()`로 연결되고, `DmChatMessageResponse.toUiItem()` 및 `mergeByMessageId()`로 UI 목록에 반영되는 흐름을 확인했다. `DmChatRoomViewModelTest`의 `realtime message callback은 SSE 메시지를 화면 상태에 병합한다`, `SSE 메시지는 messageId 중복을 제거하고 최신 메시지를 추가한다` 테스트를 유지해 `MESSAGE` append와 `messageId` 중복 제거 회귀를 고정했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomViewModelTest" --max-workers=1` PASS를 확인했다.
|
||||
|
||||
- [ ] **Task 10.3: SEND_TEXT/requestId pending 전송으로 교체**
|
||||
- [x] **Task 10.3: SEND_TEXT/requestId pending 전송으로 교체**
|
||||
- Files:
|
||||
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModel.kt`
|
||||
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/dm/model/DmChatUiModels.kt`
|
||||
@@ -644,6 +646,9 @@
|
||||
- 검증:
|
||||
- Run: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomViewModelTest" --max-workers=1`
|
||||
- Expected: blank 무시, pending 추가, 서로 다른 텍스트의 독립 pending, `SEND_TEXT` 송신, `SEND_ACK` requestId 매칭, `ERROR` 실패, timeout 실패, retry 새 requestId, 중복 ack 무시 테스트가 PASS.
|
||||
- 검증 기록:
|
||||
- 2026-06-18: `DmChatRoomViewModelTest`에 requestId 기반 독립 pending, `SEND_ACK` requestId 매칭, `ERROR` 실패, timeout 실패, retry 새 requestId, 중복 ACK 무시 테스트를 먼저 추가했다. 수정 전 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomViewModelTest" --max-workers=1` 실행 시 `DmChatMessageUiItem.requestId` 미정의 컴파일 오류로 RED를 확인했고, timeout 테스트는 구현 전 `DmChatRoomViewModelTest.kt:270` assertion failure로 RED를 확인했다.
|
||||
- 2026-06-18: `DmChatMessageUiItem`에 `requestId`를 추가하고, `DmChatRoomViewModel`의 단일 `isSending` 제한을 제거해 각 텍스트 전송이 새 `requestId`와 pending map으로 관리되도록 변경했다. `SEND_TEXT`는 WebSocket으로 전송하고, `SEND_ACK`/`ERROR`/send false/10초 timeout은 해당 requestId의 local item만 확정 또는 실패 처리한다. retry는 기존 `localId` item을 유지하면서 새 `requestId`를 발급하도록 변경했다. 이후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomViewModelTest" --max-workers=1` PASS를 확인했다.
|
||||
|
||||
- [ ] **Task 10.4: SEND_ACK보다 MESSAGE가 먼저 도착하는 race 처리**
|
||||
- Files:
|
||||
@@ -893,3 +898,4 @@
|
||||
- 2026-06-11: Phase 6.6 리뷰 후속으로 `onCleared()` 테스트를 source 문자열 검증에서 런타임 동작 검증으로 보강했다. 예약된 realtime 재연결이 `onCleared()` 후 실행되지 않는지, background thread에서 예약된 `mainHandler.post { action() }` callback이 `onCleared()` 후 상태를 갱신하지 않는지 확인하도록 수정했다. Phase 6.7 테스트에는 `requestLatch.await(2, TimeUnit.SECONDS)` 반환값 assertion을 추가해 timeout 검증 의도를 명확히 했다. 이후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomViewModelTest" --max-workers=1`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomViewModelTest" --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatEventClientTest" --max-workers=1`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.*" --max-workers=1`, `./gradlew :app:ktlintCheck --max-workers=1` PASS를 확인했다.
|
||||
- 2026-06-18: `docs/20260610_DM_채팅화면/prd.md`의 WebSocket 전환 요구사항을 기준으로 `plan-task.md`를 보강했다. 기존 Phase 1~8의 SSE 구현 이력은 보존하고, Phase 9~13에 WebSocket 모델/클라이언트, Repository/DI 전환, `JOIN_ROOM`/`JOINED`, `MESSAGE`, `SEND_TEXT`/`SEND_ACK`, `LEAVE_ROOM`/close, reconnect/heartbeat/token refresh, USER_CREATOR push routing, 제거 endpoint 회귀 검증, 최종 수동 확인 작업을 추가했다.
|
||||
- 2026-06-18: 현재 코드 기준으로 `DmChatApi`의 `/messages/text`, `/events/disconnect`, `DmChatEventClient`, `DmChatRoomViewModel.sendText()` REST 전송, `disconnectRealtime()` SSE 해제 경로가 남아 있음을 확인했고, 이를 Phase 9~13에서 제거/교체할 대상으로 문서화했다. 이번 단계는 계획 문서 수정만 수행했으며 Android 구현, 빌드, 테스트는 실행하지 않았다.
|
||||
- 2026-06-18: Phase 10의 Task 10.1~10.3 코드 리뷰 및 검증을 수행했다. `DmChatRoomViewModel`의 `JOINED` 기준 연결 확정, WebSocket `MESSAGE` 병합, `requestId` 단위 pending/SEND_ACK/ERROR/timeout/retry 처리를 확인했고 blocking issue는 발견하지 못했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomViewModelTest" --max-workers=1`, `./gradlew :app:compileDebugKotlin --max-workers=1`, `./gradlew :app:ktlintCheck --max-workers=1`, `git diff --check` PASS를 확인했다. `ktlintCheck`와 Gradle 실행에서는 기존 Gradle deprecation warning만 출력됐고 실패는 없었다. Task 10.4의 MESSAGE/SEND_ACK race와 Task 10.5 회귀 테스트 정리는 후속 미완료 범위로 유지한다.
|
||||
|
||||
Reference in New Issue
Block a user