feat(home): 팔로잉 탭 최근 소식 정책을 보강한다
This commit is contained in:
162
docs/20260625_메인_홈_팔로잉_탭_API/reviews/phase-7-review.md
Normal file
162
docs/20260625_메인_홈_팔로잉_탭_API/reviews/phase-7-review.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# Phase 7 코드 리뷰 보고서
|
||||
|
||||
## 1. 리뷰 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 리뷰 대상 | Phase 7 / Task 7.1 |
|
||||
| 기준 commit 또는 working tree | `e6f56f24` + 2026-07-30 working tree |
|
||||
| 리뷰 일자 | 2026-07-30 |
|
||||
| 리뷰어 | Codex |
|
||||
| 기준 문서 | `prd.md` Feature F·Decision Log, `plan-task.md` Phase 7 |
|
||||
| 리뷰 상태 | 판정 완료 |
|
||||
|
||||
## 2. 목적과 범위
|
||||
|
||||
- 최신 공개 크리에이터 랭킹 배치 필터와 콘텐츠별 최신 랭킹 중복 제거가 모든 확정 edge case에서 limit 전에 적용되는지 검토했다.
|
||||
- 현재 working tree의 repository, repository test, E2E fixture 변경을 포함했다.
|
||||
- 사용자의 지시에 따라 컴파일과 테스트는 실행하지 않았다. 기존 Phase 7 성공 기록은 참고 증거로만 사용했다.
|
||||
|
||||
## 3. 발견 사항 요약
|
||||
|
||||
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|
||||
|---|---|---|---|---|---|
|
||||
| `REV-P7-001` | High | 확정 | 최신 완료 배치가 0건이면 과거 크리에이터 랭킹이 다시 최신으로 판정된다 | Task 7.2 | `P7-R1` |
|
||||
| `REV-P7-002` | High | 확정 | 노출 불가능한 최신 콘텐츠 랭킹 row가 이전의 노출 가능한 row를 가린다 | Task 7.3 | `P7-R2` |
|
||||
|
||||
## 4. 발견 사항 상세
|
||||
|
||||
### REV-P7-001 — 최신 완료 배치가 0건이면 과거 크리에이터 랭킹이 다시 최신으로 판정된다
|
||||
|
||||
- **심각도:** High
|
||||
- **상태:** 확정
|
||||
- **관련 요구사항:** 최신 공개 배치만 노출, 최신 배치에 없는 크리에이터의 과거 순위 미보충
|
||||
- **소유 Task:** 신규 Task 7.2 / `P7-R1`
|
||||
|
||||
**관찰 내용**
|
||||
|
||||
최신 배치 조건은 `creator_ranking_snapshot.visibleFromAtUtc.max()`만 조회한다. 최신 집계가 성공했지만 점수 조건을 통과한
|
||||
snapshot이 0건이면 해당 배치를 나타내는 snapshot row가 없으므로 max 값은 직전 배치 시각으로 남는다.
|
||||
|
||||
랭킹 job은 결과가 0건이어도 `creator_ranking_snapshot_job`에 `WEEKLY`, `DONE`, `visibleFromAtUtc`를 남기므로 완료 배치를
|
||||
식별할 근거가 이미 있지만 현재 팔로잉 조회는 이를 사용하지 않는다.
|
||||
|
||||
**근거**
|
||||
|
||||
- 코드: `DefaultHomeFollowingQueryRepository.kt:428-451`
|
||||
- 코드: `DefaultCreatorRankingSnapshotRepository.kt:51-65`
|
||||
- 코드: `CreatorRankingSnapshotJobService.kt:52-69`
|
||||
- 테스트 공백: `shouldFindOnlyLatestVisibleCreatorRankingBatchInRecentNews`는 최신 배치에 snapshot이 1건 이상인 경우만 검증한다.
|
||||
|
||||
**정적 재현 절차**
|
||||
|
||||
1. 직전 주간 snapshot과 같은 시각의 `CREATOR_RANKING` inbox를 둔다.
|
||||
2. 더 최신 주간 job을 `DONE`으로 완료하지만 집계 결과 snapshot은 0건으로 둔다.
|
||||
3. 최신 job 공개 시각 이후 API를 조회한다.
|
||||
4. 요구 결과는 크리에이터 랭킹 0건이지만, 현재 subquery max는 직전 snapshot 시각이므로 과거 inbox가 노출된다.
|
||||
|
||||
**영향**
|
||||
|
||||
활동 부족 등으로 최신 배치 결과가 비어 있는 주에 명시적으로 금지된 과거 랭킹 보충이 발생한다.
|
||||
|
||||
**권장 조치**
|
||||
|
||||
결과 row와 독립적으로 남는 최신 공개 `DONE` job을 배치 식별 기준으로 사용하고, 최신 빈 배치에서는 과거 snapshot으로
|
||||
fallback하지 않는 회귀 테스트를 추가한다.
|
||||
|
||||
**판정 기록**
|
||||
|
||||
- 2026-07-30 — snapshot 교체와 job 완료 흐름을 정적으로 추적해 확정했다.
|
||||
|
||||
### REV-P7-002 — 노출 불가능한 최신 콘텐츠 랭킹 row가 이전의 노출 가능한 row를 가린다
|
||||
|
||||
- **심각도:** High
|
||||
- **상태:** 확정
|
||||
- **관련 요구사항:** 같은 콘텐츠의 노출 가능한 row 중 최신 1건 조회
|
||||
- **소유 Task:** 신규 Task 7.3 / `P7-R2`
|
||||
|
||||
**관찰 내용**
|
||||
|
||||
외부 row는 `CONTENT_RANKING`의 `rank is not null`, inbox 성인 조건 등으로 노출 가능 여부를 확인한다. 그러나
|
||||
`latestContentRankingNewsCondition(...)`의 newer-row subquery는 member/type/target/active/visible/order만 확인하고
|
||||
`rank is not null`과 회원별 성인 조건을 확인하지 않는다.
|
||||
|
||||
따라서 더 최신 row의 `rank`가 null이면 최신 row는 외부 조건에서 제외되면서도 이전 정상 row를 subquery에서 가려 결과가 0건이 된다.
|
||||
|
||||
**근거**
|
||||
|
||||
- 코드: `DefaultHomeFollowingQueryRepository.kt:154-166`
|
||||
- 코드: `DefaultHomeFollowingQueryRepository.kt:428-438`
|
||||
- 코드: `DefaultHomeFollowingQueryRepository.kt:454-471`
|
||||
- 테스트 공백: 현재 콘텐츠 중복 테스트는 모든 newer row가 노출 가능한 경우만 검증한다.
|
||||
|
||||
**정적 재현 절차**
|
||||
|
||||
1. 같은 회원·콘텐츠에 `rank=2`, 노출 가능 시각 09:00인 정상 row를 둔다.
|
||||
2. 같은 키에 `rank=null`, 노출 가능 시각 10:00인 active row를 둔다.
|
||||
3. 10:00 이후 조회하면 이전 row는 newer row 존재로 제외되고, newer row는 `rank is not null` 조건에서 제외된다.
|
||||
4. 요구 결과는 노출 가능한 row 중 최신인 09:00 row 1건이지만 실제 결과는 0건이다.
|
||||
|
||||
**영향**
|
||||
|
||||
부분 적재나 정책 변경으로 최신 inbox row가 노출 불가능해지면 유효한 이전 콘텐츠 랭킹까지 사라져 “노출 가능한 row 중 최신” 계약을 위반한다.
|
||||
|
||||
**권장 조치**
|
||||
|
||||
newer-row 판정에 외부 조회와 동일한 row별 노출 조건을 적용한다. 최소한 `rank is not null`과 회원별 inbox 성인 조건의 회귀
|
||||
테스트를 추가하고 기존 시각/id tie-break 테스트를 유지한다.
|
||||
|
||||
**판정 기록**
|
||||
|
||||
- 2026-07-30 — 외부 where와 correlated subquery 조건을 대조해 확정했다.
|
||||
|
||||
## 5. plan·goal 전환
|
||||
|
||||
- `plan-task.md` Phase 7에 Task 7.2/7.3, `P7-R1`, `P7-R2`, `P7-R-GATE`를 추가했다.
|
||||
- 기존 Task 7.1과 `P7-GATE`의 완료 기록은 유지했다.
|
||||
|
||||
## 6. 리뷰 종료 판정
|
||||
|
||||
| 판정 항목 | 결과 | 근거 |
|
||||
|---|---|---|
|
||||
| 리뷰 범위 전체 확인 | 충족 | working tree repository/test/E2E 정적 대조 |
|
||||
| 후보 항목 판정 완료 | 충족 | `REV-P7-001`, `REV-P7-002` 확정 |
|
||||
| 확정 항목 plan 반영 | 충족 | Task 7.2/7.3 |
|
||||
| 검증 명령과 결과 기록 | 충족 | 테스트 미실행 사유 기록 |
|
||||
|
||||
**최종 결론:** 수정 goal 필요.
|
||||
|
||||
**남은 항목:** `P7-R1` → `P7-R2` → `P7-R-GATE` 실행 후 이 문서에 수정 검증을 누적한다.
|
||||
|
||||
## 7. 수정 후 검증 기록
|
||||
|
||||
- 2026-07-30 — RED 확인: `./gradlew --no-daemon test --tests "kr.co.vividnext.sodalive.v2.home.following.application.HomeFollowingQueryServiceTest" --tests "kr.co.vividnext.sodalive.v2.home.following.adapter.out.persistence.DefaultHomeFollowingQueryRepositoryTest"` 실행 결과 최신 빈 배치와 노출 불가 newer row 보완 전 컴파일/회귀 실패를 확인했다.
|
||||
- 2026-07-30 — `CREATOR_RANKING` 최신 배치 기준을 `creator_ranking_snapshot_job`의 최신 `WEEKLY`, `DONE`, `visibleFromAtUtc <= nowUtc`로 보강해 최신 완료 배치가 비어 있어도 과거 배치를 보충하지 않도록 했다.
|
||||
- 2026-07-30 — `CONTENT_RANKING` newer row 판정에 `rank is not null`과 회원별 inbox 성인 조건을 적용해 노출 불가 최신 row가 이전 노출 가능 row를 가리지 않도록 했다.
|
||||
- 2026-07-30 — GREEN 확인: 같은 focused test 명령 재실행 결과 `BUILD SUCCESSFUL`.
|
||||
- 2026-07-30 — Gate 확인: `./gradlew --no-daemon test --tests "kr.co.vividnext.sodalive.v2.api.home.following.adapter.in.web.HomeFollowingEndToEndTest"`와 `./gradlew --no-daemon ktlintCheck` 재실행 결과 모두 `BUILD SUCCESSFUL`.
|
||||
- 2026-07-30 — 리뷰 게이트: Oracle reviewer가 Critical/Important blocker 없음으로 승인했다.
|
||||
|
||||
## 8. 후속 종료 판정 — 2026-07-30
|
||||
|
||||
- 최신 공개 크리에이터 랭킹 배치가 빈 결과여도 과거 배치로 fallback하지 않는 현재 job 기준 조건을 정적으로 재확인했다.
|
||||
- `CONTENT_RANKING` newer row 판정에 `rank is not null`과 회원별 inbox 성인 조건이 적용된 현재 코드를 정적으로 재확인했다.
|
||||
- 이번 후속 판정에서는 컴파일과 테스트를 재실행하지 않았고, 위 `## 7. 수정 후 검증 기록`의 기존 성공 결과를 근거로 삼았다.
|
||||
|
||||
**최종 결론:** `P7-R1`, `P7-R2` 및 `P7-R-GATE` 수정 검증 완료.
|
||||
|
||||
**남은 항목:** 없음.
|
||||
|
||||
## 9. 3차 정적 리뷰 — 2026-07-30
|
||||
|
||||
- 최신 DONE job 우선의 크리에이터 랭킹 배치 판정, legacy snapshot fallback, 노출 가능한 콘텐츠 랭킹 중복 제거를 현재 working tree에서 다시 추적했다.
|
||||
- 컴파일과 테스트는 사용자 지시에 따라 실행하지 않았다.
|
||||
- runtime 신규 확정 발견 사항 없음. PRD의 stale 최신 배치 설명은 문서 소유 Phase의 `REV-P6-002`와 Task 6.4로 전환했으며, 기존 Phase 7 완료 판정을 유지한다.
|
||||
|
||||
## 10. 4차 정적 리뷰 — 2026-07-30
|
||||
|
||||
- 최신 공개 `WEEKLY`, `DONE` job 기준과 job 부재 시 snapshot fallback, 최신 빈 배치의 과거 랭킹 미보충을 다시 추적했다.
|
||||
- `CONTENT_RANKING`의 노출 가능한 newer row 판정에 active/rank/성인/visible/id 조건이 적용되고 전체 limit 전에 콘텐츠별 한 건만 남는지 확인했다.
|
||||
- repository 테스트가 신규 배치 공개 전후, 빈 최신 배치, rank null·성인 newer row와 동률 id 해소를 고정하는지 정적으로 확인했다.
|
||||
- 컴파일과 테스트는 사용자 지시에 따라 실행하지 않았다.
|
||||
- 신규 확정 발견 사항 없음. `REV-P7-001`, `REV-P7-002` 수정 완료와 기존 Phase 7 완료 판정을 유지한다.
|
||||
Reference in New Issue
Block a user