From a81987c3f794d51d2ef61525ea24feeb0cab0538 Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 18 Jun 2026 14:47:02 +0900 Subject: [PATCH] =?UTF-8?q?docs(user-creator-chat):=20OSIV=20=EC=A0=84?= =?UTF-8?q?=ED=99=98=20=EA=B2=80=EC=A6=9D=20=EA=B8=B0=EB=A1=9D=EC=9D=84=20?= =?UTF-8?q?=EA=B0=B1=EC=8B=A0=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plan-task.md | 77 +++++++++++++++---- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md b/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md index 41b30969..a6859e77 100644 --- a/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md +++ b/docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md @@ -242,7 +242,7 @@ ### Phase 0: OSIV 비활성화 사전 점검 -- [ ] **Task 0.1: 현재 OSIV 설정과 위험 패턴 조사** +- [x] **Task 0.1: 현재 OSIV 설정과 위험 패턴 조사** - Files: - Modify: `docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md` - TDD 예외 사유: 코드 변경 전 사전 조사 task로, 자동화 테스트보다 정적 검색과 결과 문서화가 목적이다. @@ -257,8 +257,13 @@ - 통과 확인: - Run: `rg -n "OSIV 점검 기록|lazy loading|open-in-view" docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md` - Expected: 조사 결과와 후속 조치가 문서에 기록되어야 한다. + - 검증 기록: + - 무엇: 현재 OSIV 명시 여부와 lazy loading 위험 후보를 정적 검색으로 조사했다. + - 왜: `spring.jpa.open-in-view=false` 전환 전에 controller 응답 직렬화나 인증 principal 접근에서 트랜잭션 밖 lazy 접근 가능성을 확인하기 위해서다. + - 어떻게: `rg -n "open-in-view|spring.jpa" src/main/resources src/test/resources`, `rg -n "member\\?\\.auth|member\\.auth|member\\?\\.notification|member\\.notification|ApiResponse\\.ok\\([^\\n]*(repository|findBy|findAll)|ResponseEntity\\.ok\\([^\\n]*(repository|findBy|findAll)" src/main/kotlin/kr/co/vividnext/sodalive`, `rg -n "@Service|@Transactional|findByIdOrNull|findById\\(|findAll\\(|\\.member|\\.sender|\\.recipient|\\.auth|\\.chatRoom|\\.series|\\.audioContent" src/main/kotlin/kr/co/vividnext/sodalive`를 실행했다. + - 결과: main/test `application.yml` 모두 `spring.jpa`는 있으나 `open-in-view`는 명시되어 있지 않았다. `EventController`, `UserActionController`, `AuditionController`, `CreatorAdminContentSeriesGenreController`, `AudioContentCommentController` 등에서 `MemberAdapter.member.auth` 직접 접근 후보가 확인되었다. QueryDSL repository의 `member.auth`, `series.member`, `audioContent.member` 접근은 쿼리 식 내부 경로가 대부분이라 즉시 lazy 직렬화 위험으로 분류하지 않았다. -- [ ] **Task 0.2: OSIV off 테스트 실행 범위 선정** +- [x] **Task 0.2: OSIV off 테스트 실행 범위 선정** - Files: - Modify: `docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md` - TDD 예외 사유: 구현 전 테스트 전략 정의 task다. @@ -269,8 +274,19 @@ - 통과 확인: - Run: `rg -n "OSIV off 우선 테스트|ControllerTest|MockMvc" docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md` - Expected: 우선 실행할 테스트 목록 또는 기준이 문서에 기록되어야 한다. + - OSIV off 우선 테스트: + - `kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest`: `@SpringBootTest`, `@AutoConfigureMockMvc`, `@Transactional`, `MemberAdapter`를 함께 사용해 실제 JPA/MockMvc 경계와 인증 principal 전달 표면을 확인할 수 있다. + - `kr.co.vividnext.sodalive.v2.api.home.CreatorRankingControllerTest`: `@SpringBootTest`, `@AutoConfigureMockMvc`, `@Transactional`, `MemberAdapter`를 함께 사용해 인증 회원 id 기반 조회 표면을 확인할 수 있다. + - `kr.co.vividnext.sodalive.v2.api.creator.channel.home.adapter.in.web.CreatorChannelHomeControllerTest`: `@WebMvcTest`라 JPA lazy loading 자체 검증은 제한적이지만 controller가 `MemberAdapter.member`를 facade로 전달하는 표면 회귀를 확인할 수 있다. + - `kr.co.vividnext.sodalive.v2.api.creator.channel.live.adapter.in.web.CreatorChannelLiveControllerTest`: `@WebMvcTest`라 JPA lazy loading 자체 검증은 제한적이지만 인증 principal 전달 표면 회귀를 확인할 수 있다. + - `kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceIntegrationTest`, `kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest`: 현재 유저-크리에이터 채팅 전용 `ControllerTest`가 없어, service 트랜잭션 안 DTO 변환과 lazy 접근 안전성을 보조 확인한다. + - 검증 기록: + - 무엇: OSIV off 영향이 드러날 가능성이 높은 controller/service 테스트 범위를 선정했다. + - 왜: Phase 0.3에서 무작위 전체 테스트가 아니라 인증 principal lazy 접근, entity 직접 반환, DTO 변환 경계가 있는 테스트를 우선 실행하기 위해서다. + - 어떻게: `rg --files src/test/kotlin/kr/co/vividnext/sodalive | rg 'ControllerTest\\.kt$'`, `rg -n "@SpringBootTest|@AutoConfigureMockMvc|@Transactional|MockMvc|MemberAdapter" src/test/kotlin/kr/co/vividnext/sodalive -g "*ControllerTest.kt"`, `rg --files src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat`를 실행했다. + - 결과: `HomeRecommendationControllerTest`, `CreatorRankingControllerTest`를 우선 통합 테스트로 선정하고, `CreatorChannelHomeControllerTest`, `CreatorChannelLiveControllerTest`, user-creator-chat service 테스트를 보조 범위로 선정했다. -- [ ] **Task 0.3: OSIV off로 후보 테스트를 실행하고 실패를 분류** +- [x] **Task 0.3: OSIV off로 후보 테스트를 실행하고 실패를 분류** - Files: - Modify: `docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md` - TDD 예외 사유: 설정 전환 영향 조사 task다. @@ -285,8 +301,13 @@ - 통과 확인: - Run: `rg -n "LazyInitializationException|OSIV off 실패|OSIV off 성공" docs/20260618_유저크리에이터채팅_WebSocket전환/plan-task.md` - Expected: 테스트 결과와 분류가 문서에 기록되어야 한다. + - OSIV off 성공: + - Run: `./gradlew --no-daemon cleanTest test -Dkotlin.compiler.execution.strategy=in-process -Dspring.jpa.open-in-view=false --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceIntegrationTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests '*CreatorChannelHomeControllerTest' --tests '*CreatorChannelLiveControllerTest' --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest --tests kr.co.vividnext.sodalive.v2.api.home.CreatorRankingControllerTest` + - Result: `BUILD SUCCESSFUL in 1m 24s` + - XML 확인: `UserCreatorChatServiceIntegrationTest` 2개, `UserCreatorChatServiceTest` 8개, `CreatorChannelHomeControllerTest` 2개, `CreatorChannelLiveControllerTest` 5개, `HomeRecommendationControllerTest` 21개, `CreatorRankingControllerTest` 3개 모두 `failures=0`, `errors=0`. + - 분류: 선정한 user-creator-chat service/integration, 홈/랭킹 controller 통합 테스트, 보조 WebMvc controller 테스트 범위에서는 확인된 `LazyInitializationException` 없음. user-creator-chat DTO 변환은 현재 service 트랜잭션 안에서 수행되는 것으로 판단했다. -- [ ] **Task 0.4: lazy loading 의존 제거 후 OSIV off 명시** +- [x] **Task 0.4: lazy loading 의존 제거 후 OSIV off 명시** - Files: - Modify: `src/main/resources/application.yml` - Modify: `src/test/resources/application.yml` @@ -309,6 +330,11 @@ spring: - Run: `./gradlew test -Dspring.jpa.open-in-view=false --tests '<수정한 테스트>'` - Expected: `BUILD SUCCESSFUL` - REFACTOR: WebSocket 전환 작업과 관계없는 API 스키마 변경은 하지 않는다. + - 검증 기록: + - 무엇: main/test 설정에 `spring.jpa.open-in-view=false`를 명시했다. + - 왜: Phase 0.3에서 user-creator-chat service/integration, 홈/랭킹 controller 통합 테스트, 보조 WebMvc controller 테스트 범위에 `LazyInitializationException`이 없었고, OSIV 정책을 명시해야 이후 WebSocket 전환 작업의 트랜잭션 경계를 안전하게 유지할 수 있기 때문이다. + - 어떻게: `src/main/resources/application.yml`, `src/test/resources/application.yml`의 `spring.jpa` 아래에 `open-in-view: false`를 추가했다. + - 결과: 확인된 lazy loading 재현 실패가 없어 production code의 service/repository/controller 수정은 하지 않았다. 공개 API 스키마 변경도 없다. --- @@ -579,18 +605,39 @@ spring: ## 5. 구현 후 검증 기록 -아직 구현 전이다. 각 task 완료 즉시 무엇을, 왜, 어떻게 검증했는지 실행 명령과 결과를 이 섹션 또는 해당 task 아래에 누적한다. +- 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` 명시를 확인했다. + - Run: `./gradlew --no-daemon cleanTest test -Dkotlin.compiler.execution.strategy=in-process -Dspring.jpa.open-in-view=false --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceIntegrationTest --tests kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatServiceTest --tests '*CreatorChannelHomeControllerTest' --tests '*CreatorChannelLiveControllerTest' --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest --tests kr.co.vividnext.sodalive.v2.api.home.CreatorRankingControllerTest` + - Result: `BUILD SUCCESSFUL in 1m 24s`; XML 기준 `UserCreatorChatServiceIntegrationTest` 2개, `UserCreatorChatServiceTest` 8개, `CreatorChannelHomeControllerTest` 2개, `CreatorChannelLiveControllerTest` 5개, `HomeRecommendationControllerTest` 21개, `CreatorRankingControllerTest` 3개 모두 `failures=0`, `errors=0`. ## 6. OSIV 점검 기록 -아직 점검 전이다. Task 0.1부터 다음 형식으로 누적한다. - -```markdown - API/기능: - - 파일: - - 위험 유형: - - lazy 접근 대상: - - OSIV off 테스트: - - 수정 방향: - - 처리 상태: -``` + - 파일: `src/main/resources/application.yml`, `src/test/resources/application.yml` + - 위험 유형: OSIV 정책 미명시 + - lazy 접근 대상: 해당 없음 + - OSIV off 테스트: `rg -n "open-in-view|spring.jpa" src/main/resources src/test/resources` + - 수정 방향: main/test `spring.jpa.open-in-view=false` 명시 + - 처리 상태: 완료 +- API/기능: 유저-크리에이터 채팅 room open/messages/voice service 경계 + - 파일: `src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceIntegrationTest.kt`, `src/test/kotlin/kr/co/vividnext/sodalive/v2/usercreatorchat/UserCreatorChatServiceTest.kt` + - 위험 유형: service/facade 트랜잭션 밖 DTO 변환 중 lazy 연관 접근 가능성 + - lazy 접근 대상: `UserCreatorChatParticipant.member`, `UserCreatorChatMessage.participant` + - OSIV off 테스트: Phase 0 묶음 검증 명령에 포함 + - 수정 방향: 현재 범위에서는 DTO 변환이 service 트랜잭션 안에서 수행되어 추가 수정 없음 + - 처리 상태: XML 기준 `UserCreatorChatServiceIntegrationTest` 2개, `UserCreatorChatServiceTest` 8개 모두 `failures=0`, `errors=0` +- API/기능: 홈 추천/크리에이터 랭킹 controller 통합 테스트 + - 파일: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/HomeRecommendationControllerTest.kt`, `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/CreatorRankingControllerTest.kt` + - 위험 유형: controller 요청 처리 또는 응답 직렬화 중 lazy 연관 접근 가능성 + - lazy 접근 대상: `MemberAdapter.member.auth`, 홈/랭킹 조회 응답 DTO 관련 entity 연관 + - OSIV off 테스트: Phase 0 묶음 검증 명령에 포함 + - 수정 방향: 확인된 `LazyInitializationException` 없음. 추가 lazy 수정 없음 + - 처리 상태: XML 기준 `HomeRecommendationControllerTest` 21개, `CreatorRankingControllerTest` 3개 모두 `failures=0`, `errors=0` +- API/기능: 크리에이터 채널 home/live WebMvc controller 표면 + - 파일: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/adapter/in/web/CreatorChannelHomeControllerTest.kt`, `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/live/adapter/in/web/CreatorChannelLiveControllerTest.kt` + - 위험 유형: controller에서 인증 principal을 facade로 전달하는 표면 회귀 가능성 + - lazy 접근 대상: `MemberAdapter.member` + - OSIV off 테스트: Phase 0 묶음 검증 명령에 포함 + - 수정 방향: JPA lazy loading 직접 검증은 아니며, WebMvc 표면 회귀만 확인 + - 처리 상태: XML 기준 `CreatorChannelHomeControllerTest` 2개, `CreatorChannelLiveControllerTest` 5개 모두 `failures=0`, `errors=0`