# Phase 4 코드 리뷰 보고서 ## 1. 리뷰 정보 | 항목 | 내용 | |---|---| | 리뷰 대상 | Phase 4 / Task 4.1~4.2 | | 기준 commit 또는 working tree | `f1c2e6c5` + 2026-07-30 working tree | | 리뷰 일자 | 2026-07-30 | | 리뷰어 | Codex | | 기준 문서 | `prd.md`, `plan-task.md`, 홈 API 구조 정렬 후속 문서, `docs/agent-guides/*.md` | | 리뷰 상태 | 판정 완료 | ## 2. 목적과 범위 - service의 접근 검증, 조회자 context, 섹션 조립, 최종 정책 보정을 PRD와 대조했다. - `CreatorChannelHomeQueryService.kt`, `MemberContentPreferenceService.kt`, 대응 service 테스트를 포함했다. - 사용자 지시에 따라 컴파일·테스트는 실행하지 않았다. ## 3. 검토 근거 - `CreatorChannelHomeQueryService.kt:70-71`은 `getStoredPreference(viewer)` 후 `canViewAdultContent(viewer)`를 이어서 호출한다. - `MemberContentPreferenceService.kt:144-157`에서 `canViewAdultContent`ub294 `getStoredPreference(member).isAdult`를 다시 호출한다. - 두 호출은 같은 요청에서 같은 `ViewerContentPreference`를 사용할 수 있으며, `getStoredPreference`는 `REQUIRES_NEW` transaction이다. ## 4. 발견 사항 | ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal | |---|---|---|---|---|---| | `REV-P4-001` | Low | 완료 | 홈 조회가 콘텐츠 선호를 같은 요청에서 두 번 조회한다 | Task 4.3 | `P4-R1` | ### REV-P4-001 — 홈 조회가 콘텐츠 선호를 같은 요청에서 두 번 조회한다 - **심각도:** Low - **상태:** 확정 - **관련 요구사항:** Phase 4 조회자 성인 노출·콘텐츠 타입 context 조립 - **소유 Task:** Task 4.3 / `P4-R1` **관찰 내용** service가 이미 받은 `preference.isAdult`를 사용할 수 있지만 `canViewAdultContent(viewer)`를 다시 호출한다. 실제 bean에서는 이 메서드가 `getStoredPreference` 전체 경로를 반복한다. **영향** 공개 응답은 바뀌지 않지만, 홈 조회마다 독립 transaction·선호·국가 context 조회가 중복된다. **권장 조치** `preference.isAdult`를 성인 필터에 재사용하고, service 테스트에서 별도 `canViewAdultContent` 호출이 없음을 고정한다. **판정 기록** - 2026-07-30 — 두 method의 정적 호출 관계와 transaction annotation으로 확정. - 2026-07-30 — `CreatorChannelHomeQueryServiceTest` RED/GREEN으로 `preference.isAdult` 재사용과 `canViewAdultContent(viewer)` 미호출을 검증하고 완료. ## 5. plan·goal 전환 - `plan-task.md` Phase 4에 Task 4.3 / `P4-R1`을 추가했다. - 실행 objective: `REV-P4-001`을 수정하고 service 조립 회귀를 방지한다. ## 6. 리뷰 종료 판정 | 판정 항목 | 결과 | 근거 | |---|---|---| | 리뷰 범위 전체 확인 | 충족 | service·선호 service·테스트 정적 대조 | | 후보 항목 판정 완료 | 충족 | `REV-P4-001` 확정 | | 확정 항목 plan 반영 | 충족 | Task 4.3 / `P4-R1` | | 검증 명령과 결과 기록 | 충족 | 정적 검토만 실행, 테스트 미실행 사유 기록 | **최종 결론:** 수정 goal 완료. **남은 항목:** 없음. ## 7. 2차 리뷰 — 2026-07-30 ### 7.1 리뷰 범위와 방법 - service/facade의 조회자 context 조립과 기본 `now` 생성 지점을 기존 라이브 목록, 홈 Following, UTC 응답·KST 월 경계 계약과 대조했다. - 사용자 지시에 따라 테스트·컴파일·ktlint은 실행하지 않았다. ### 7.2 발견 사항 | ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal | |---|---|---|---|---|---| | `REV-P4-002` | Medium | 완료 | 다른 크리에이터가 조회하면 입장 제한이 적용되지 않는다 | Task 4.4 | `P4-R2` | | `REV-P4-003` | Medium | 완료 | 홈 기본 시각이 JVM timezone에 따라 달라진다 | Task 4.5 | `P4-R3` | #### REV-P4-002 — 다른 크리에이터가 조회하면 입장 제한이 적용되지 않는다 - **관련 요구사항:** PRD Feature B/F의 기존 라이브 목록 동일 정책, Task 4.1 - **관찰:** service는 `isViewerCreator = viewerId == creatorId`로 계산한다. 반면 기존 라이브 목록과 `HomeFollowingQueryService`는 조회자의 `MemberRole.CREATOR` 여부를 사용하며, repository는 이 값이 true일 때 `isAvailableJoinCreator` 또는 자기 라이브 예외를 적용한다. - **영향:** 크리에이터가 다른 크리에이터 채널을 볼 때 `isAvailableJoinCreator == false`인 현재/예약 라이브가 홈에 노출될 수 있다. - **권장 조치:** 조회자의 role로 flag를 산출하고 다른 크리에이터 조회 회귀 테스트를 추가한다. - **완료 기록:** 2026-07-30 — 다른 크리에이터/일반 회원/대상 본인 focused test로 `viewer.role == MemberRole.CREATOR` 계산을 검증했다. #### REV-P4-003 — 홈 기본 시각이 JVM timezone에 따라 달라진다 - **관련 요구사항:** UTC 시간 계약, KST 기준 이번 달 후원, Task 4.1·6.4 - **관찰:** facade와 service의 기본값은 `LocalDateTime.now()`인 반면 repository는 입력 `now`를 UTC로 간주해 KST 월 경계로 변환하고 DTO도 UTC offset을 붙인다. JVM timezone을 고정하는 설정은 확인되지 않았고, 인접 `HomeFollowingQueryService`는 UTC clock을 명시한다. - **영향:** JVM이 UTC가 아니면 공개/예약 콘텐츠 경계와 이번 달 후원 범위가 timezone offset만큼 이동하고, 응답 문자열도 실제 instant와 다를 수 있다. 현재 E2E fixture도 같은 `LocalDateTime.now()`를 사용해 이 조건을 드러내지 못한다. - **권장 조치:** 인자 없는 조회의 `now`를 UTC로 생성하고 비 UTC JVM timezone 회귀 테스트를 추가한다. - **완료 기록:** 2026-07-30 — facade 기본 호출을 `Asia/Seoul` JVM timezone에서 검증하고 facade/service 기본 `now`를 UTC로 고정했다. ### 7.3 plan·goal 전환과 종료 판정 - `plan-task.md` Phase 4에 Task 4.4 / `P4-R2`, Task 4.5 / `P4-R3`을 추가했다. - **최종 결론:** Medium 2건 수정 완료. - **남은 항목:** 없음. ## 8. 3차 리뷰 — 2026-07-31 - **대상:** 접근 검증 순서, 콘텐츠 선호 단일 조회, 조회자 role/effective gender 전달, facade·service 기본 UTC 시각과 전체 섹션 조립. - **방법:** `CreatorChannelHomeQueryService`, `CreatorChannelHomeFacade`와 대응 service/facade 테스트를 Task 4.1~4.5 및 기존 라이브 목록 정책과 정적 대조했다. 사용자 지시에 따라 테스트·컴파일·ktlint은 실행하지 않았다. - **결과:** `REV-P4-001`~`REV-P4-003` 수정 반영을 포함해 신규 확정 발견 사항 없음. Phase 4 후속 Task를 추가하지 않는다. - **남은 항목:** 없음. ## 9. 4차 리뷰 — 2026-07-31 - **대상:** 접근 예외 순서, 콘텐츠 선호 단일 조회, 조회자 role/effective gender, UTC `now` 전달과 전체 섹션 조립. - **방법:** query service/facade의 실제 호출 흐름과 service/facade 테스트를 기존 라이브 목록 정책 및 Task 4.1~4.5와 정적 대조했다. 사용자 지시에 따라 테스트·컴파일·ktlint은 실행하지 않았다. - **결과:** 기존 `REV-P4-001`~`REV-P4-003` 보정이 유지되며 신규 확정 발견 사항 없음. Phase 4 후속 Task를 추가하지 않는다. - **남은 항목:** 없음.