docs(user-creator-chat): 채팅 푸시 deep link 계약을 기록한다
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
**Goal:** 유저-크리에이터 1:1 채팅의 SSE 실시간 연결을 제거하고, 채팅방 화면 진입 중에만 유지되는 raw WebSocket + Redis presence/pub-sub 구조로 전환한다.
|
||||
|
||||
**Architecture:** REST는 방 생성, 방 열기, 과거 메시지 조회, 음성 업로드에 유지하고 텍스트 실시간 송수신과 방 presence는 WebSocket으로 처리한다. 서버는 다중 인스턴스를 전제로 local WebSocket session registry와 Redis presence/pub-sub을 함께 사용한다. 상대방이 해당 `roomId`에 접속 중이면 WebSocket으로만 전달하고, 접속 중이 아니면 기존 FCM/APNs 푸시 흐름에 `roomId`/`chat_type` 이동 정보를 포함해 발송한다.
|
||||
**Architecture:** REST는 방 생성, 방 열기, 과거 메시지 조회, 음성 업로드에 유지하고 텍스트 실시간 송수신과 방 presence는 WebSocket으로 처리한다. 서버는 다중 인스턴스를 전제로 local WebSocket session registry와 Redis presence/pub-sub을 함께 사용한다. 상대방이 해당 `roomId`에 접속 중이면 WebSocket으로만 전달하고, 접속 중이 아니면 기존 FCM/APNs 푸시 흐름에 `deep_link` 이동 정보만 포함해 발송한다.
|
||||
|
||||
**Tech Stack:** Kotlin, Spring Boot 2.7.14, Java 17, Spring WebSocket, Spring Data Redis, Redis pub/sub, Spring Data JPA, JUnit 5, Mockito, Gradle Wrapper
|
||||
|
||||
@@ -31,9 +31,8 @@
|
||||
- 상대방이 같은 `roomId`에 WebSocket presence 있음: 푸시 미발송
|
||||
- 상대방이 같은 `roomId`에 WebSocket presence 없음: 푸시 발송
|
||||
- 푸시 payload 필수값:
|
||||
- `room_id`
|
||||
- `message_id`
|
||||
- `chat_type=USER_CREATOR`
|
||||
- `deep_link`: 운영 `voiceon://chat/{roomId}`, 개발/테스트 `voiceon-test://chat/{roomId}`
|
||||
- v2 채팅 푸시에서는 `room_id`, `message_id`, `chat_type` data payload를 사용하지 않는다.
|
||||
- Redis key 기본안:
|
||||
- `v2:user-creator-chat:ws:presence:{roomId}:{memberId}:{sessionId}`
|
||||
- `v2:user-creator-chat:ws:room:{roomId}:member:{memberId}:sessions`
|
||||
@@ -84,9 +83,9 @@
|
||||
|
||||
### 푸시 payload
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmEvent.kt`
|
||||
- 필요 시 `chatType` 또는 동등한 payload 값을 추가한다.
|
||||
- 필요 시 v2 채팅용 deep link 값을 추가한다.
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmService.kt`
|
||||
- `chat_type` data payload를 추가한다.
|
||||
- v2 채팅 푸시는 `deep_link`만 data payload에 포함하고 `room_id`, `message_id`, `chat_type`은 제외한다.
|
||||
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/fcm/FcmServiceTest.kt`
|
||||
|
||||
### SSE 제거
|
||||
@@ -228,10 +227,10 @@
|
||||
- access token이 refresh되면 기존 WebSocket을 닫고 새 token으로 다시 연결한다.
|
||||
|
||||
### 푸시 이동
|
||||
- 푸시 payload의 `chat_type == "USER_CREATOR"`와 `room_id`를 확인한다.
|
||||
- 사용자가 푸시를 터치하면 `room_id`에 해당하는 채팅방 화면으로 이동한다.
|
||||
- 푸시 payload의 `deep_link`를 확인한다.
|
||||
- 사용자가 푸시를 터치하면 `voiceon://chat/{roomId}` 또는 `voiceon-test://chat/{roomId}`의 `{roomId}`에 해당하는 채팅방 화면으로 이동한다.
|
||||
- 푸시 진입 후에도 일반 진입과 동일하게 `openRoom` 호출 후 WebSocket 연결과 `JOIN_ROOM`을 수행한다.
|
||||
- `room_id`가 없거나 숫자로 파싱할 수 없으면 채팅방 직접 이동을 하지 않고 앱 기본 알림 처리로 fallback 한다.
|
||||
- `deep_link`가 없거나 채팅방 room id를 해석할 수 없으면 채팅방 직접 이동을 하지 않고 앱 기본 알림 처리로 fallback 한다.
|
||||
|
||||
### 클라이언트 제거 대상
|
||||
- `GET /api/v2/user-creator-chat/rooms/{roomId}/events` 호출
|
||||
@@ -568,7 +567,7 @@ spring:
|
||||
- 검증 기록:
|
||||
- 무엇: 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에서는 변경하지 않았다.
|
||||
- 범위: 상대방 미접속 시 push payload 보강은 Task 4.3 범위라 이번 task에서는 변경하지 않았다. 현재 계약은 v2 채팅 푸시 payload에 `deep_link`만 포함하는 것이다.
|
||||
- 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`를 보내도 메시지 저장 경로로 들어갈 수 있다는 테스트가 기존 구현에서 실패함을 확인했다.
|
||||
@@ -581,21 +580,27 @@ spring:
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmService.kt`
|
||||
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceTest.kt`
|
||||
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/fcm/FcmServiceTest.kt`
|
||||
- RED: 상대방 presence가 없으면 `FcmEvent`가 `roomId`, `messageId`, `chatType=USER_CREATOR` 정보를 포함하는 테스트를 작성한다.
|
||||
- RED: `FcmService`가 FCM data payload에 `chat_type`을 넣는 테스트를 작성한다.
|
||||
- RED: 상대방 presence가 없으면 `FcmEvent`가 v2 채팅용 `deep_link` 생성 정보를 포함하고 `roomId`, `messageId`, `chatType=USER_CREATOR` data payload를 포함하지 않는 테스트를 작성한다.
|
||||
- RED: `FcmService`가 FCM data payload에 `deep_link=voiceon[-test]://chat/{roomId}`만 넣는 테스트를 작성한다.
|
||||
- 실패 확인:
|
||||
- Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.fcm.FcmServiceTest`
|
||||
- Expected: chat_type payload 부재로 실패한다.
|
||||
- GREEN: `FcmEvent` 또는 `FcmService.send`에 chat type을 추가하고 user-creator chat push 발행 시 채운다.
|
||||
- Expected: v2 채팅 deep_link payload 부재 또는 기존 `room_id`/`message_id`/`chat_type` 잔존으로 실패한다.
|
||||
- GREEN: v2 채팅 push 발행 시 `deep_link`만 채우고 기존 `room_id`, `message_id`, `chat_type` data payload는 제거한다.
|
||||
- 통과 확인:
|
||||
- Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.fcm.FcmServiceTest`
|
||||
- Expected: `BUILD SUCCESSFUL`
|
||||
- REFACTOR: 기존 live/content/community deep link payload와 충돌하지 않게 `chat_type`은 message category에서만 채운다.
|
||||
- REFACTOR: 기존 live/content/community deep link payload와 충돌하지 않게 v2 채팅 deep link는 `voiceon[-test]://chat/{roomId}` 규칙으로만 생성한다.
|
||||
- 검증 기록:
|
||||
- 무엇: WebSocket 텍스트 전송에서 상대방 presence가 없으면 `roomId`, `messageId`, `chatType=USER_CREATOR`를 포함한 FCM 이벤트를 발행하고, FCM data payload에 `chat_type`을 포함하도록 했다.
|
||||
- 현재 요구사항 변경: v2 채팅 푸시 payload는 `deep_link`만 사용하고 `room_id`, `message_id`, `chat_type`은 제거한다. 기존 완료 기록은 이전 계약 기준 이력이며, 후속 구현에서 새 계약에 맞춰 수정한다.
|
||||
- 무엇: WebSocket 텍스트/REST 음성 전송에서 상대방 presence가 없으면 `FcmEvent.deepLinkValue=CHAT`, `deepLinkId=roomId`만 포함한 FCM 이벤트를 발행하도록 수정했다. FCM data payload 생성은 `deep_link=voiceon[-test]://chat/{roomId}`만 포함하고 `room_id`, `message_id`, `chat_type`을 제외한다.
|
||||
- 왜: 상대방이 같은 `roomId`에 접속 중이 아닐 때 푸시 터치로 유저-크리에이터 채팅방에 이동해야 하기 때문이다.
|
||||
- RED: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.fcm.FcmServiceTest` 실행 시 `FcmEvent.chatType`, `FcmService.buildDataPayload` unresolved reference로 `compileTestKotlin` 실패를 확인했다.
|
||||
- GREEN: 같은 focused 명령 재실행 결과 `BUILD SUCCESSFUL in 4m 30s`로 통과했다.
|
||||
- 이전 계약 기준 RED: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.fcm.FcmServiceTest` 실행 시 `FcmEvent.chatType`, `FcmService.buildDataPayload` unresolved reference로 `compileTestKotlin` 실패를 확인했다.
|
||||
- 이전 계약 기준 GREEN: 같은 focused 명령 재실행 결과 `BUILD SUCCESSFUL in 4m 30s`로 통과했다. 현재 요구사항은 위 RED/GREEN 항목처럼 `deep_link` 단일 payload로 후속 수정한다.
|
||||
- Fresh 검증 Run: `./gradlew --no-daemon test -Dkotlin.compiler.execution.strategy=in-process --rerun-tasks --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests kr.co.vividnext.sodalive.fcm.FcmServiceTest`
|
||||
- Fresh 검증 Result: `BUILD SUCCESSFUL in 3m 45s`; focused 테스트 10 actionable tasks가 실제 실행됐다.
|
||||
- Fresh 정적 확인 Run: `rg -n "room_id|message_id|chat_type|deep_link|voiceon://chat|voiceon-test://chat" docs/20260618_유저크리에이터채팅_WebSocket전환 src/main/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat src/test/kotlin/kr/co/vividnext/sodalive/fcm src/main/kotlin/kr/co/vividnext/sodalive/fcm`
|
||||
- Fresh 정적 확인 Result: v2 채팅 service/test 경로는 `deepLinkValue=CHAT`, `deepLinkId=roomId`, `deep_link` 테스트로 확인됐고, `room_id`/`message_id`/`chat_type`은 공통 FCM payload helper와 문서상 제외 조건에만 남아 있음을 확인했다.
|
||||
- 코드 리뷰 메모: `UserCreatorChatService.publishMessagePush`, `FcmSendListener.sendPush`, `FcmService.buildDeepLink/buildDataPayload`, 관련 단위 테스트를 대조했다. Task 4.3 범위에서 즉시 수정이 필요한 production 코드 결함은 발견하지 못했다.
|
||||
|
||||
- [x] **Task 4.4: LEAVE_ROOM, close, heartbeat 처리**
|
||||
- Files:
|
||||
@@ -691,7 +696,7 @@ spring:
|
||||
- Modify: `docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md`
|
||||
- TDD 예외 사유: 문서 갱신은 자동화 테스트 작성 대상이 아니다.
|
||||
- 대체 검증 방법:
|
||||
- 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전환`
|
||||
- Run: `rg -n "GET /api/v2/user-creator-chat/rooms/\\{roomId\\}/events|events/disconnect|messages/text|JOIN_ROOM|SEND_TEXT|LEAVE_ROOM|deep_link" docs/20260618_유저크리에이터채팅_WebSocket전환`
|
||||
- Expected: 제거 대상 API와 신규 WebSocket/푸시 계약이 모두 문서에 명시되어야 한다.
|
||||
- GREEN: 클라이언트 연동 순서를 `openRoom` REST 호출 후 WebSocket connect + `JOIN_ROOM`으로 갱신한다.
|
||||
- 통과 확인:
|
||||
@@ -708,7 +713,7 @@ spring:
|
||||
- Modify: `docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md`
|
||||
- TDD 예외 사유: 앱 코드가 현재 서버 저장소에 없으므로 자동화 테스트를 작성할 수 없다.
|
||||
- 대체 검증 방법:
|
||||
- Run: `rg -n "iOS|Android|JOIN_ROOM|SEND_ACK|MESSAGE|LEAVE_ROOM|푸시|room_id|chat_type" docs/20260618_유저크리에이터채팅_WebSocket전환/prd.md docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md`
|
||||
- Run: `rg -n "iOS|Android|JOIN_ROOM|SEND_ACK|MESSAGE|LEAVE_ROOM|푸시|room_id|deep_link" docs/20260618_유저크리에이터채팅_WebSocket전환/prd.md docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md`
|
||||
- Expected: 클라이언트 변경 사항이 PRD와 plan-task 양쪽에 기록되어야 한다.
|
||||
- GREEN: 앱 담당자가 구현해야 할 진입, 전송, 수신, 이탈, 재연결, 푸시 이동, 제거 대상 API를 문서에 유지한다.
|
||||
- 통과 확인:
|
||||
@@ -739,7 +744,7 @@ spring:
|
||||
- Expected: `BUILD SUCCESSFUL`
|
||||
- Run: `rg -n "SseEmitter|TEXT_EVENT_STREAM|connectEvents|disconnectRealtime|UserCreatorChatRealtimeService" src/main src/test`
|
||||
- Expected: 검색 결과 없음
|
||||
- Run: `rg -n "spring-boot-starter-websocket|/ws/v2/user-creator-chat|chat_type|USER_CREATOR" build.gradle.kts src/main src/test`
|
||||
- Run: `rg -n "spring-boot-starter-websocket|/ws/v2/user-creator-chat|deep_link|USER_CREATOR" build.gradle.kts src/main src/test`
|
||||
- Expected: WebSocket 의존성, endpoint, 푸시 payload 관련 구현이 확인됨
|
||||
|
||||
---
|
||||
@@ -766,8 +771,8 @@ spring:
|
||||
- Fresh lint Result: `BUILD SUCCESSFUL in 7s`.
|
||||
- Fresh 정적 확인 Run: `rg -n "open-in-view" src/main/resources src/test/resources`
|
||||
- Fresh 정적 확인 Result: main/test 설정의 `spring.jpa.open-in-view=false` 명시를 확인했다.
|
||||
- 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 "spring-boot-starter-websocket|/ws/v2/user-creator-chat|deep_link|USER_CREATOR" build.gradle.kts src/main src/test`
|
||||
- Fresh 정적 확인 Result: WebSocket 의존성, endpoint, FCM `deep_link` 구현과 테스트를 확인했다. v2 채팅 푸시 payload는 `deep_link` 단일 값이다.
|
||||
- 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`
|
||||
@@ -777,7 +782,7 @@ spring:
|
||||
- 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`
|
||||
- Run: `rg -n "GET /api/v2/user-creator-chat/rooms/\\{roomId\\}/events|events/disconnect|messages/text|JOIN_ROOM|SEND_TEXT|LEAVE_ROOM|deep_link" docs/20260618_유저크리에이터채팅_WebSocket전환 docs/plan-task/20260513_유저크리에이터채팅방개편.md`
|
||||
- Result: 제거 대상 API와 신규 WebSocket/푸시 계약이 문서에 함께 명시되어 있음을 확인했다.
|
||||
- Run: `./gradlew --no-daemon ktlintCheck`
|
||||
- Result: import 정렬 수정 후 `BUILD SUCCESSFUL in 29s`.
|
||||
@@ -786,9 +791,9 @@ spring:
|
||||
- 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 정적 확인 Run: `rg -n "spring-boot-starter-websocket|/ws/v2/user-creator-chat|deep_link|USER_CREATOR" build.gradle.kts src/main src/test`
|
||||
- Fresh 정적 확인 Result: WebSocket 의존성, endpoint, FCM `deep_link` 구현과 테스트를 확인했다. v2 채팅 푸시 payload는 `deep_link` 단일 값이다.
|
||||
- Fresh 문서 확인 Run: `rg -n "GET /api/v2/user-creator-chat/rooms/\\{roomId\\}/events|events/disconnect|messages/text|JOIN_ROOM|SEND_TEXT|LEAVE_ROOM|deep_link" 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`.
|
||||
|
||||
Reference in New Issue
Block a user