docs(recommendation): 응원 크리에이터 검토 기록을 갱신한다
This commit is contained in:
@@ -1,11 +1,23 @@
|
||||
# 메인 홈 추천 응원 크리에이터 스냅샷 수정 Plan/Task
|
||||
|
||||
## 후속 변경 상태
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 상태 | 3차 Phase별 리뷰 완료 |
|
||||
| 확정일 | 2026-07-31 |
|
||||
| 요구사항 기준 | `docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/prd.md` 전체 |
|
||||
| 현재 Phase | Phase 1~7 3차 리뷰 완료 |
|
||||
| 현재 활성 Goal | 없음 |
|
||||
| 다음 Goal | 없음 |
|
||||
|
||||
## 시나리오 계약
|
||||
- Happy path: 인기 커뮤니티와 동일한 최근 7일 UTC half-open 범위로 `CHEER_CREATOR` 점수를 계산하고, 점수순 상위 16개 스냅샷을 저장한다. Real surface: `DefaultHomeRecommendationQueryRepositoryTest`, `RecommendationSnapshotRefreshServiceTest`.
|
||||
- Score: 응원 점수는 `((donationAmount * 0.45) + (fanTalkCount * 0.30) + (donationCount * 0.10)) * newBoost`다. 후원 금액은 `CHANNEL_DONATION`과 `DONATION`의 `use_can_calculate.can`을 그대로 사용하고, 후원 수는 `UseCanCalculate.useCan` 기준으로 중복 제거한다. Real surface: `RecommendationScorePolicyTest`, `DefaultHomeRecommendationQueryRepositoryTest`.
|
||||
- Boost: 신규 부스트는 크리에이터 데뷔일 기준 0~10일 `1.15`, 11~20일 `1.10`, 21~30일 `1.05`, 31일 이상 `1.0`이다. Real surface: `RecommendationScorePolicyTest`, `DefaultHomeRecommendationQueryRepositoryTest`.
|
||||
- Fallback: 최신 `CHEER_CREATOR` 스냅샷이 없으면 lock, double-check, 동일 refresh 로직 재사용, refresh 후 재조회 순서로 fallback을 실행한다. lock 대기는 최대 300ms, 홈 API refresh 완료 대기는 최대 1,500ms다. Real surface: fallback service test, `HomeRecommendationQueryServiceTest`.
|
||||
- Empty marker: `CHEER_CREATOR` refresh 결과가 0건이면 `targetId = 0` marker를 저장해 정상 refresh 완료 상태를 남기고, 조회 응답에서는 marker를 제외한다. Real surface: `RecommendationSnapshotPersistenceAdapterTest`, `HomeRecommendationQueryServiceTest`.
|
||||
- Personalized filter: 인증 회원의 `cheerCreators`에서 조회자 본인과 `CreatorFollowing.isActive == true`인 팔로우 크리에이터를 제외한다. 비활성 팔로우 이력과 비회원 조회는 기존 동작을 유지한다. Real surface: `DefaultHomeRecommendationQueryRepositoryTest`.
|
||||
- Adjacent regression: 메인 홈 추천 API URL과 `CHEER_CREATOR` 응답 필드는 변경하지 않는다. AI 캐릭터, 인기 커뮤니티, 최근 데뷔 등 다른 섹션 산식과 공개 스키마는 이번 변경으로 바꾸지 않는다. Real surface: 기존 focused tests, `HomeRecommendationControllerTest`.
|
||||
|
||||
## 범위와 전제
|
||||
@@ -16,12 +28,15 @@
|
||||
- 집계 기간은 인기 커뮤니티와 동일하게 KST 전날을 포함한 최근 7일이며, DB 조회에는 UTC half-open window를 사용한다.
|
||||
- fallback orchestration은 AI 캐릭터 전용 구현을 그대로 복사하지 않고, 섹션별 lock key와 refresh action을 받을 수 있는 최소 공통 runner를 우선 적용한다.
|
||||
- 다른 스냅샷 섹션으로 empty marker를 확장하는 작업은 이번 구현 범위에서 제외한다. 단, `CHEER_CREATOR`에 적용할 때 이후 공통화가 가능하도록 조건문/상수명을 명확히 둔다.
|
||||
- 본인·팔로우 제외는 스냅샷 생성이 아닌 `findCheerCreatorRecommendationDetails(...)` 상세 조회 시점에서 기존 `memberId`로 적용한다.
|
||||
- 기존 16명 스냅샷 후보 안에서만 필터링하며, 필터 결과가 8명 미만이어도 하위 후보 조회나 스냅샷 저장 수 확대를 하지 않는다.
|
||||
|
||||
## 기존 CHEER_CREATOR 로직 유지/변경 경계
|
||||
- 유지: `RecommendedSectionType.CHEER_CREATOR` enum 값과 code는 변경하지 않는다.
|
||||
- 유지: 홈 응원 크리에이터 응답 필드인 `creatorId`, `creatorNickname`, `creatorProfileImage`는 변경하지 않는다.
|
||||
- 유지: 홈 첫 화면 응답은 최대 8명, 스냅샷 후보 조회는 최대 16개를 사용한다.
|
||||
- 유지: 상세 조회 시점의 활성 크리에이터 필터와 차단 필터는 유지한다.
|
||||
- 유지: 비회원 조회와 비활성 팔로우 이력이 있는 크리에이터 조회는 기존 동작을 유지한다.
|
||||
- 유지: 후원 금액은 `use_can_calculate.can` 값을 그대로 합산한다.
|
||||
- 변경: 점수 가중치는 후원 금액 45%, 팬Talk 수 30%, 후원 수 10%로 바꾼다.
|
||||
- 변경: 후원 수는 `UseCanCalculate.useCan` 기준 distinct count로 계산한다.
|
||||
@@ -30,6 +45,7 @@
|
||||
- 변경: 신규 부스트는 기존 크리에이터 공통 부스트 `1.5/1.3/1.2`가 아니라 `CHEER_CREATOR` 전용 `1.15/1.10/1.05`를 사용한다.
|
||||
- 추가: `CHEER_CREATOR` 최신 스냅샷이 없을 때 fallback refresh를 실행한다.
|
||||
- 추가: `CHEER_CREATOR` refresh 결과 0건이면 empty snapshot marker를 저장한다.
|
||||
- 추가: 인증 회원 본인과 활성 팔로우 중인 크리에이터를 `cheerCreators` 상세 조회에서 제외한다.
|
||||
|
||||
## 실행 명령
|
||||
- 문서 명령 확인: `./gradlew tasks --all`
|
||||
@@ -55,6 +71,32 @@
|
||||
- REFACTOR: 기존 홈 추천 구현 파일과 테스트 파일 기준으로 task별 수정/검증 경로를 맞춘다.
|
||||
- 기대 결과: 구현 시작 전에 PRD와 plan-task가 같은 디렉터리에 준비된다.
|
||||
|
||||
#### Task R1.1 PRD 관련 문서 경로 정합성 복구
|
||||
|
||||
**Goal 실행 `P1-R1`:** `REV-P1-001`에서 확인한 존재하지 않는 샘플 PRD 경로를 실제 가이드 경로로 정정한다.
|
||||
|
||||
- **시작 조건:** `reviews/phase-1-review.md`의 `REV-P1-001` 확정.
|
||||
- **완료 증거:** 문서 경로 정정, 대상 파일 존재 확인, `git diff --check` 통과, 전체 검증 기록 누적.
|
||||
- **범위 밖:** PRD 요구사항·결정 내용 변경, 코드·테스트 변경, 다른 문서의 링크 일괄 정리.
|
||||
- **TDD 예외 사유:** 문서 링크 정정만 수행하며 런타임 동작을 변경하지 않는다.
|
||||
|
||||
- [x] `prd.md`의 `docs/prd/sample-prd.md`를 실제 파일인 `docs/sample/sample-prd.md`로 정정한다.
|
||||
- [x] `test -f docs/sample/sample-prd.md`와 `git diff --check -- docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/prd.md`로 링크 대상과 문서 diff를 확인한다.
|
||||
- [x] 무엇을/왜/어떻게 검증했는지 전체 검증 기록에 누적한다.
|
||||
|
||||
#### Task R1.2 후속 변경 상태 정합성 복구
|
||||
|
||||
**Goal 실행 `P1-R2`:** `REV-P1-002`에서 확인한 상단 상태표의 요구사항 범위·Phase·다음 Goal을 현재 계획과 검증 상태에 맞게 정리한다.
|
||||
|
||||
- **시작 조건:** `reviews/phase-1-review.md`의 `REV-P1-002` 확정.
|
||||
- **완료 증거:** 상태표가 PRD 전체, Phase 1~7, 미완료 후속 Goal을 정확히 가리킴, `git diff --check`와 문서 명령 유효성 확인, 전체 검증 기록 누적.
|
||||
- **범위 밖:** PRD 요구사항 변경, 코드·테스트 변경, 이전 검증 기록 삭제.
|
||||
- **TDD 예외 사유:** 현재 작업 상태 문구만 복구하며 런타임 동작을 변경하지 않는다.
|
||||
|
||||
- [x] 상태표의 요구사항 기준을 PRD 전체로, Phase 상태를 Phase 1~7 현재 판정으로, 다음 Goal을 실제 미완료 Goal로 맞춘다.
|
||||
- [x] `git diff --check -- docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/plan-task.md`와 `./gradlew tasks --all`로 문서 diff와 명령 유효성을 확인한다.
|
||||
- [x] 완료 후 다음 Goal을 `P3-R2`로 갱신하고 전체 검증 기록에 무엇을/왜/어떻게 검증했는지 누적한다.
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: 산식과 부스트 정책
|
||||
@@ -144,6 +186,32 @@
|
||||
- REFACTOR: AI 캐릭터와 인기 커뮤니티 스냅샷 query가 영향받지 않았는지 focused test로 확인한다.
|
||||
- 기대 결과: `CHEER_CREATOR` 스냅샷 저장 후보만 정확히 변경된다.
|
||||
|
||||
#### Task R3.1 `CHEER_CREATOR` 후보 경계·정렬 완료 근거 보강
|
||||
|
||||
**Goal 실행 `P3-R1`:** `REV-P3-001`에서 누락이 확인된 Task 3.5의 후보 제외·상위 16개·저장 정렬 회귀 증거를 테스트로 고정한다.
|
||||
|
||||
- **시작 조건:** `reviews/phase-3-review.md`의 `REV-P3-001` 확정.
|
||||
- **완료 증거:** 실패 재현 테스트 작성·확인, 필요한 경우 최소 구현, repository/persistence focused test 통과, 전체 검증 기록 누적.
|
||||
- **범위 밖:** 점수 가중치·집계 기간·스냅샷 저장 수 변경, 랜덤 정책 변경, 다른 추천 섹션 쿼리 수정.
|
||||
|
||||
- [x] **RED:** 실제 데뷔 이력이 있지만 후원·팬Talk가 모두 0인 후보, 미래 데뷔 이력만 있는 후보, 비활성 크리에이터가 제외되는 테스트를 추가한다.
|
||||
- [x] **RED:** 17개 이상의 점수 후보에서 점수 내림차순 상위 16개만 반환되는 repository 테스트와, 저장된 동점 스냅샷이 `randomTieBreaker` 오름차순으로 조회되는 `CHEER_CREATOR` persistence 테스트를 추가한다.
|
||||
- [x] **GREEN:** 새 테스트가 구현 결함을 드러낼 때만 해당 조건·정렬 경로를 최소 수정하고, 테스트 누락뿐이면 프로덕션 코드는 변경하지 않는다.
|
||||
- [x] **REFACTOR/GATE:** `DefaultHomeRecommendationQueryRepositoryTest`와 `RecommendationSnapshotPersistenceAdapterTest` focused test 및 `git diff --check`를 실행해 결과를 누적한다.
|
||||
|
||||
#### Task R3.2 종료된 라이브 데뷔 이력 복구
|
||||
|
||||
**Goal 실행 `P3-R2`:** `REV-P3-002`에서 확인한 `CHEER_CREATOR` 데뷔일 계산이 채널명이 있는 종료 라이브를 제외하는 문제를 수정하고 회귀를 방지한다.
|
||||
|
||||
- **시작 조건:** `reviews/phase-3-review.md`의 `REV-P3-002` 확정과 `P1-R2` 완료.
|
||||
- **완료 증거:** 종료 라이브 재현 테스트의 의도한 실패, `CHEER_CREATOR` 데뷔 CTE 최소 수정, repository focused test·`ktlintCheck`·`git diff --check` 통과, 전체 검증 기록 누적.
|
||||
- **범위 밖:** 점수 가중치·집계 window·저장 수·정렬 변경, 다른 추천 섹션의 데뷔 정책 변경, 공개 API 변경.
|
||||
|
||||
- [x] **RED:** 활성 콘텐츠는 없고 `channel_name`이 있는 종료 라이브와 최근 7일 응원 활동만 있는 활성 크리에이터가 `CHEER_CREATOR` 후보에 포함되는 실패 테스트를 추가한다. 빈 `channel_name`의 종료 라이브는 데뷔 이력으로 인정하지 않는 경계를 함께 유지한다.
|
||||
- [x] **RED 확인:** `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest`를 실행해 현재 `lr.is_active = true` 조건 때문에 종료 라이브 후보가 누락되는 assertion 실패를 확인한다.
|
||||
- [x] **GREEN:** `findCheerCreatorSnapshots(...)`의 `creator_debut` 라이브 branch에서 `lr.is_active = true`만 제거하고, `channel_name is not null`, `channel_name <> ''`, `begin_date_time <= :snapshotAt` 조건은 유지한다.
|
||||
- [x] **REFACTOR/GATE:** repository focused test, `./gradlew ktlintCheck`, `git diff --check`를 실행하고 점수·window·후보 상한·다른 섹션 쿼리가 변경되지 않았음을 기록한다.
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: refresh 저장과 empty marker
|
||||
@@ -178,6 +246,19 @@
|
||||
- REFACTOR: 전체 일괄 refresh 성공 로그는 유지하되, 섹션별 로그와 중복되어도 검색 가능한 event key를 사용한다.
|
||||
- 기대 결과: 운영에서 `CHEER_CREATOR` refresh 결과 0건과 실패를 구분할 수 있다.
|
||||
|
||||
#### Task R4.1 `CHEER_CREATOR` refresh 실패 로그 보강
|
||||
|
||||
**Goal 실행 `P4-R1`:** `REV-P4-001`에서 확인한 섹션별 refresh 실패 로그 누락을 보완해 성공·빈 결과·실패를 운영 로그로 구분한다.
|
||||
|
||||
- **시작 조건:** `reviews/phase-4-review.md`의 `REV-P4-001` 확정.
|
||||
- **완료 증거:** 실패 로그 RED 테스트, 최소 로그 구현, refresh focused test 통과, 전체 검증 기록 누적.
|
||||
- **범위 밖:** fallback 실패 로그 형식 변경, 로그 수집 인프라·메트릭 시스템 추가, refresh 트랜잭션 정책 변경.
|
||||
|
||||
- [x] **RED:** `refreshCheerCreatorSnapshots(nowUtc)`의 query 또는 저장 실패 시 `event=cheer_creator_recommendation_snapshot_refresh_failure`, window·`snapshotAt`, 오류 정보가 기록되고 예외는 기존처럼 전파되는 테스트를 추가한다.
|
||||
- [x] **GREEN:** 성공 경로를 변경하지 않는 최소 `runCatching` 또는 `try/catch` 로그를 추가한 뒤 원래 예외를 다시 던진다.
|
||||
- [x] **REFACTOR/GATE:** `RecommendationSnapshotRefreshServiceTest`와 `git diff --check`를 실행하고 중복 로그가 의도된 event key로 구분되는지 확인한다.
|
||||
- [x] 무엇을/왜/어떻게 검증했는지 전체 검증 기록에 누적한다.
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: fallback refresh
|
||||
@@ -224,6 +305,19 @@
|
||||
- REFACTOR: 스냅샷 후보 16개 조회, 상세 조회 후 최대 8개 반환, 차단 필터 전달은 기존 동작을 유지한다.
|
||||
- 기대 결과: 홈 통합 조회의 최근 응원이 많은 크리에이터 섹션이 스냅샷 없음 상황을 자체 복구할 수 있다.
|
||||
|
||||
#### Task R5.1 fallback single-flight·double-check 회귀 증거 보강
|
||||
|
||||
**Goal 실행 `P5-R1`:** `REV-P5-001`에서 누락이 확인된 동일 섹션 동시 요청 single-flight와 lock 내부 double-check를 결정적 테스트로 고정한다.
|
||||
|
||||
- **시작 조건:** `reviews/phase-5-review.md`의 `REV-P5-001` 확정.
|
||||
- **완료 증거:** 동시성·double-check RED 테스트 작성·확인, 필요한 경우 최소 구현, fallback focused test 통과, 전체 검증 기록 누적.
|
||||
- **범위 밖:** worker 수 조정, timeout·lock 대기 값 변경, 다른 섹션 fallback 정책 확대.
|
||||
|
||||
- [x] **RED:** 동일 JVM에서 동시에 들어온 둘 이상의 `CHEER_CREATOR` fallback 요청이 하나의 refresh future만 공유하고 `refreshCheerCreatorSnapshots(...)`를 1회만 호출하는 테스트를 latch 기반으로 추가한다.
|
||||
- [x] **RED:** 최초 조회 뒤 lock 획득 전 다른 요청/스케줄러가 대상일 marker 또는 실제 row를 저장하면 lock 안의 double-check가 refresh를 생략하고 최신 상태를 다시 조회하는 테스트를 추가한다.
|
||||
- [x] **GREEN:** 새 테스트가 구현 결함을 드러낼 때만 `refreshFutures` 또는 lock 내부 존재 확인 경로를 최소 수정한다.
|
||||
- [x] **REFACTOR/GATE:** sleep 없이 `RecommendationSnapshotFallbackServiceTest` focused test와 `git diff --check`를 실행해 결과를 누적한다.
|
||||
|
||||
---
|
||||
|
||||
### Phase 6: API 회귀와 최종 검증
|
||||
@@ -262,18 +356,104 @@
|
||||
- REFACTOR: 문서와 코드의 산식/timeout/window 값이 다르면 구현 또는 문서를 수정한 뒤 재검증한다.
|
||||
- 기대 결과: 전체 테스트, 포맷, 문서 명령 유효성, diff 공백 검사가 모두 통과한다.
|
||||
|
||||
#### Task R6.1 `cheerCreators` item 공개 스키마 회귀 테스트 보강
|
||||
|
||||
**Goal 실행 `P6-R1`:** `REV-P6-001`에서 확인한 빈 배열 중심 스키마 검증을 실제 item의 정확한 필드 계약 검증으로 보강한다.
|
||||
|
||||
- **시작 조건:** `reviews/phase-6-review.md`의 `REV-P6-001` 확정.
|
||||
- **완료 증거:** 비어 있지 않은 item 직렬화/컨트롤러 테스트, 정확한 필드 집합 검증, API focused test 통과, 전체 검증 기록 누적.
|
||||
- **범위 밖:** DTO 필드 추가·이름 변경, API URL 변경, 다른 홈 섹션 스키마 정리.
|
||||
|
||||
- [x] **RED:** `cheerCreators`에 item을 넣고 `creatorId`, `creatorNickname`, `creatorProfileImage` 값과 필드 수 3을 검증하는 직렬화 테스트를 추가한다.
|
||||
- [x] **RED:** 홈 API 테스트에서 비어 있지 않은 `cheerCreators` item의 동일 필드 계약을 검증하고 예상 밖 필드가 없음을 확인한다.
|
||||
- [x] **GREEN:** 기존 DTO가 테스트를 만족하면 프로덕션 코드는 변경하지 않고, 계약 불일치가 드러날 때만 기존 공개 스키마로 최소 복구한다.
|
||||
- [x] **REFACTOR/GATE:** `HomeRecommendationControllerTest`, `HomeRecommendationResponseTest`, `git diff --check`를 실행해 결과를 누적한다.
|
||||
|
||||
---
|
||||
|
||||
### Phase 7: 본인·팔로우 크리에이터 노출 제외
|
||||
|
||||
**Phase 결과:** 인증 회원의 `cheerCreators`에서 조회자 본인과 활성 팔로우 크리에이터가 제외되고, 비활성 팔로우 이력과 비회원 조회는 기존 동작을 유지한다.
|
||||
|
||||
**선행조건:** Phase 1~6 완료와 PRD Feature D의 2026-07-31 후속 요구사항 확정.
|
||||
|
||||
**Phase 완료 조건:** `P7-T1`과 `P7-GATE` 완료, focused test·영향 범위 회귀·문서 검증 결과 누적.
|
||||
|
||||
#### Task 7.1 `cheerCreators` 상세 조회 개인화 필터 보강
|
||||
|
||||
**Goal 실행 `P7-T1`:** 기존 `memberId` 기반 상세 조회에서 본인과 활성 팔로우 크리에이터만 제외하는 최소 조회 조건을 추가한다.
|
||||
|
||||
- **시작 조건:** PRD Feature D의 본인·활성 팔로우 제외, 비활성 팔로우·비회원 유지, 16명 후보 안에서만 필터링한다는 결정 확정.
|
||||
- **완료 증거:** 아래 체크박스 전체 완료, repository focused test 통과, 직접 영향 회귀 통과, 실행 결과를 이 문서의 전체 검증 기록에 누적.
|
||||
- **범위 밖:** 스냅샷 산식·정렬·저장 수, 16명 밖 하위 후보 보충, 공개 DTO/API, 다른 추천 섹션의 팔로우 필터.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt`
|
||||
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt`
|
||||
- Verify: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt`
|
||||
- Verify: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/HomeRecommendationControllerTest.kt`
|
||||
|
||||
**Interfaces:**
|
||||
|
||||
- Consumes: `HomeRecommendationQueryPort.findCheerCreatorRecommendationDetails(creatorIds: List<Long>, memberId: Long?): List<HomeCheerCreatorRecommendationRecord>`
|
||||
- Produces: 같은 시그니처와 반환 타입을 유지하면서, `memberId != null`일 때만 본인과 활성 팔로우를 제외하는 상세 조회 계약.
|
||||
|
||||
- [x] **RED:** `DefaultHomeRecommendationQueryRepositoryTest`에 조회자 크리에이터, 활성 팔로우 크리에이터, 비활성 팔로우 이력만 있는 크리에이터, 관계가 없는 크리에이터를 준비한다. `memberId = viewer.id`로 조회했을 때 비활성 팔로우 이력 크리에이터와 관계가 없는 크리에이터만 반환하는 `shouldExcludeSelfAndActiveFollowedCreatorsFromCheerCreatorDetails` 테스트를 작성한다. `memberId = null`은 모든 활성 후보를 유지하는 `shouldKeepAnonymousCheerCreatorDetailsWithoutMemberFilters` 테스트도 작성한다.
|
||||
- [x] **RED 확인:** `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest`를 실행해 현재 조회가 조회자 본인과 활성 팔로우 크리에이터를 함께 반환하여 첫 번째 테스트가 의도한 assertion 실패를 내는지 확인한다.
|
||||
- [x] **GREEN:** `findCheerCreatorRecommendationDetails(...)`에 `memberId`가 있을 때 `member.id != memberId`를 적용하고, 동일 회원과 후보 크리에이터 사이에 `CreatorFollowing.isActive == true`인 row가 존재하지 않는 조건을 추가한다. `memberId == null`이면 두 조건은 적용하지 않는다.
|
||||
- [x] **GREEN 확인:** 같은 repository focused test를 재실행해 본인·활성 팔로우 제외, 비활성 팔로우·비회원 유지, 기존 양방향 차단 제외 테스트가 모두 통과하는지 확인한다.
|
||||
- [x] **REFACTOR:** 이번 조건에 필요한 QueryDSL alias/helper만 남기고, `HomeRecommendationQueryServiceTest`로 기존 16명 후보 조회·필터 후 최대 8명 조립이 유지되는지 확인한다. `HomeRecommendationControllerTest`와 `ktlintCheck`로 공개 스키마·포맷 회귀를 확인하고 실제 명령·결과를 전체 검증 기록에 남긴다.
|
||||
|
||||
### Phase 7 완료 조건
|
||||
|
||||
- [x] `P7-T1`의 RED·GREEN·REFACTOR 체크박스와 완료 증거가 모두 충족됐다.
|
||||
- [x] 인증 회원 본인·활성 팔로우만 제외되고 비활성 팔로우·비회원·양방향 차단·활성 크리에이터 정책이 조합되는 것이 검증됐다.
|
||||
- [x] 스냅샷 산식·저장 수·정렬, 응답 DTO, 다른 추천 섹션에 변경이 없다.
|
||||
|
||||
#### Phase 7 Gate
|
||||
|
||||
**Goal 실행 `P7-GATE`:** `cheerCreators` 개인화 필터와 직접 영향 회귀를 최종 판정한다.
|
||||
|
||||
- **시작 조건:** `P7-T1` 완료.
|
||||
- **완료 증거:** 아래 명령 전부 통과, `git diff --check` 출력 없음, 전체 검증 기록 누적.
|
||||
- **범위 밖:** 게이트 통과를 위한 테스트 삭제·완화와 관련 없는 리팩터링.
|
||||
|
||||
```bash
|
||||
./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest
|
||||
./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryServiceTest --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest
|
||||
./gradlew ktlintCheck
|
||||
git diff --check
|
||||
```
|
||||
|
||||
**Expected:** 모든 명령이 exit code 0이고, 인증 회원 본인·활성 팔로우는 제외되며 비활성 팔로우·비회원 결과와 기존 API 스키마는 유지된다.
|
||||
|
||||
---
|
||||
|
||||
## Coverage Check
|
||||
- Feature A: Task 2.1, Task 3.2, Task 3.4에서 후원 금액 45%, 팬Talk 30%, 후원 수 10%, 후원 수 distinct 기준을 검증한다.
|
||||
- Feature B: Task 3.1, Task 3.3에서 최근 7일 KST 범위를 UTC half-open 조회 범위로 변환하고 `windowEndExclusiveUtc` 경계를 검증한다.
|
||||
- Feature C: Task 2.2, Task 3.4에서 데뷔일 기준 응원 전용 신규 부스트와 경계값을 검증한다.
|
||||
- Feature D: Task 3.5, Task 5.4, Task 6.1에서 최신 `CHEER_CREATOR` 스냅샷 순서, 후보 16개/응답 8개, 기존 응답 스키마 유지를 검증한다.
|
||||
- Feature D: Task 3.5, Task 5.4, Task 6.1, Task 7.1에서 최신 `CHEER_CREATOR` 스냅샷 순서, 후보 16개/응답 8개, 본인·활성 팔로우 제외, 비활성 팔로우·비회원 유지, 기존 응답 스키마 유지를 검증한다.
|
||||
- Feature E: Task 5.1, Task 5.2, Task 5.3, Task 5.4에서 fallback refresh 재사용, double-check, 300ms lock 대기, 1,500ms 홈 API 대기, timeout 후 background 완료, 중복 refresh 방지를 검증한다.
|
||||
- Feature F: Task 4.1, Task 4.2, Task 5.3에서 `CHEER_CREATOR` empty marker 저장, 조회 제외, 존재 여부 true, marker 기반 fallback 반복 방지를 검증한다.
|
||||
- Non-Goals: Task 4.1, Task 6.1, Task 6.3에서 다른 스냅샷 섹션 marker 확장 없음, 공개 API URL/응답 필드 변경 없음, 신규 DDL 없음, 관리자/ML/A-B 제외를 확인한다.
|
||||
- Non-Goals: Task 4.1, Task 6.1, Task 6.3, Task 7.1에서 다른 스냅샷 섹션 marker 확장 없음, 공개 API URL/응답 필드 변경 없음, 16명 밖 후보 보충 없음, 신규 DDL 없음, 관리자/ML/A-B 제외를 확인한다.
|
||||
|
||||
## 전체 검증 기록
|
||||
- 2026-07-31: Phase 1~7 3차 리뷰로 PRD·plan-task·현재 코드·테스트를 정적으로 대조했다. 이전 리뷰에서 보완한 문서 정합성, 종료 라이브 데뷔 이력, `CHEER_CREATOR` refresh 실패 로그, fallback single-flight·double-check, 공개 응답 3개 필드, 본인·활성 팔로우 제외가 현재 구현과 회귀 테스트에 유지됨을 확인했다. 각 결과는 기존 `reviews/phase-1-review.md`~`reviews/phase-7-review.md`에 3차 리뷰로 별도 누적했다. 추가 확정 발견 사항이 없어 신규 회귀 Task/Goal은 추가하지 않았다. 사용자 지시에 따라 Gradle compile/test는 실행하지 않았다. `git diff --check`는 출력 없이 통과했다. 문서 명령 유효성 확인용 `./gradlew tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 권한으로 실패한 뒤 승인된 동일 명령에서 `BUILD SUCCESSFUL`로 통과했다.
|
||||
- 2026-07-31: `P3-R2`로 `CHEER_CREATOR` 데뷔 CTE가 채널명이 있는 종료 라이브를 데뷔 이력으로 인정하도록 복구했다. RED 확인으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest`를 실행해 `shouldIncludeEndedLiveWithChannelNameAsCheerCreatorDebut`가 `AssertionFailedError`로 실패하는 것을 확인했다. 이후 `findCheerCreatorSnapshots(...)` 라이브 branch에서 `lr.is_active = true`만 제거했고, 같은 repository focused test는 `BUILD SUCCESSFUL`로 통과했다. `./gradlew ktlintCheck`도 `BUILD SUCCESSFUL`로 통과했으며, `git diff --check`는 출력 없이 통과했다.
|
||||
- 2026-07-31: `P1-R2`로 상단 후속 변경 상태를 현재 PRD 전체, Phase 1~7 판정, 실제 미완료 Goal `P3-R2` 기준으로 정리했다. 문서 정합성 복구만 수행해 TDD 예외로 처리했다. `git diff --check -- docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/plan-task.md`는 출력 없이 통과했고, `./gradlew tasks --all`은 `BUILD SUCCESSFUL`로 통과했다.
|
||||
- 2026-07-31: Phase 1~7 2차 리뷰로 PRD·plan-task·현재 코드·테스트·관련 구현 이력을 정적 대조했다. `REV-P1-002`의 상단 상태표 불일치와 `REV-P3-002`의 종료 라이브 데뷔 이력 제외를 확정해 각각 `P1-R2`, `P3-R2` 신규 회귀 Task로 전환했고, Phase 2·4·5·6·7은 추가 확정 발견 사항이 없다. 결과는 기존 `reviews/phase-1-review.md`~`reviews/phase-7-review.md`에 2차 리뷰로 각각 누적했다. 사용자 지시에 따라 Gradle compile/test는 실행하지 않았다. `git diff --check`는 출력 없이 통과했고, `./gradlew tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 권한으로 실패한 후 승인된 동일 명령으로 재실행해 `BUILD SUCCESSFUL`로 통과했다.
|
||||
- 2026-07-31: `P1-R1`, `P3-R1`, `P4-R1`, `P5-R1`, `P6-R1` 후속 보완의 최종 focused 회귀로 `./gradlew cleanTest test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.RecommendationSnapshotPersistenceAdapterTest --tests kr.co.vividnext.sodalive.v2.recommendation.application.RecommendationSnapshotRefreshServiceTest --tests kr.co.vividnext.sodalive.v2.recommendation.application.RecommendationSnapshotFallbackServiceTest --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest --tests kr.co.vividnext.sodalive.v2.api.home.dto.recommendation.HomeRecommendationResponseTest`를 실행해 `BUILD SUCCESSFUL`로 통과했다. 이어서 `./gradlew ktlintCheck`는 `BUILD SUCCESSFUL`, `git diff --check`는 출력 없이 통과했다. 전체 `./gradlew test`는 테스트 assertion 실패가 아니라 `build/test-results/test/TEST-*.xml` 결과 파일 쓰기 실패로 중단되어 별도 환경/파일시스템 이슈 확인이 필요하다.
|
||||
- 2026-07-31: `P1-R1`로 `prd.md`의 샘플 PRD 링크를 실제 파일 `docs/sample/sample-prd.md`로 정정했다. `test -f docs/sample/sample-prd.md`와 `git diff --check -- docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/prd.md`를 실행해 출력 없이 통과했다.
|
||||
- 2026-07-31: `P3-R1`로 `CHEER_CREATOR` 후보 제외·상위 16개·동점 저장 정렬 회귀 테스트를 보강했다. 리뷰 판정처럼 구현 결함은 드러나지 않아 프로덕션 코드는 변경하지 않았다. `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.RecommendationSnapshotPersistenceAdapterTest`는 `BUILD SUCCESSFUL`, 관련 `git diff --check`는 출력 없이 통과했다.
|
||||
- 2026-07-31: `P4-R1`로 `refreshCheerCreatorSnapshots(nowUtc)` 실패 시 `event=cheer_creator_recommendation_snapshot_refresh_failure`와 window·`snapshotAt`·오류 정보를 남기고 원 예외를 전파하도록 보강했다. RED 확인으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.application.RecommendationSnapshotRefreshServiceTest.shouldLogCheerCreatorRefreshFailureWithWindow`가 `AssertionFailedError`로 실패했고, GREEN 후 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.application.RecommendationSnapshotRefreshServiceTest`는 `BUILD SUCCESSFUL`, 관련 `git diff --check`는 출력 없이 통과했다.
|
||||
- 2026-07-31: `P5-R1`로 동일 섹션 동시 요청 single-flight와 lock 내부 double-check를 sleep 없이 latch 기반 테스트로 보강했다. 리뷰 판정처럼 구현 결함은 드러나지 않아 프로덕션 코드는 변경하지 않았다. `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.application.RecommendationSnapshotFallbackServiceTest`는 `BUILD SUCCESSFUL`, 관련 `git diff --check`는 출력 없이 통과했다.
|
||||
- 2026-07-31: `P6-R1`로 `cheerCreators` item 직렬화와 홈 API 응답의 `creatorId`, `creatorNickname`, `creatorProfileImage` 3개 필드 계약을 보강했다. 최초 controller focused test는 대상일 snapshot fixture 불일치와 테스트 환경 CDN host 기대값 불일치로 실패했고, fixture를 `RecommendationSnapshotWindowPolicy.previousKstDayUtcWindow(LocalDateTime.now(UTC)).snapshotAt` 및 실제 테스트 host 설정에 맞춘 뒤 `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest --tests kr.co.vividnext.sodalive.v2.api.home.dto.recommendation.HomeRecommendationResponseTest`가 `BUILD SUCCESSFUL`로 통과했다. 관련 `git diff --check`는 출력 없이 통과했다.
|
||||
- 2026-07-31: Phase별 리뷰 문서와 회귀 Task 추가 후 `git diff --check`를 실행해 출력 없이 통과했다. 문서 명령 유효성 확인용 `./gradlew tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 권한으로 실패했고, 승인 후 동일 명령을 재실행해 `BUILD SUCCESSFUL`로 통과했다. compile/test task는 실행하지 않았다.
|
||||
- 2026-07-31: Phase 1~7 구현 상태를 PRD·plan-task·현재 코드·테스트와 정적으로 대조했다. 사용자 지시에 따라 Gradle compile/test는 새로 실행하지 않았고 기존 검증 기록을 실행 증거로 참조했다. 확정 항목은 `reviews/phase-1-review.md`부터 `reviews/phase-7-review.md`까지 Phase별로 기록했으며, `REV-P1-001`, `REV-P3-001`, `REV-P4-001`, `REV-P5-001`, `REV-P6-001`을 각각 `P1-R1`, `P3-R1`, `P4-R1`, `P5-R1`, `P6-R1` 신규 회귀 Task로 전환했다. Phase 2와 Phase 7은 확정 발견 사항이 없다.
|
||||
- 2026-07-31: Phase 7 `P7-T1` 구현으로 `findCheerCreatorRecommendationDetails(...)`가 인증 회원 조회 시 조회자 본인과 `CreatorFollowing.isActive == true`인 팔로우 크리에이터를 제외하도록 보강했다. RED 확인으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest`를 실행해 `shouldExcludeSelfAndActiveFollowedCreatorsFromCheerCreatorDetails` assertion 실패를 확인했고, GREEN 후 같은 명령은 `BUILD SUCCESSFUL`로 통과했다. 직접 영향 회귀 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryServiceTest --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest`와 `./gradlew ktlintCheck`도 `BUILD SUCCESSFUL`로 통과했다.
|
||||
- 2026-07-31: 후속 요구사항으로 인증 회원 본인과 활성 팔로우 크리에이터를 `cheerCreators` 상세 조회에서 제외하는 정책을 PRD Feature D와 Phase 7 `P7-T1`/`P7-GATE`에 반영했다. 비활성 팔로우·비회원 유지와 16명 후보 밖 보충 없음을 경계로 고정했다. `git diff --check`는 출력 없이 통과했다. `./gradlew tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 파일 권한으로 실패했고, 승인 후 동일 명령을 재실행해 `BUILD SUCCESSFUL`로 통과했다.
|
||||
- 2026-07-10: PRD 기반으로 `plan-task.md`를 생성했다. 구현 전 계획 문서 작성 작업이므로 코드 테스트는 아직 실행하지 않았고, 문서 형식/명령 유효성 검증을 진행한다.
|
||||
- 2026-07-10: 문서 검증으로 `git diff --check -- docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/plan-task.md`를 실행해 통과했다. `./gradlew tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 파일 접근 제한으로 실패했고, 권한 상승 재실행 결과 `BUILD SUCCESSFUL`로 통과했다.
|
||||
- 2026-07-10: 구현 RED 확인으로 `RecommendationScorePolicyTest`는 `CHEER_NEW_BOOST_*`와 `calculateCheerCreatorNewBoost(...)` 미구현 컴파일 실패를 확인했고, `DefaultHomeRecommendationQueryRepositoryTest`는 half-open/distinct 집계 기대값 불일치 실패를 확인했다. `RecommendationSnapshotPersistenceAdapterTest`는 `CHEER_CREATOR` empty marker 미지원 실패를 확인했다.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# PRD: 메인 홈 추천 응원 크리에이터 스냅샷 수정
|
||||
|
||||
## 1. Overview
|
||||
메인 홈 추천 탭의 `CHEER_CREATOR` 스냅샷 생성과 조회를 최근 7일 데이터 기반의 응원 점수로 수정하고, 스냅샷이 없을 때 홈 API가 동일 refresh 로직을 안전하게 재사용하도록 fallback 흐름을 보강한다.
|
||||
메인 홈 추천 탭의 `CHEER_CREATOR` 스냅샷 생성과 조회를 최근 7일 데이터 기반의 응원 점수로 수정하고, 스냅샷이 없을 때 홈 API가 동일 refresh 로직을 안전하게 재사용하도록 fallback 흐름을 보강한다. 인증 회원에게는 조회자 본인과 현재 활성 팔로우 중인 크리에이터를 `cheerCreators` 응답에서 제외한다.
|
||||
|
||||
---
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
- 현재 일괄 refresh와 홈 API fallback refresh가 섹션별로 동일한 생성 로직을 공유하지 않으면 산식 drift가 발생할 수 있다.
|
||||
- 스냅샷이 없는 초기 배포, 운영 데이터 삭제, 배치 실패 상황에서 홈 조회가 매 요청마다 무거운 집계를 중복 실행하면 API 지연과 DB 부하가 커질 수 있다.
|
||||
- 집계 산식이 추천 노출 순서를 직접 바꾸므로 DB-side 계산과 Kotlin-side 계산 중 어떤 방식을 선택하더라도 산식/부스트 경계값 테스트가 필요하다.
|
||||
- 현재 `CHEER_CREATOR` 상세 조회는 활성 크리에이터와 양방향 차단 조건만 적용하여, 인증 회원 본인이나 이미 팔로우 중인 크리에이터가 추천에 노출될 수 있다.
|
||||
|
||||
---
|
||||
|
||||
@@ -23,21 +24,24 @@
|
||||
- 홈 API는 fallback refresh 완료를 최대 1,500ms까지만 기다리고, lock 대기는 최대 300ms로 제한한다.
|
||||
- fallback refresh 실패, timeout, refresh 결과 없음은 홈 API 전체 실패로 전파하지 않고 `CHEER_CREATOR` 섹션 빈 배열로 처리한다.
|
||||
- 산식과 신규 부스트는 단위 테스트에서 경계값과 가중치 계산을 촘촘히 검증한다.
|
||||
- 인증 회원의 `cheerCreators` 상세 조회에서 조회자 본인과 `CreatorFollowing.isActive == true`인 팔로우 크리에이터를 제외한다.
|
||||
- 비활성 팔로우 이력과 비회원 조회는 기존 조회 정책을 유지한다.
|
||||
|
||||
---
|
||||
|
||||
## 4. Non-Goals
|
||||
- 메인 홈 추천 API URL, 응답 필드, 응답 JSON 스키마는 변경하지 않는다.
|
||||
- `CHEER_CREATOR` 이외 추천 섹션의 산식과 조회 정책은 변경하지 않는다.
|
||||
- 관리자 화면, 수동 추천 편집, A/B 테스트, 개인화 추천은 이번 범위에 포함하지 않는다.
|
||||
- 관리자 화면, 수동 추천 편집, A/B 테스트, 사용자별 응원 점수·스냅샷 순서 산정은 이번 범위에 포함하지 않는다.
|
||||
- 후원, 팬Talk 생성/수정/삭제 자체의 도메인 동작은 변경하지 않는다.
|
||||
- 신규 추천 스냅샷 테이블을 만들지 않고, 기존 `recommendation_snapshot` 구조를 우선 재사용한다.
|
||||
- 팔로우/본인 필터링으로 8명이 채워지지 않을 때 스냅샷 저장 수나 조회 후보를 16명 이상으로 늘리는 작업은 범위에 포함하지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## 5. Target Users
|
||||
- 회원/비회원: 메인 홈 추천 탭에서 최근 7일 응원 반응이 많았던 크리에이터를 발견하는 사용자
|
||||
- 앱 클라이언트: 기존 응답 계약을 유지한 채 `CHEER_CREATOR` 추천 순서만 변경된 결과를 받는 클라이언트
|
||||
- 앱 클라이언트: 기존 응답 계약을 유지한 채 `CHEER_CREATOR` 점수 순서와 인증 회원 조회 필터를 반영한 결과를 받는 클라이언트
|
||||
- 운영자: 최근 7일 후원/팬Talk 반응이 추천 노출에 반영되는지 확인해야 하는 운영 담당자
|
||||
|
||||
---
|
||||
@@ -46,6 +50,7 @@
|
||||
- 사용자는 메인 홈 추천 탭에서 최근 7일 응원이 많았던 크리에이터를 우선 보고 싶다.
|
||||
- 사용자는 후원 금액뿐 아니라 팬Talk와 후원 참여 횟수도 함께 반영된 추천을 보고 싶다.
|
||||
- 사용자는 신규 크리에이터가 일정 기간 동안 적절한 노출 기회를 받기를 기대한다.
|
||||
- 인증 회원은 자신과 이미 팔로우 중인 크리에이터를 제외한 새로운 응원 크리에이터를 보고 싶다.
|
||||
- 앱 클라이언트는 스냅샷이 없는 상황에서도 홈 API가 실패하지 않고 안정적으로 빈 배열 또는 생성된 스냅샷을 받기를 원한다.
|
||||
- 운영자는 배치 실패 후 첫 홈 조회가 스케줄러와 동일한 로직으로 스냅샷을 복구하기를 원한다.
|
||||
|
||||
@@ -118,10 +123,15 @@
|
||||
- 크리에이터 닉네임
|
||||
- 크리에이터 프로필 이미지
|
||||
- 조회 시점에도 기존 차단 필터와 활성 크리에이터 필터를 적용한다.
|
||||
- 인증 회원이 크리에이터인 경우 `creatorId == memberId`인 조회자 본인을 제외한다.
|
||||
- 인증 회원과 크리에이터 사이의 `CreatorFollowing.isActive == true`인 팔로우 관계가 있으면 해당 크리에이터를 제외한다.
|
||||
- 과거 언팔로우로 `CreatorFollowing.isActive == false`인 이력만 있는 크리에이터는 제외하지 않는다.
|
||||
- 비회원은 본인과 팔로우 관계를 판정할 `memberId`가 없으므로 해당 필터를 적용하지 않는다.
|
||||
- 스냅샷 후보는 최대 16개까지 조회하고, 상세 조회/필터링 후 홈 첫 화면에는 최대 8명을 반환한다.
|
||||
|
||||
#### Edge Cases
|
||||
- 최신 스냅샷 row가 존재하지만 조회 필터로 모두 제외되면 빈 배열을 반환한다.
|
||||
- 본인과 활성 팔로우 크리에이터를 제외한 결과가 8명보다 적으면 16명 스냅샷 후보 범위 안에서 조회 가능한 수만 반환하고, 16명 밖의 하위 후보로 보충하지 않는다.
|
||||
- 상세 조회 결과가 스냅샷 저장 개수보다 적어도 홈 조회 전체는 성공 처리한다.
|
||||
- 스냅샷 정렬 순서와 응답 순서는 일치해야 한다.
|
||||
|
||||
@@ -175,6 +185,7 @@
|
||||
- 기존 `kr.co.vividnext.sodalive.v2.recommendation` 패키지 경계와 `v2.api.home`에서 `v2.recommendation`을 호출하는 의존 방향을 유지한다.
|
||||
- 기존 `RecommendationSnapshot`, `RecommendationSnapshotPort`, `HomeRecommendationQueryPort` 기반 저장/조회 구조를 재사용한다.
|
||||
- 공개 API 응답 DTO는 필드 추가 없이 유지한다.
|
||||
- 본인과 활성 팔로우 제외는 기존 `memberId`를 사용하는 `findCheerCreatorRecommendationDetails(...)` 상세 조회 경로에서 적용하고, 스냅샷 생성 산식과 저장 데이터는 변경하지 않는다.
|
||||
- 스케줄러 refresh와 fallback refresh는 산식, 기간, 저장 limit, 정렬 기준이 갈라지지 않도록 같은 application service 경로를 사용한다.
|
||||
- fallback refresh 기능은 AI 캐릭터 전용 구현을 복사하기보다 섹션별로 재사용 가능한 형태를 우선 검토한다. 단, 과도한 일반화가 필요하면 `CHEER_CREATOR`에 필요한 최소 추상화만 적용한다.
|
||||
- `CHEER_CREATOR` 집계는 정확한 top 후보를 위해 최종 점수 계산 전 candidate pre-limit를 두지 않는다.
|
||||
@@ -208,6 +219,9 @@
|
||||
- 후원 수는 `UseCanCalculate.useCan`이 같은 row를 1개 후원 이벤트로 보고 중복 제거한다.
|
||||
- 팬Talk 수는 `CreatorCheers.isActive == true`인 row 수로 계산한다.
|
||||
- 빈 결과 marker 정책은 다른 스냅샷 섹션에도 확장하는 것이 맞지만, 이번 구현 범위에서는 `CHEER_CREATOR`에만 적용한다.
|
||||
- 인증 회원 본인과 활성 팔로우 중인 크리에이터는 `cheerCreators`에서 제외하고, 비활성 팔로우 이력은 제외 근거로 사용하지 않는다.
|
||||
- 필터링 후 8명 미만이어도 기존 16명 스냅샷 후보 범위를 넘어서 보충하지 않는다.
|
||||
- 비회원은 기존 `CHEER_CREATOR` 조회 결과를 유지한다.
|
||||
|
||||
---
|
||||
|
||||
@@ -244,7 +258,7 @@
|
||||
---
|
||||
|
||||
## 13. Related Documents
|
||||
- `docs/prd/sample-prd.md`
|
||||
- `docs/sample/sample-prd.md`
|
||||
- `docs/agent-guides/작업절차.md`
|
||||
- `docs/agent-guides/문서유지보수.md`
|
||||
- `docs/20260529_메인_홈_추천_API/prd.md`
|
||||
|
||||
125
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-1-review.md
Normal file
125
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-1-review.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Phase 1 리뷰 보고서
|
||||
|
||||
## 1. 리뷰 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 리뷰 대상 | Phase 1 / Task 1.1 |
|
||||
| 기준 commit 또는 working tree | `5123494e` 기준 working tree |
|
||||
| 리뷰 일자 | 2026-07-31 |
|
||||
| 리뷰어 | Codex |
|
||||
| 기준 문서 | `prd.md`, `plan-task.md`, `docs/agent-guides/작업절차.md`, `docs/agent-guides/문서유지보수.md` |
|
||||
| 리뷰 상태 | 보완 완료 |
|
||||
|
||||
## 2. 리뷰 목적과 범위
|
||||
|
||||
- PRD와 구현 계획이 같은 작업 디렉터리에 있고 구현 기준을 충분히 고정했는지 확인한다.
|
||||
- 문서 참조 경로와 완료 체크가 현재 저장소 근거와 일치하는지 확인한다.
|
||||
- 코드·테스트 동작과 다른 Phase의 구현 품질은 제외한다.
|
||||
|
||||
## 3. 판정 기준
|
||||
|
||||
- 심각도는 `docs/sample/sample-review.md`의 Blocker/High/Medium/Low 기준을 사용한다.
|
||||
- 존재하지 않는 근거 문서 링크는 문서 정합성 문제인 Low로 판정한다.
|
||||
|
||||
## 4. 검토한 근거
|
||||
|
||||
- 계획: Task 1.1
|
||||
- 문서: `prd.md`의 Related Documents, `plan-task.md`의 시나리오 계약·범위·Phase 분해
|
||||
- 정적 검증: `test -e docs/prd/sample-prd.md`, `test -e docs/sample/sample-prd.md`, `git diff --check`
|
||||
- 문서 명령 검증: `./gradlew tasks --all`은 sandbox 권한 실패 후 승인된 동일 명령에서 `BUILD SUCCESSFUL`
|
||||
- 사용자 지시에 따라 Gradle compile/test는 실행하지 않았다.
|
||||
|
||||
## 5. 발견 사항 요약
|
||||
|
||||
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|
||||
|---|---|---|---|---|---|
|
||||
| `REV-P1-001` | Low | 보완 완료 | PRD의 샘플 문서 링크가 실제 경로와 다르다 | Task R1.1 | `P1-R1` |
|
||||
|
||||
## 6. 발견 사항 상세
|
||||
|
||||
### REV-P1-001 — PRD의 샘플 문서 링크가 실제 경로와 다르다
|
||||
|
||||
- **심각도:** Low
|
||||
- **상태:** 확정
|
||||
- **관련 요구사항:** 문서 유지보수 규칙의 샘플 PRD 참조
|
||||
- **소유 Task:** Task R1.1
|
||||
|
||||
**관찰 내용**
|
||||
|
||||
`prd.md`는 `docs/prd/sample-prd.md`를 관련 문서로 가리키지만 해당 파일은 없고, 가이드가 지정한 실제 파일은 `docs/sample/sample-prd.md`다.
|
||||
|
||||
**영향**
|
||||
|
||||
후속 요구사항 보강 시 잘못된 템플릿 경로를 따라가 문서 작성 절차가 중단될 수 있다. 런타임 영향은 없다.
|
||||
|
||||
**권장 조치**
|
||||
|
||||
요구사항 내용은 바꾸지 않고 관련 문서 경로 한 곳만 실제 파일로 정정한다.
|
||||
|
||||
**판정 기록**
|
||||
|
||||
- 2026-07-31 — 두 경로의 파일 존재 여부를 정적으로 확인해 확정했다.
|
||||
- 2026-07-31 — `prd.md` 링크를 `docs/sample/sample-prd.md`로 정정하고 `test -f docs/sample/sample-prd.md`, `git diff --check -- docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/prd.md` 출력 없음으로 보완 완료했다.
|
||||
|
||||
## 7. 확정 항목의 plan·goal 전환
|
||||
|
||||
- `plan-task.md` Phase 1에 Task R1.1 / `P1-R1`을 추가했다.
|
||||
|
||||
## 8. 리뷰 종료 판정
|
||||
|
||||
| 판정 항목 | 결과 | 근거 |
|
||||
|---|---|---|
|
||||
| 리뷰 범위 전체 확인 | 충족 | PRD·plan-task·가이드 대조 완료 |
|
||||
| 후보 항목 판정 완료 | 충족 | `REV-P1-001` 확정 |
|
||||
| 확정 항목 plan 반영 | 충족 | Task R1.1 |
|
||||
| 검증 명령과 결과 기록 | 충족 | 파일 존재 확인과 diff 공백 검사 |
|
||||
|
||||
**최종 결론:** 보완 완료
|
||||
|
||||
**남은 항목:** 없음
|
||||
|
||||
---
|
||||
|
||||
## 9. 2차 리뷰 기록 — 2026-07-31
|
||||
|
||||
### 리뷰 정보·범위
|
||||
|
||||
- **기준:** `5123494e` 기준 미커밋 working tree, PRD·`plan-task.md`·문서 유지보수 가이드.
|
||||
- **목적:** 후속 요구사항과 Phase 7 구현 이후 상단 작업 상태가 현재 근거와 일치하는지 점검한다.
|
||||
- **검증:** `plan-task.md` 상태표·Phase 1~7·전체 검증 기록을 정적 대조했다. 사용자가 컨파일·테스트 통과 상태를 전제로 제공했으므로 Gradle compile/test는 실행하지 않았다.
|
||||
|
||||
### 발견 사항
|
||||
|
||||
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|
||||
|---|---|---|---|---|---|
|
||||
| `REV-P1-002` | Low | 보완 완료 | 상단 후속 변경 상태가 현재 계획·검증 상태와 다르다 | Task R1.2 | `P1-R2` |
|
||||
|
||||
#### REV-P1-002 — 상단 후속 변경 상태가 현재 근거와 다르다
|
||||
|
||||
- **심각도:** Low
|
||||
- **상태:** 보완 완료
|
||||
- **관련 요구사항:** 문서 유지보수 규칙의 현재 상태·활성/다음 Goal 기록
|
||||
- **근거:** `plan-task.md:7-12`는 요구사항 기준을 Feature D로만 표시하고 Phase 7을 현재 Phase에서 누락하며, 다음 Goal로 이전 XML 파일 쓰기 실패 조사를 유지한다. 반면 문서 본문은 Feature A~F와 Phase 7 완료를 기록하고, 사용자는 현재 컨파일·테스트가 통과했다고 명시했다.
|
||||
- **영향:** 다음 작업자가 이미 종료된 환경 이슈를 다음 Goal로 오인하거나 전체 요구사항 범위를 Feature D로 잘못 판단할 수 있다. 런타임 영향은 없다.
|
||||
- **권장 조치:** 상태표만 현재 PRD 전체, Phase 1~7, 미완료 후속 Goal 기준으로 정리한다.
|
||||
- **판정 기록:** 2026-07-31 — 상태표와 Phase 7·전체 검증 기록을 정적 대조해 확정했다.
|
||||
- **보완 기록:** 2026-07-31 — `plan-task.md` 상단 상태표를 PRD 전체, Phase 1~7 후속 보완 상태, 다음 Goal `P3-R2` 기준으로 정리했다. `git diff --check -- docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/plan-task.md`는 출력 없이 통과했고, `./gradlew tasks --all`은 `BUILD SUCCESSFUL`로 통과했다.
|
||||
|
||||
### plan·goal 전환과 종료 판정
|
||||
|
||||
- `plan-task.md` Phase 1에 Task R1.2 / `P1-R2`를 추가했다.
|
||||
- **최종 결론:** 보완 완료.
|
||||
- **남은 항목:** 없음.
|
||||
|
||||
---
|
||||
|
||||
## 10. 3차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 1 / Task 1.1·Task R1.1~R1.2, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `prd.md`, `plan-task.md`의 상태표·시나리오 계약·Phase 1~7·전체 검증 기록, `docs/agent-guides/작업절차.md`, `docs/agent-guides/문서유지보수.md`.
|
||||
- **검증 방법:** PRD·plan-task 동시 존재, 실제 샘플 문서 경로, 완료 Task와 현재 상태·활성/다음 Goal의 일치 여부를 정적으로 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음. 상단 상태만 3차 리뷰 완료로 갱신했다.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
79
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-2-review.md
Normal file
79
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-2-review.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Phase 2 리뷰 보고서
|
||||
|
||||
## 1. 리뷰 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 리뷰 대상 | Phase 2 / Task 2.1~2.2 |
|
||||
| 기준 commit 또는 working tree | 구현 commit `c9e35f2e`, 현재 `5123494e` 기준 working tree |
|
||||
| 리뷰 일자 | 2026-07-31 |
|
||||
| 리뷰어 | Codex |
|
||||
| 기준 문서 | PRD Feature A·C, `plan-task.md` Phase 2 |
|
||||
| 리뷰 상태 | 판정 완료 |
|
||||
|
||||
## 2. 리뷰 목적과 범위
|
||||
|
||||
- 응원 점수 가중치와 전용 신규 부스트가 PRD 값 및 경계일 계약과 일치하는지 확인한다.
|
||||
- 기존 크리에이터·AI·커뮤니티 점수 정책 값의 회귀 여부를 정적으로 확인한다.
|
||||
|
||||
## 3. 판정 기준
|
||||
|
||||
- 확정 가중치 `0.45/0.30/0.10`, 부스트 `1.15/1.10/1.05/1.0`, 경계일 `0·10/11·20/21·30/31`을 기준으로 판정한다.
|
||||
|
||||
## 4. 검토한 근거
|
||||
|
||||
- 코드: `RecommendationScoreSpec.kt`, `RecommendationScorePolicy.kt`
|
||||
- 테스트: `RecommendationScorePolicyTest.shouldCalculateCheerScore`, `shouldApplyCheerCreatorNewBoostByDebutDays`
|
||||
- 이력: `git show c9e35f2e`
|
||||
- 사용자 지시에 따라 Gradle compile/test는 실행하지 않았으며 plan-task의 기존 통과 기록을 참조했다.
|
||||
|
||||
## 5. 발견 사항 요약
|
||||
|
||||
확정 발견 사항 없음.
|
||||
|
||||
## 6. 발견 사항 상세
|
||||
|
||||
- 점수 함수와 DB가 공유하는 상수 값이 PRD와 일치한다.
|
||||
- 0일, 10/11일, 20/21일, 30/31일 단위 테스트가 모두 존재한다.
|
||||
- 기존 `calculateCreatorNewBoost(...)` 값은 `1.5/1.3/1.2`로 유지된다.
|
||||
|
||||
## 7. 확정 항목의 plan·goal 전환
|
||||
|
||||
전환 항목 없음.
|
||||
|
||||
## 8. 리뷰 종료 판정
|
||||
|
||||
| 판정 항목 | 결과 | 근거 |
|
||||
|---|---|---|
|
||||
| 리뷰 범위 전체 확인 | 충족 | 코드·테스트·구현 이력 대조 완료 |
|
||||
| 후보 항목 판정 완료 | 충족 | 후보 없음 |
|
||||
| 확정 항목 plan 반영 | 해당 없음 | 확정 발견 사항 없음 |
|
||||
| 검증 명령과 결과 기록 | 충족 | 정적 검토 및 기존 검증 기록 참조 |
|
||||
|
||||
**최종 결론:** 확정 발견 사항 없음
|
||||
|
||||
**남은 항목:** 없음
|
||||
|
||||
---
|
||||
|
||||
## 9. 2차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 2 / Task 2.1~2.2, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `RecommendationScoreSpec.kt:16-18,29-31`, `RecommendationScorePolicy.kt:21-29,67-78`, `RecommendationScorePolicyTest.shouldCalculateCheerScore`, `shouldApplyCheerCreatorNewBoostByDebutDays`.
|
||||
- **검증 방법:** PRD의 `0.45/0.30/0.10`, `1.15/1.10/1.05/1.0`, 10/20/30일 경계를 코드·테스트와 정적 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
|
||||
---
|
||||
|
||||
## 10. 3차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 2 / Task 2.1~2.2, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `RecommendationScoreSpec.kt:16-18,29-31`, `RecommendationScorePolicy.kt:21-29,67-78`, `RecommendationScorePolicyTest.shouldCalculateCheerScore`, `shouldApplyCheerCreatorNewBoostByDebutDays`.
|
||||
- **검증 방법:** 점수 가중치 `0.45/0.30/0.10`, 부스트 `1.15/1.10/1.05/1.0`, 0·10/11·20/21·30/31일 경계와 기존 크리에이터 부스트 유지 여부를 코드·테스트로 정적 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
130
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-3-review.md
Normal file
130
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-3-review.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# Phase 3 리뷰 보고서
|
||||
|
||||
## 1. 리뷰 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 리뷰 대상 | Phase 3 / Task 3.1~3.5 |
|
||||
| 기준 commit 또는 working tree | 구현 commit `4f348c36`, 보정 commit `6da2378b`, 현재 `5123494e` 기준 working tree |
|
||||
| 리뷰 일자 | 2026-07-31 |
|
||||
| 리뷰어 | Codex |
|
||||
| 기준 문서 | PRD Feature A~C, `plan-task.md` Phase 3 |
|
||||
| 리뷰 상태 | 보완 완료 |
|
||||
|
||||
## 2. 리뷰 목적과 범위
|
||||
|
||||
- 최근 7일 UTC half-open window, 후원·팬Talk 집계, DB-side 점수·부스트, 후보·정렬·limit 구현을 확인한다.
|
||||
- 완료 처리된 Task의 테스트 증거가 명시된 경계 조건을 직접 고정하는지 확인한다.
|
||||
|
||||
## 3. 판정 기준
|
||||
|
||||
- 구현 결함과 완료 증거 누락을 구분한다. 이번 발견은 현재 코드 동작 위반이 아니라 회귀 테스트 근거 누락으로 Low다.
|
||||
|
||||
## 4. 검토한 근거
|
||||
|
||||
- 코드: `RecommendationSnapshotRefreshService.kt`, `RecommendationSnapshotWindowPolicy.kt`, `DefaultHomeRecommendationQueryRepository.kt`
|
||||
- 테스트: `RecommendationSnapshotRefreshServiceTest`, `DefaultHomeRecommendationQueryRepositoryTest`, `RecommendationSnapshotPersistenceAdapterTest`
|
||||
- 이력: `git show 4f348c36`, `git show 6da2378b`
|
||||
- 사용자 지시에 따라 Gradle compile/test는 실행하지 않았다.
|
||||
|
||||
## 5. 발견 사항 요약
|
||||
|
||||
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|
||||
|---|---|---|---|---|---|
|
||||
| `REV-P3-001` | Low | 보완 완료 | Task 3.5의 일부 후보·상위 16개·동점 정렬 완료 증거가 직접 테스트로 고정되지 않았다 | Task R3.1 | `P3-R1` |
|
||||
|
||||
## 6. 발견 사항 상세
|
||||
|
||||
### REV-P3-001 — Task 3.5의 일부 완료 증거가 직접 테스트로 고정되지 않았다
|
||||
|
||||
- **심각도:** Low
|
||||
- **상태:** 확정
|
||||
- **관련 요구사항:** Feature A·C Edge Cases, Task 3.5
|
||||
- **소유 Task:** Task R3.1
|
||||
|
||||
**관찰 내용**
|
||||
|
||||
현재 테스트는 donation 종류·상태·half-open 경계, distinct 후원 수, 점수/부스트, 데뷔 이력 없음과 `limit = 1` 점수 우선순위를 검증한다. 그러나 Task 3.5에 명시된 다음 계약의 직접 테스트는 확인되지 않았다.
|
||||
|
||||
- 실제 데뷔 이력은 있으나 후원·팬Talk가 모두 0인 후보 제외
|
||||
- 미래 데뷔 이력만 있는 후보와 비활성 크리에이터 제외
|
||||
- 17개 이상 후보의 상위 16개 제한
|
||||
- `CHEER_CREATOR` 저장 row의 동점 `randomTieBreaker` 오름차순 조회
|
||||
|
||||
코드는 해당 조건을 구현하고 있어 현재 런타임 결함으로 판정하지 않는다.
|
||||
|
||||
**영향**
|
||||
|
||||
후속 native SQL 수정에서 후보 조건·저장 수·동점 순서가 회귀해도 focused test가 이를 직접 잡지 못할 수 있다.
|
||||
|
||||
**권장 조치**
|
||||
|
||||
프로덕션 코드를 선제 변경하지 않고 누락된 경계 테스트를 먼저 추가하며, 실제 실패가 드러나는 조건만 최소 수정한다.
|
||||
|
||||
**판정 기록**
|
||||
|
||||
- 2026-07-31 — 테스트명·fixture·assertion과 Task 3.5 체크리스트를 대조해 확정했다.
|
||||
- 2026-07-31 — 후보 제외, 상위 16개 제한, `CHEER_CREATOR` 동점 `randomTieBreaker` 오름차순 조회 테스트를 추가했다. focused repository/persistence test는 `BUILD SUCCESSFUL`, 관련 `git diff --check`는 출력 없음으로 보완 완료했다.
|
||||
|
||||
## 7. 확정 항목의 plan·goal 전환
|
||||
|
||||
- `plan-task.md` Phase 3에 Task R3.1 / `P3-R1`을 추가했다.
|
||||
|
||||
## 8. 리뷰 종료 판정
|
||||
|
||||
| 판정 항목 | 결과 | 근거 |
|
||||
|---|---|---|
|
||||
| 리뷰 범위 전체 확인 | 충족 | query·window·정책·테스트 대조 완료 |
|
||||
| 후보 항목 판정 완료 | 충족 | `REV-P3-001` 확정 |
|
||||
| 확정 항목 plan 반영 | 충족 | Task R3.1 |
|
||||
| 검증 명령과 결과 기록 | 충족 | 정적 검색·구현 이력 확인 |
|
||||
|
||||
**최종 결론:** 보완 완료
|
||||
|
||||
**남은 항목:** 없음
|
||||
|
||||
---
|
||||
|
||||
## 9. 2차 리뷰 기록 — 2026-07-31
|
||||
|
||||
### 리뷰 정보·범위
|
||||
|
||||
- **기준:** `5123494e` 기준 미커밋 working tree, PRD Feature A~C, `plan-task.md` Phase 3, 선행 홈 추천 PRD Feature E.
|
||||
- **목적:** 최종 SQL의 7일 window·집계·점수·데뷔일·후보 조건을 현재 요구사항과 다시 대조한다.
|
||||
- **검증:** `findCheerCreatorSnapshots(...)` SQL과 관련 repository 테스트, `075ca88f` 종료 라이브 데뷔 판정 보강 이력을 정적 추적했다. Gradle compile/test는 실행하지 않았다.
|
||||
|
||||
### 발견 사항
|
||||
|
||||
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|
||||
|---|---|---|---|---|---|
|
||||
| `REV-P3-002` | High | 보완 완료 | 종료된 라이브가 `CHEER_CREATOR` 데뷔 이력에서 제외된다 | Task R3.2 | `P3-R2` |
|
||||
|
||||
#### REV-P3-002 — 종료된 라이브가 `CHEER_CREATOR` 데뷔 이력에서 제외된다
|
||||
|
||||
- **심각도:** High
|
||||
- **상태:** 보완 완료
|
||||
- **관련 요구사항:** PRD Feature C, Task 3.4
|
||||
- **근거:** 현재 PRD는 데뷔일을 선행 홈 추천 PRD와 동일하게 계산하도록 한다(`prd.md:102-109`). 선행 PRD는 `channel_name`이 있는 종료 라이브도 데뷔 이력으로 인정하고 `live_room.is_active`를 조건으로 사용하지 않도록 확정한다(`docs/20260529_메인_홈_추천_API/prd.md:157-159`). 그러나 `DefaultHomeRecommendationQueryRepository.kt:589-594`의 `CHEER_CREATOR` 데뷔 CTE는 `lr.is_active = true`를 요구한다. 관련 스냅샷 테스트는 빈 채널명과 활성 라이브만 검증하고 종료 라이브 경계를 고정하지 않는다.
|
||||
- **재현 경로:** 활성 콘텐츠는 없고 채널명이 있는 `is_active = false` 종료 라이브와 최근 7일 응원 활동만 있는 활성 크리에이터를 준비한다. 현재 SQL에서는 `creator_debut` row가 생성되지 않아 후보에서 제외된다.
|
||||
- **영향:** 정상적으로 라이브를 종료한 크리에이터가 응원 점수가 있어도 스냅샷 후보에서 누락되고, 더 늦은 활성 콘텐츠가 있으면 실제 최초 데뷔일보다 높은 신규 부스트를 받을 수 있다.
|
||||
- **권장 조치:** `CHEER_CREATOR` CTE의 라이브 branch에서 `lr.is_active = true`만 제거하고, 종료 라이브·빈 채널명 경계를 repository 회귀 테스트로 고정한다.
|
||||
- **판정 기록:** 2026-07-31 — 요구사항·SQL·선행 보강 commit·테스트 누락을 정적 대조해 확정했다.
|
||||
- **보완 기록:** 2026-07-31 — 채널명이 있는 종료 라이브와 최근 7일 응원 활동만 있는 크리에이터가 `CHEER_CREATOR` 후보에 포함되는 RED 테스트를 추가했고, 빈 `channel_name` 종료 라이브 제외 경계를 함께 고정했다. RED 확인에서 `shouldIncludeEndedLiveWithChannelNameAsCheerCreatorDebut`가 `AssertionFailedError`로 실패했고, `findCheerCreatorSnapshots(...)` 라이브 branch의 `lr.is_active = true`만 제거한 뒤 repository focused test가 `BUILD SUCCESSFUL`로 통과했다. `./gradlew ktlintCheck`도 `BUILD SUCCESSFUL`로 통과했으며, `git diff --check`는 출력 없이 통과했다.
|
||||
|
||||
### plan·goal 전환과 종료 판정
|
||||
|
||||
- `plan-task.md` Phase 3에 Task R3.2 / `P3-R2`를 추가했다.
|
||||
- **최종 결론:** 보완 완료.
|
||||
- **남은 항목:** 없음.
|
||||
|
||||
---
|
||||
|
||||
## 10. 3차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 3 / Task 3.1~3.5·Task R3.1~R3.2, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `RecommendationSnapshotWindowPolicy.kt:7-34`, `DefaultHomeRecommendationQueryRepository.kt:573-647,1185-1227`, `RecommendationSnapshotRefreshService.kt:91-127`, 산식·half-open 경계·후원 distinct·후보 상한·종료 라이브·동점 정렬 repository/persistence 테스트.
|
||||
- **검증 방법:** 최근 7일 UTC half-open window, `CHANNEL_DONATION`·`DONATION`, `UseCanCalculate.useCan` distinct 후원 수, active 팬Talk, DB-side 점수·부스트, 미래/데뷔 없음/비활성 후보 제외, 종료 라이브 데뷔 이력, 점수순 상위 16개와 저장 정렬을 정적으로 추적했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
101
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-4-review.md
Normal file
101
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-4-review.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Phase 4 리뷰 보고서
|
||||
|
||||
## 1. 리뷰 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 리뷰 대상 | Phase 4 / Task 4.1~4.3 |
|
||||
| 기준 commit 또는 working tree | 구현 commit `64b05dee`, `ce43cf2c`, 현재 `5123494e` 기준 working tree |
|
||||
| 리뷰 일자 | 2026-07-31 |
|
||||
| 리뷰어 | Codex |
|
||||
| 기준 문서 | PRD Feature F·Metrics, `plan-task.md` Phase 4 |
|
||||
| 리뷰 상태 | 보완 완료 |
|
||||
|
||||
## 2. 리뷰 목적과 범위
|
||||
|
||||
- empty marker 저장·조회 제외·존재 판정·실제 row 대체를 확인한다.
|
||||
- `CHEER_CREATOR` refresh 성공·실패 관측성 완료 여부를 확인한다.
|
||||
|
||||
## 3. 판정 기준
|
||||
|
||||
- 응답/데이터 무결성 문제와 운영 관측성 누락을 구분한다. 섹션 실패 로그 누락은 Low다.
|
||||
|
||||
## 4. 검토한 근거
|
||||
|
||||
- 코드: `RecommendationSnapshotPersistenceAdapter.kt`, `RecommendationSnapshotRepository.kt`, `RecommendationSnapshotRefreshService.kt`
|
||||
- 테스트: `RecommendationSnapshotPersistenceAdapterTest`, `RecommendationSnapshotRefreshServiceTest`
|
||||
- 정적 검색: `cheer_creator_recommendation_snapshot_refresh_success|failure`
|
||||
- 사용자 지시에 따라 Gradle compile/test는 실행하지 않았다.
|
||||
|
||||
## 5. 발견 사항 요약
|
||||
|
||||
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|
||||
|---|---|---|---|---|---|
|
||||
| `REV-P4-001` | Low | 보완 완료 | `CHEER_CREATOR` 섹션별 refresh 실패 로그가 없다 | Task R4.1 | `P4-R1` |
|
||||
|
||||
## 6. 발견 사항 상세
|
||||
|
||||
### REV-P4-001 — `CHEER_CREATOR` 섹션별 refresh 실패 로그가 없다
|
||||
|
||||
- **심각도:** Low
|
||||
- **상태:** 확정
|
||||
- **관련 요구사항:** PRD Metrics, Task 4.3 GREEN·기대 결과
|
||||
- **소유 Task:** Task R4.1
|
||||
|
||||
**관찰 내용**
|
||||
|
||||
`refreshCheerCreatorSnapshots(...)`는 커밋 후 `event=cheer_creator_recommendation_snapshot_refresh_success`를 남긴다. 반면 query 또는 저장 실패를 같은 섹션 event로 기록하는 코드는 없고, 일괄 refresh의 공통 실패 로그 또는 fallback 공통 실패 로그만 남는다.
|
||||
|
||||
**영향**
|
||||
|
||||
운영에서 스케줄러·fallback 중 어느 경로에서 `CHEER_CREATOR` 생성이 실패했는지 섹션 event만으로 일관되게 집계하기 어렵다. 저장/응답 동작 자체의 결함은 확인되지 않았다.
|
||||
|
||||
**권장 조치**
|
||||
|
||||
성공 경로와 예외 전파를 유지하면서 섹션 실패 event와 window·오류 정보를 최소 추가한다.
|
||||
|
||||
**판정 기록**
|
||||
|
||||
- 2026-07-31 — 코드와 테스트 전체에서 섹션 실패 event가 없음을 정적 검색해 확정했다.
|
||||
- 2026-07-31 — 실패 로그 RED 테스트를 추가해 `AssertionFailedError`를 확인한 뒤 `refreshCheerCreatorSnapshots`에 최소 실패 로그와 예외 재전파를 추가했다. `RecommendationSnapshotRefreshServiceTest`는 `BUILD SUCCESSFUL`, 관련 `git diff --check`는 출력 없음으로 보완 완료했다.
|
||||
|
||||
## 7. 확정 항목의 plan·goal 전환
|
||||
|
||||
- `plan-task.md` Phase 4에 Task R4.1 / `P4-R1`을 추가했다.
|
||||
|
||||
## 8. 리뷰 종료 판정
|
||||
|
||||
| 판정 항목 | 결과 | 근거 |
|
||||
|---|---|---|
|
||||
| 리뷰 범위 전체 확인 | 충족 | marker·로그 경로 확인 |
|
||||
| 후보 항목 판정 완료 | 충족 | `REV-P4-001` 확정 |
|
||||
| 확정 항목 plan 반영 | 충족 | Task R4.1 |
|
||||
| 검증 명령과 결과 기록 | 충족 | 정적 검색과 코드 대조 |
|
||||
|
||||
**최종 결론:** 보완 완료
|
||||
|
||||
**남은 항목:** 없음
|
||||
|
||||
---
|
||||
|
||||
## 9. 2차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 4 / Task 4.1~4.3·Task R4.1, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `RecommendationSnapshotPersistenceAdapter.kt:38-50,73-96`, `RecommendationSnapshotRepository.kt:10-55`, `RecommendationSnapshotRefreshService.kt:91-127`, marker 대체·조회 제외·존재 판정·성공/실패 로그 테스트.
|
||||
- **검증 방법:** marker가 응답 조회에서 제외되면서 대상일 refresh 존재 판정에는 포함되는지, 실제 row 재실행이 marker를 대체하는지, 성공·실패 event가 분리되는지를 정적 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
|
||||
---
|
||||
|
||||
## 10. 3차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 4 / Task 4.1~4.3·Task R4.1, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `RecommendationSnapshotPersistenceAdapter.kt:38-50,73-96`, `RecommendationSnapshotRepository.kt:10-55`, `RecommendationSnapshotRefreshService.kt:91-127`, marker 저장·조회 제외·존재 판정·실제 row 대체·성공/실패 로그 테스트.
|
||||
- **검증 방법:** `CHEER_CREATOR` 빈 결과가 `targetId = 0` marker로 저장되고 응답 조회에서는 제외되는지, 대상일 존재 판정과 실제 row 재실행 대체가 유지되는지, 성공·실패 event가 구분되고 원 예외가 전파되는지 정적으로 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
104
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-5-review.md
Normal file
104
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-5-review.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Phase 5 리뷰 보고서
|
||||
|
||||
## 1. 리뷰 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 리뷰 대상 | Phase 5 / Task 5.1~5.4 |
|
||||
| 기준 commit 또는 working tree | 구현 commit `391acf9e`, `7d0cf0a8`, 현재 `5123494e` 기준 working tree |
|
||||
| 리뷰 일자 | 2026-07-31 |
|
||||
| 리뷰어 | Codex |
|
||||
| 기준 문서 | PRD Feature E·F, `plan-task.md` Phase 5 |
|
||||
| 리뷰 상태 | 보완 완료 |
|
||||
|
||||
## 2. 리뷰 목적과 범위
|
||||
|
||||
- 대상일 조회, section lock, lock 내부 double-check, single-flight, timeout·실패 격리, refresh 후 재조회 흐름을 확인한다.
|
||||
- 구현된 동시성 계약의 직접 회귀 테스트가 존재하는지 확인한다.
|
||||
|
||||
## 3. 판정 기준
|
||||
|
||||
- 구현에는 해당 경로가 존재하지만 직접 테스트가 없는 경우 완료 증거 누락인 Low로 판정한다.
|
||||
|
||||
## 4. 검토한 근거
|
||||
|
||||
- 코드: `RecommendationSnapshotFallbackService.kt`, `HomeRecommendationQueryService.kt`
|
||||
- 테스트: `RecommendationSnapshotFallbackServiceTest`, `HomeRecommendationQueryServiceTest`
|
||||
- 정적 검색: `single|동시|refreshFutures|double-check`와 latch 기반 테스트
|
||||
- 사용자 지시에 따라 Gradle compile/test는 실행하지 않았다.
|
||||
|
||||
## 5. 발견 사항 요약
|
||||
|
||||
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|
||||
|---|---|---|---|---|---|
|
||||
| `REV-P5-001` | Low | 보완 완료 | 동일 섹션 single-flight와 lock 내부 double-check의 직접 회귀 테스트가 없다 | Task R5.1 | `P5-R1` |
|
||||
|
||||
## 6. 발견 사항 상세
|
||||
|
||||
### REV-P5-001 — single-flight와 double-check의 직접 회귀 테스트가 없다
|
||||
|
||||
- **심각도:** Low
|
||||
- **상태:** 확정
|
||||
- **관련 요구사항:** Feature E, Task 5.1·5.3
|
||||
- **소유 Task:** Task R5.1
|
||||
|
||||
**관찰 내용**
|
||||
|
||||
구현은 section별 `refreshFutures`와 lock 획득 후 `hasSnapshot(...)` 재확인을 수행한다. 현재 테스트는 lock miss, refresh 실패, timeout 후 worker 지속, marker 선존재, AI 작업 중 CHEER 독립 실행을 검증하지만 다음 경쟁 조건을 직접 재현하지 않는다.
|
||||
|
||||
- 동일 섹션의 동시 요청이 실제 refresh 1회만 공유하는지
|
||||
- 최초 조회 뒤 lock 진입 전에 다른 실행 주체가 row/marker를 저장했을 때 refresh를 생략하는지
|
||||
|
||||
**영향**
|
||||
|
||||
향후 executor·future·lock 코드 변경에서 중복 refresh 방지의 핵심 경쟁 조건이 깨져도 focused test가 탐지하지 못할 수 있다.
|
||||
|
||||
**권장 조치**
|
||||
|
||||
sleep 대신 latch와 결정적 fake를 사용해 두 경쟁 조건을 고정하고, 실패가 확인될 때만 프로덕션 코드를 최소 수정한다.
|
||||
|
||||
**판정 기록**
|
||||
|
||||
- 2026-07-31 — fallback 테스트 전체와 구현의 동시성 분기를 대조해 확정했다.
|
||||
- 2026-07-31 — 동일 섹션 동시 요청 single-flight와 lock 내부 double-check를 latch 기반 테스트로 추가했다. 현 구현이 테스트를 만족해 프로덕션 코드는 변경하지 않았고, `RecommendationSnapshotFallbackServiceTest`는 `BUILD SUCCESSFUL`, 관련 `git diff --check`는 출력 없음으로 보완 완료했다.
|
||||
|
||||
## 7. 확정 항목의 plan·goal 전환
|
||||
|
||||
- `plan-task.md` Phase 5에 Task R5.1 / `P5-R1`을 추가했다.
|
||||
|
||||
## 8. 리뷰 종료 판정
|
||||
|
||||
| 판정 항목 | 결과 | 근거 |
|
||||
|---|---|---|
|
||||
| 리뷰 범위 전체 확인 | 충족 | fallback 코드·테스트 분기 대조 완료 |
|
||||
| 후보 항목 판정 완료 | 충족 | `REV-P5-001` 확정 |
|
||||
| 확정 항목 plan 반영 | 충족 | Task R5.1 |
|
||||
| 검증 명령과 결과 기록 | 충족 | 정적 검색과 기존 기록 참조 |
|
||||
|
||||
**최종 결론:** 보완 완료
|
||||
|
||||
**남은 항목:** 없음
|
||||
|
||||
---
|
||||
|
||||
## 9. 2차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 5 / Task 5.1~5.4·Task R5.1, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `RecommendationSnapshotFallbackService.kt:81-205`, `HomeRecommendationQueryService.kt:112-136`, `RecommendationSnapshotFallbackServiceTest`, `HomeRecommendationQueryServiceTest`.
|
||||
- **검증 방법:** 대상일 exact snapshot 조회, marker 존재 판정, section lock·double-check·single-flight, 300ms/1,500ms, timeout 후 worker 유지, refresh 실패 격리, 16명 후보 재조회를 코드·테스트와 정적 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
|
||||
---
|
||||
|
||||
## 10. 3차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 5 / Task 5.1~5.4·Task R5.1, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `RecommendationSnapshotFallbackService.kt:28-245`, `HomeRecommendationQueryService.kt:112-136`, fallback service와 query service의 대상일·marker·lock miss·timeout·실패·동시성 테스트.
|
||||
- **검증 방법:** 대상일 exact snapshot, section별 lock key, 300ms lock 대기, 1,500ms 홈 대기, lock 내부 double-check, section별 single-flight, timeout 후 worker 유지, 실패 격리, refresh 후 재조회와 16명 후보 전달을 정적으로 추적했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
101
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-6-review.md
Normal file
101
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-6-review.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Phase 6 리뷰 보고서
|
||||
|
||||
## 1. 리뷰 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 리뷰 대상 | Phase 6 / Task 6.1~6.3 |
|
||||
| 기준 commit 또는 working tree | 현재 `5123494e` 기준 working tree와 plan-task 기존 검증 기록 |
|
||||
| 리뷰 일자 | 2026-07-31 |
|
||||
| 리뷰어 | Codex |
|
||||
| 기준 문서 | PRD Non-Goals·Feature D, `plan-task.md` Phase 6 |
|
||||
| 리뷰 상태 | 보완 완료 |
|
||||
|
||||
## 2. 리뷰 목적과 범위
|
||||
|
||||
- 홈 API URL과 `cheerCreators` item의 공개 필드가 유지되는지 확인한다.
|
||||
- 완료 처리된 API 스키마 회귀 테스트가 비어 있지 않은 item 계약을 직접 고정하는지 확인한다.
|
||||
|
||||
## 3. 판정 기준
|
||||
|
||||
- DTO 구현은 맞지만 회귀 테스트가 필드 계약을 검출하지 못하는 경우 완료 증거 누락인 Low로 판정한다.
|
||||
|
||||
## 4. 검토한 근거
|
||||
|
||||
- 코드: `HomeRecommendationResponse.kt`, `HomeRecommendationFacade.kt`, `HomeRecommendationQueryPort.kt`
|
||||
- 테스트: `HomeRecommendationControllerTest`, `HomeRecommendationResponseTest`
|
||||
- 기존 실행 증거: plan-task의 2026-07-10, 2026-07-31 검증 기록
|
||||
- 사용자 지시에 따라 Gradle compile/test는 실행하지 않았다.
|
||||
|
||||
## 5. 발견 사항 요약
|
||||
|
||||
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|
||||
|---|---|---|---|---|---|
|
||||
| `REV-P6-001` | Low | 보완 완료 | `cheerCreators` item의 정확한 3개 필드 계약이 테스트로 고정되지 않았다 | Task R6.1 | `P6-R1` |
|
||||
|
||||
## 6. 발견 사항 상세
|
||||
|
||||
### REV-P6-001 — `cheerCreators` item의 정확한 3개 필드 계약이 테스트로 고정되지 않았다
|
||||
|
||||
- **심각도:** Low
|
||||
- **상태:** 확정
|
||||
- **관련 요구사항:** Feature D, Non-Goals, Task 6.1
|
||||
- **소유 Task:** Task R6.1
|
||||
|
||||
**관찰 내용**
|
||||
|
||||
응답 DTO는 기존 `HomeCreatorItem`을 사용해 `creatorId`, `creatorNickname`, `creatorProfileImage`를 유지한다. 그러나 `HomeRecommendationResponseTest`는 `cheerCreators = emptyList()`로 직렬화하고, controller 테스트는 배열 존재만 확인한다. 따라서 item 필드가 추가·삭제·개명되어도 현재 두 assertion은 통과할 수 있다.
|
||||
|
||||
**영향**
|
||||
|
||||
향후 DTO 변경에서 공개 API 스키마 회귀가 focused test를 빠져나갈 수 있다. 현재 DTO 자체의 계약 위반은 확인되지 않았다.
|
||||
|
||||
**권장 조치**
|
||||
|
||||
비어 있지 않은 item을 사용해 값과 정확한 필드 수 3을 직렬화 및 controller 계층에서 고정한다.
|
||||
|
||||
**판정 기록**
|
||||
|
||||
- 2026-07-31 — 관련 테스트 fixture와 JSON assertion을 대조해 확정했다.
|
||||
- 2026-07-31 — `cheerCreators` item 직렬화와 홈 API 응답의 정확한 3개 필드 계약을 테스트로 추가했다. focused API test는 fixture 보정 후 `BUILD SUCCESSFUL`, 관련 `git diff --check`는 출력 없음으로 보완 완료했다.
|
||||
|
||||
## 7. 확정 항목의 plan·goal 전환
|
||||
|
||||
- `plan-task.md` Phase 6에 Task R6.1 / `P6-R1`을 추가했다.
|
||||
|
||||
## 8. 리뷰 종료 판정
|
||||
|
||||
| 판정 항목 | 결과 | 근거 |
|
||||
|---|---|---|
|
||||
| 리뷰 범위 전체 확인 | 충족 | DTO·facade·API 테스트 대조 완료 |
|
||||
| 후보 항목 판정 완료 | 충족 | `REV-P6-001` 확정 |
|
||||
| 확정 항목 plan 반영 | 충족 | Task R6.1 |
|
||||
| 검증 명령과 결과 기록 | 충족 | 정적 검토와 기존 실행 기록 참조 |
|
||||
|
||||
**최종 결론:** 보완 완료
|
||||
|
||||
**남은 항목:** 없음
|
||||
|
||||
---
|
||||
|
||||
## 9. 2차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 6 / Task 6.1~6.3·Task R6.1, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `HomeRecommendationResponseTest.kt:61-67,117-123`, `HomeRecommendationControllerTest.kt:529-549`, `HomeRecommendationFacade.kt`, `HomeRecommendationQueryService.kt`.
|
||||
- **검증 방법:** `cheerCreators` 실제 item의 `creatorId`, `creatorNickname`, `creatorProfileImage` 값과 정확한 3개 필드 계약, 기존 API URL·DTO 유지, 대상일 snapshot fixture를 정적 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
|
||||
---
|
||||
|
||||
## 10. 3차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 6 / Task 6.1~6.3·Task R6.1, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `HomeRecommendationController.kt`, `HomeRecommendationResponse.kt:20-51`, `HomeRecommendationFacade.kt:50-95,294-298`, `HomeRecommendationControllerTest.shouldKeepCheerCreatorItemSchemaOnHomeRecommendations`, `HomeRecommendationResponseTest`의 정확한 필드 집합 assertion.
|
||||
- **검증 방법:** 기존 `GET /api/v2/home/recommendations` URL과 `cheerCreators` item의 `creatorId`, `creatorNickname`, `creatorProfileImage` 3개 필드만 유지되는지, 대상일 스냅샷 fixture가 실제 조회 경로와 일치하는지 정적으로 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
82
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-7-review.md
Normal file
82
docs/20260710_메인_홈_추천_응원크리에이터_스냅샷/reviews/phase-7-review.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Phase 7 리뷰 보고서
|
||||
|
||||
## 1. 리뷰 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 리뷰 대상 | Phase 7 / Task 7.1 / `P7-GATE` |
|
||||
| 기준 commit 또는 working tree | `5123494e` 기준 미커밋 working tree |
|
||||
| 리뷰 일자 | 2026-07-31 |
|
||||
| 리뷰어 | Codex |
|
||||
| 기준 문서 | PRD Feature D, `plan-task.md` Phase 7 |
|
||||
| 리뷰 상태 | 판정 완료 |
|
||||
|
||||
## 2. 리뷰 목적과 범위
|
||||
|
||||
- 인증 회원 본인과 활성 팔로우 크리에이터만 제외되는지 확인한다.
|
||||
- 비활성 팔로우 이력, 비회원, 기존 양방향 차단, 스냅샷 순서·후보 16개/응답 8개 정책이 유지되는지 확인한다.
|
||||
|
||||
## 3. 판정 기준
|
||||
|
||||
- 공개 API나 스냅샷 산식을 변경하지 않고 상세 조회의 `memberId != null` 조건에서만 개인화 필터를 적용해야 한다.
|
||||
|
||||
## 4. 검토한 근거
|
||||
|
||||
- 변경 diff: `DefaultHomeRecommendationQueryRepository.kt`, `DefaultHomeRecommendationQueryRepositoryTest.kt`, PRD, plan-task
|
||||
- 코드: `notViewerCondition(...)`, `notActiveFollowedCreatorCondition(...)`, 기존 `notBlockedCreatorCondition(...)`
|
||||
- 테스트: `shouldExcludeSelfAndActiveFollowedCreatorsFromCheerCreatorDetails`, `shouldKeepAnonymousCheerCreatorDetailsWithoutMemberFilters`, 기존 양방향 차단 테스트
|
||||
- 정적 검증: `git diff --check`, `git diff --name-status`
|
||||
- 사용자 지시에 따라 Gradle compile/test는 실행하지 않았으며 plan-task의 기존 통과 기록을 참조했다.
|
||||
|
||||
## 5. 발견 사항 요약
|
||||
|
||||
확정 발견 사항 없음.
|
||||
|
||||
## 6. 발견 사항 상세
|
||||
|
||||
- `memberId == null`이면 신규 두 조건이 모두 생략된다.
|
||||
- 인증 회원이면 `member.id != memberId`와 활성 `CreatorFollowing` row의 `not exists`가 적용된다.
|
||||
- `isActive == false` 팔로우 이력은 제외 조건이 아니며 기존 차단 조건은 그대로 조합된다.
|
||||
- 서비스는 기존처럼 스냅샷 순서로 상세를 재조립하고 최대 8개만 반환한다.
|
||||
- 변경 범위는 PRD·plan-task·repository·repository test 네 파일로 한정되어 공개 DTO나 스냅샷 생성 경로를 수정하지 않았다.
|
||||
|
||||
## 7. 확정 항목의 plan·goal 전환
|
||||
|
||||
전환 항목 없음.
|
||||
|
||||
## 8. 리뷰 종료 판정
|
||||
|
||||
| 판정 항목 | 결과 | 근거 |
|
||||
|---|---|---|
|
||||
| 리뷰 범위 전체 확인 | 충족 | 요구사항·diff·테스트 정적 대조 완료 |
|
||||
| 후보 항목 판정 완료 | 충족 | 후보 없음 |
|
||||
| 확정 항목 plan 반영 | 해당 없음 | 확정 발견 사항 없음 |
|
||||
| 검증 명령과 결과 기록 | 충족 | diff 검사 및 기존 검증 기록 참조 |
|
||||
|
||||
**최종 결론:** 확정 발견 사항 없음
|
||||
|
||||
**남은 항목:** 없음
|
||||
|
||||
---
|
||||
|
||||
## 9. 2차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 7 / Task 7.1·`P7-GATE`, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `DefaultHomeRecommendationQueryRepository.kt:804-828,1274-1304`, `HomeRecommendationQueryService.kt:112-120`, 본인·활성/비활성 팔로우·비회원·양방향 차단 repository 테스트.
|
||||
- **검증 방법:** `memberId == null`의 필터 생략, 인증 회원의 본인 제외, `CreatorFollowing.isActive == true` 필터, 비활성 이력 유지, 기존 차단 조건 조합, snapshot 순서·최대 8명 재조립을 정적 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
|
||||
---
|
||||
|
||||
## 10. 3차 리뷰 기록 — 2026-07-31
|
||||
|
||||
- **리뷰 대상:** Phase 7 / Task 7.1·`P7-GATE`, `5123494e` 기준 미커밋 working tree.
|
||||
- **검토 근거:** `DefaultHomeRecommendationQueryRepository.kt:803-827,1273-1303`, `HomeRecommendationQueryService.kt:112-120`, 본인·활성/비활성 팔로우·비회원·양방향 차단 repository 테스트와 service의 memberId·순서·limit 테스트.
|
||||
- **검증 방법:** `memberId == null` 필터 생략, 인증 회원 본인 제외, `CreatorFollowing.isActive == true`의 `not exists`, 비활성 이력 유지, 기존 양방향 차단, 16명 후보 안에서 스냅샷 순서대로 최대 8명 반환을 정적으로 대조했다. Gradle compile/test는 실행하지 않았다.
|
||||
- **발견 사항:** 확정 발견 사항 없음.
|
||||
- **plan·goal 전환:** 전환 항목 없음.
|
||||
- **최종 결론:** 확정 발견 사항 없음.
|
||||
- **남은 항목:** 없음.
|
||||
Reference in New Issue
Block a user