feat(home): 최근 활동 이동 식별자를 보강한다
This commit is contained in:
@@ -29,6 +29,9 @@
|
||||
- 저장소에는 DB migration 디렉터리가 없으므로 신규 스냅샷/조회 이력 엔티티 추가 시 운영 DB DDL 반영은 배포 절차에서 별도 수행한다. 코드 구현 task에는 JPA 엔티티/리포지토리와 통합 테스트를 포함하고, Phase 7 완료 후 신규 엔티티 테이블 생성 SQL을 문서 산출물로 작성한다.
|
||||
- 조회 구현은 JPA/QueryDSL 우선, native SQL 제한 사용의 하이브리드 전략으로 진행한다. 단순 조회/상세 조립/대상 활성 조건은 JPA 또는 QueryDSL로 표현하고, CTE/window function/`union all`/DB-side exact scoring처럼 SQL 고급 기능이 필요한 추천 산정에만 native SQL을 사용한다. native SQL 사용 시에는 H2 MySQL mode와 Kotlin 정책 산식 parity를 포함한 repository 통합 테스트를 반드시 둔다.
|
||||
- 이번 범위에서는 기존 홈/콘텐츠 홈/라이브/AI 캐릭터 API의 공개 스키마를 변경하지 않고, 앱 다국어 문구 번역, ML 개인화, A/B 테스트 플랫폼, 관리자 화면, 추천 결과 수동 편집 기능은 구현하지 않는다. 응답 enum은 앱 다국어 처리를 위해 안정적인 영문 code로 유지한다.
|
||||
- 방금 활동한 크리에이터 item은 활동을 등록한 `Member.id`를 non-null `creatorId`로 항상 제공한다.
|
||||
- `LIVE` 활동의 `targetId`는 `live_room.is_active = true`이면 `live_room.id`, `false`이면 `null`로 제공한다.
|
||||
- 별도 `isOnAir`, `targetType`, 종료 전용 활동 타입은 추가하지 않고 기존 활동 시간·정렬과 비 LIVE `targetId` 의미를 유지한다.
|
||||
|
||||
---
|
||||
|
||||
@@ -691,12 +694,185 @@
|
||||
|
||||
---
|
||||
|
||||
### Phase 11: 최근 활동 라이브 이동 대상 분기
|
||||
|
||||
**Phase 결과:** `recentlyActiveCreators[]`가 모든 활동의 `creatorId`를 제공하고, 진행 중 라이브는 라이브 방으로, 종료된 라이브는 크리에이터 채널로 이동할 수 있는 식별자 계약을 제공한다.
|
||||
|
||||
**선행조건:** Phase 10 완료와 `docs/20260529_메인_홈_추천_API/prd.md` Feature D의 2026-07-30 확정 계약.
|
||||
|
||||
**Phase 완료 조건:** `P11-T1`, `P11-T2`, `P11-GATE`의 체크박스와 완료 증거가 모두 충족되고 검증 결과가 이 문서의 Verification Log에 누적된다.
|
||||
|
||||
**리뷰 후속 조건(2026-07-30):** 완료된 `P11-T1`, `P11-T2`, `P11-GATE`는 되돌리지 않고, `REV-P11-001`의 신규 회귀 Goal `P11-R1`을 완료한 뒤 Phase 11 리뷰를 종료한다.
|
||||
|
||||
#### Task 11.1: 최근 활동 조회 record와 LIVE target id 분기
|
||||
|
||||
**Goal 실행 `P11-T1`:** 최근 활동 조회 결과가 크리에이터 id를 항상 포함하고 라이브 활성 상태에 따라 라이브 방 id 또는 `null`을 반환한다.
|
||||
|
||||
- **시작 조건:** Phase 10 완료와 PRD Feature D Response Contract 확정.
|
||||
- **완료 증거:** 아래 체크박스 완료, repository focused test 통과, 내부 record와 native query row 매핑 일치.
|
||||
- **범위 밖:** 공개 API DTO와 facade 매핑, 신규 활동 타입·이동 타입·상태 필드 추가.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt`
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt`
|
||||
- Modify: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt`
|
||||
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt`
|
||||
|
||||
**Interfaces:**
|
||||
|
||||
- Consumes: `LiveRoom.isActive`, `LiveRoom.id`, `LiveRoom.member.id`, 기존 `findRecentlyActiveCreators(limit, memberId, includeAdultActivities)`.
|
||||
- Produces:
|
||||
|
||||
```kotlin
|
||||
data class RecentlyActiveCreatorRecord(
|
||||
val creatorId: Long,
|
||||
val creatorNickname: String,
|
||||
val creatorProfileImage: String?,
|
||||
val activityType: CreatorActivityType,
|
||||
val activityAt: LocalDateTime,
|
||||
val targetId: Long?
|
||||
)
|
||||
```
|
||||
|
||||
- [x] **RED:** `shouldFindOneLatestActivityPerCreatorWithActivityType`에서 모든 활동의 `creatorId`를 검증하고 진행 중 LIVE의 `targetId`가 `live_room.id`인지 검증한다. `shouldIncludeInactiveLiveWithChannelNameInRecentlyActiveCreators`에서는 종료된 LIVE의 `creatorId`와 `targetId = null`을 검증한다.
|
||||
- [x] **RED 확인:** 아래 focused test를 실행해 `creatorId` 미구현 컴파일 실패 또는 진행 중 LIVE `targetId`의 `null` assertion 실패를 확인한다.
|
||||
|
||||
```bash
|
||||
./gradlew test \
|
||||
--tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest.shouldFindOneLatestActivityPerCreatorWithActivityType \
|
||||
--tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest.shouldIncludeInactiveLiveWithChannelNameInRecentlyActiveCreators
|
||||
```
|
||||
|
||||
- [x] **GREEN:** `RecentlyActiveCreatorRecord`에 non-null `creatorId`를 추가한다. native SQL outer select에 `ranked.creator_id`를 포함하고 LIVE branch의 `target_id`를 아래 식으로 변경한 뒤 row index를 새 select 순서에 맞춘다. `HomeRecommendationQueryServiceTest`의 기존 record fixture에는 해당 크리에이터 id만 추가한다.
|
||||
|
||||
```sql
|
||||
case when lr.is_active = true then lr.id else null end as target_id
|
||||
```
|
||||
|
||||
- [x] **GREEN 확인:** RED focused test를 다시 실행해 진행 중 LIVE는 `targetId = live_room.id`, 종료된 LIVE는 `targetId = null`, 모든 활동은 올바른 `creatorId`를 반환하는지 확인한다.
|
||||
- [x] **REFACTOR:** 비 LIVE 활동의 `targetId`, `activityAt`, 크리에이터별 최신 활동 선정, 차단·성인·비활성 회원 제외 조건을 변경하지 않았는지 repository 테스트 클래스 전체로 회귀 확인하고 결과를 Progress에 기록한다.
|
||||
|
||||
```bash
|
||||
./gradlew test \
|
||||
--tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest \
|
||||
--tests kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryServiceTest
|
||||
```
|
||||
|
||||
#### Task 11.2: 최근 활동 공개 응답에 creatorId 노출
|
||||
|
||||
**Goal 실행 `P11-T2`:** 홈 통합 API가 내부 최근 활동 record의 `creatorId`와 상태별 `targetId`를 최종 JSON에 그대로 노출한다.
|
||||
|
||||
- **시작 조건:** `P11-T1` 완료.
|
||||
- **완료 증거:** 아래 체크박스 완료, 홈 통합 API 통합 테스트 통과, additive schema와 상태별 JSON 계약 확인.
|
||||
- **범위 밖:** 앱 네비게이션 코드 구현, 라이브 입장 실패 처리, 기존 endpoint URL과 다른 추천 item 변경.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/dto/recommendation/HomeRecommendationResponse.kt`
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacade.kt`
|
||||
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/HomeRecommendationControllerTest.kt`
|
||||
|
||||
**Interfaces:**
|
||||
|
||||
- Consumes: `P11-T1`의 `RecentlyActiveCreatorRecord.creatorId`와 상태별 nullable `targetId`.
|
||||
- Produces:
|
||||
|
||||
```kotlin
|
||||
data class HomeActiveCreatorItem(
|
||||
val creatorId: Long,
|
||||
val creatorNickname: String,
|
||||
val creatorProfileImage: String,
|
||||
val activityType: String,
|
||||
val activityAt: String,
|
||||
val targetId: Long?
|
||||
)
|
||||
```
|
||||
|
||||
- [x] **RED:** `HomeRecommendationControllerTest.shouldExposeNavigationIdsForRecentlyActiveLiveCreators`를 추가한다. 서로 다른 크리에이터의 진행 중 LIVE와 종료된 LIVE를 저장하고 홈 통합 API 응답에서 두 item의 `creatorId`, 진행 중 LIVE의 `targetId = live_room.id`, 종료된 LIVE의 명시적 `targetId = null`을 검증한다.
|
||||
- [x] **RED 확인:** 아래 focused test를 실행해 `creatorId` JSON path 미존재로 실패하는지 확인한다.
|
||||
|
||||
```bash
|
||||
./gradlew test \
|
||||
--tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest.shouldExposeNavigationIdsForRecentlyActiveLiveCreators
|
||||
```
|
||||
|
||||
- [x] **GREEN:** `HomeActiveCreatorItem`에 non-null `creatorId`를 추가하고 `HomeRecommendationFacade.RecentlyActiveCreatorRecord.toItem()`에서 `creatorId = creatorId`를 매핑한다. controller 테스트의 `saveLiveRoom` fixture는 종료된 라이브를 만들 수 있도록 `isActive: Boolean = true`만 추가한다.
|
||||
- [x] **GREEN 확인:** 같은 focused test를 다시 실행해 최종 JSON의 진행 중/종료 LIVE 이동 식별자 계약을 확인한다.
|
||||
- [x] **REFACTOR:** `isOnAir`, `targetType`, 종료 전용 활동 타입을 추가하지 않고 기존 프로필 이미지·활동 타입·UTC 시간 변환을 유지한다. 홈 API 테스트 클래스 전체를 실행해 공개 응답 회귀를 확인하고 결과를 Progress에 기록한다.
|
||||
|
||||
```bash
|
||||
./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest
|
||||
```
|
||||
|
||||
#### Phase 11 Gate
|
||||
|
||||
**Goal 실행 `P11-GATE`:** Phase 11의 내부 조회·공개 응답 계약과 변경 범위 품질을 최종 판정한다.
|
||||
|
||||
- **시작 조건:** `P11-T1`, `P11-T2` 완료.
|
||||
- **완료 증거:** 아래 focused/영향 범위 회귀, lint, 문서 검증이 모두 통과하고 실제 결과가 Verification Log에 기록됨.
|
||||
- **범위 밖:** Gate 통과를 위한 테스트 삭제·완화, 전체 라이브/추천 구조 리팩터링, 신규 dependency 추가.
|
||||
|
||||
```bash
|
||||
./gradlew test \
|
||||
--tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest \
|
||||
--tests kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryServiceTest \
|
||||
--tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest
|
||||
./gradlew ktlintCheck
|
||||
./gradlew tasks --all
|
||||
git diff --check
|
||||
```
|
||||
|
||||
**Expected:** 모든 명령이 0 exit code로 통과하고, 진행 중 LIVE는 라이브 방 id, 종료된 LIVE는 `null`, 모든 최근 활동 item은 non-null 크리에이터 id를 반환하며 비 LIVE 활동 계약은 유지된다.
|
||||
|
||||
- 전체 `./gradlew test`는 공통 인증·설정·다중 도메인을 변경하지 않는 국소 조회/DTO 변경이므로 기본 생략한다. focused/영향 범위 회귀에서 범위를 판단할 수 없는 실패가 발생하면 전체 테스트로 확장하고 결과를 기록한다.
|
||||
|
||||
**기존 구현 실행 순서:** `P11-T1 → P11-T2 → P11-GATE`
|
||||
|
||||
#### Task 11.3: 종료 LIVE targetId의 명시적 null JSON 계약 검증 보강
|
||||
|
||||
**Goal 실행 `P11-R1`:** `REV-P11-001`에 따라 종료 LIVE 응답이 `targetId` 필드를 생략하지 않고 명시적 `null`로 제공하는 계약을 회귀 테스트로 고정한다.
|
||||
|
||||
- **시작 조건:** `docs/20260529_메인_홈_추천_API/reviews/phase-11-review.md`의 `REV-P11-001` 확정.
|
||||
- **완료 증거:** JSON path 존재와 null 값을 각각 검증하는 focused test, 홈 API 테스트 회귀, lint·문서 검증, review/Verification Log 기록.
|
||||
- **범위 밖:** production DTO·facade·query 변경, nullable 정책 변경, 신규 Jackson 전역 설정.
|
||||
- **TDD 예외 사유:** 현재 production 구현은 nullable DTO와 기본 Jackson 설정으로 명시적 null을 직렬화하며, 확정 항목은 누락과 null을 구분하지 못하는 기존 assertion의 판별력 공백이다. production 동작을 변경하지 않는 테스트 보강이므로 별도 실패 구현을 만들지 않는다.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/HomeRecommendationControllerTest.kt`
|
||||
- Modify: `docs/20260529_메인_홈_추천_API/plan-task.md`
|
||||
- Modify: `docs/20260529_메인_홈_추천_API/reviews/phase-11-review.md`
|
||||
|
||||
- [x] 종료 LIVE의 `$.data.recentlyActiveCreators[1].targetId`에 `hasJsonPath()`를 추가하고 기존 `doesNotExist()`를 함께 사용해 필드 존재와 null 값을 모두 검증한다.
|
||||
- [x] 아래 focused test를 실행해 명시적 null JSON 계약이 통과하는지 확인한다.
|
||||
|
||||
```bash
|
||||
./gradlew test \
|
||||
--tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest.shouldExposeNavigationIdsForRecentlyActiveLiveCreators
|
||||
```
|
||||
|
||||
- [x] 홈 API 테스트 클래스와 Phase 11 문서 검증을 실행한다.
|
||||
|
||||
```bash
|
||||
./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest
|
||||
./gradlew ktlintCheck
|
||||
./gradlew tasks --all
|
||||
git diff --check
|
||||
```
|
||||
|
||||
- [x] 실제 실행 결과를 이 문서 Verification Log와 `phase-11-review.md`의 수정 후 검증 기록에 누적하고 `REV-P11-001`을 `수정 완료`로 갱신한다.
|
||||
|
||||
**후속 실행 순서:** `P11-R1`
|
||||
|
||||
---
|
||||
|
||||
## PRD Coverage Check
|
||||
|
||||
- Feature A: Phase 3, Phase 6, Phase 7에서 통합 조회, limit, 인증/비회원, 팔로우 제외, 콘텐츠 조회 이력, 본인인증 여부, 차단 필터, 스냅샷 빈 배열 처리를 검증한다.
|
||||
- Feature B: Task 3.1, Task 6.3에서 라이브 최신순/전체보기/비활성 회원 제외와 크리에이터 닉네임/프로필 이미지/라이브 번호 노출 필드를 검증한다.
|
||||
- Feature C: Task 3.1과 Task 7.7에서 기존 콘텐츠 홈 배너 재활용, orders 정렬, 동일 orders 랜덤 정렬, 활성 배너/콘텐츠 조건, `EVENT`/`CREATOR`/`SERIES` 대상 비활성 제외, `CREATOR`/`SERIES` 대상 양방향 차단 제외, `LINK` 배너의 자체 활성 상태 기준 노출, 앱 이동 필드 유지를 검증한다.
|
||||
- Feature D: Task 1.3, Task 3.1, Task 10.1에서 활동 타입 영문 enum, 최신 활동 1개, 크리에이터 프로필 이미지/닉네임, UTC 시간, 이동 대상 id nullable, `COMMUNITY` 활동의 `creator_community.id` 이동 대상 id를 검증한다.
|
||||
- Feature D: Task 1.3, Task 3.1, Task 10.1, Task 11.1, Task 11.2, Task 11.3에서 활동 타입 영문 enum, 최신 활동 1개, 크리에이터 id/프로필 이미지/닉네임, UTC 시간, `COMMUNITY` 활동의 `creator_community.id`, 진행 중 LIVE의 `live_room.id`, 종료된 LIVE의 명시적 nullable 이동 대상과 크리에이터 채널 fallback 식별자를 검증한다.
|
||||
- Feature E: Task 1.1, Task 1.2, Task 3.2, Task 6.3에서 데뷔일/점수/동점 랜덤 정렬/프로필 이미지와 닉네임 노출/전체보기를 검증한다.
|
||||
- Feature F: Task 1.1, Task 3.2, Task 6.3, Task 9.1에서 첫 오디오 콘텐츠 판정, 최신성 점수 구간, 예약 공개 제외, native query Boolean 계산 컬럼 매핑을 검증한다.
|
||||
- Feature G: Task 1.1, Task 2.2, Task 2.6, Task 2.7, Task 2.8, Task 2.9, Task 3.3, Task 6.3, Task 8.1, Task 8.2에서 AI 캐릭터 점수, 캐릭터 생성일 기준 신규 부스트, 스냅샷, AI 채팅 집계 범위, DB-side exact scoring, 응답 필드, 오리지널 작품명 조건, 전체보기, AI 캐릭터에 대응하는 `creatorId` 노출을 검증한다.
|
||||
@@ -705,12 +881,17 @@
|
||||
- Feature J: Task 1.1, Task 2.2, Task 2.3.1, Task 2.4, Task 2.5, Task 2.8, Task 2.9, Task 3.3, Task 5.1, Task 5.2에서 최근 응원 점수/스냅샷 조회, 스냅샷 일 배치 클러스터 단일 실행, 8명 limit, 크리에이터 프로필 이미지/닉네임 노출, `CHANNEL_DONATION` 기준 후원 금액/후원 수, 팬 Talk 수, 최근 7일 집계, 데뷔일 기준 신규 부스트, DB-side exact scoring, 해당 섹션의 동시 팔로우를 검증한다.
|
||||
- Feature K: Task 1.1, Task 2.2, Task 2.5, Task 2.8, Task 2.9, Task 3.3, Task 7.1에서 인기 커뮤니티 점수/조건/홈 통합 응답 노출 필드(크리에이터 프로필 이미지, 닉네임, UTC 시간, 좋아요 수, 댓글 수, 내용)/댓글 불가 게시글 댓글 수 0점 계산, 데뷔일 기준 신규 부스트, 최근 7일 집계, DB-side exact scoring을 검증한다.
|
||||
- Metrics: Task 7.2에서 메인 홈 API 성공률/응답 시간, 섹션별 빈 응답 비율, 전체보기 API 조회 수, 추천 섹션별 클릭률, 동시 팔로우 요청/성공 수, 콘텐츠 조회 이력 기록 성공률, 일 배치 집계 성공/실패 수와 스냅샷 생성 소요 시간의 로그 또는 metric 기록 지점을 검증한다.
|
||||
- Technical Constraints/Non-Goals: Phase 1~7과 Phase 9에서 `v2.api.home`/`v2.recommendation` 패키지 경계, `port.out` 의존 방향, 신규 v2 endpoint 분리, 기존 공개 스키마 유지, 서버 다국어 번역/ML 개인화/A-B 테스트/관리자 화면/수동 편집 제외 조건을 검증한다. 응답 enum 영문 code 안정성은 Task 1.3과 Task 3.1에서, `RecommendationSnapshotPort`의 persistence entity 노출 정리는 Task 2.4에서, 점수 기반 스냅샷의 `RecommendationScoreSpec` 공유 산식과 candidate pre-limit 금지는 Task 2.9에서, JPA/QueryDSL 우선 및 native SQL 제한 사용 전략은 Task 2.9와 Task 3.1에서, native query Boolean 계산 컬럼 매핑은 Task 9.1에서, 신규 엔티티 테이블 생성 SQL 문서화는 Task 7.4에서 검증한다.
|
||||
- Technical Constraints/Non-Goals: Phase 1~7, Phase 9, Phase 11에서 `v2.api.home`/`v2.recommendation` 패키지 경계, `port.out` 의존 방향, 신규 v2 endpoint 분리, additive `creatorId`, 기존 필드 유지, 서버 다국어 번역/ML 개인화/A-B 테스트/관리자 화면/수동 편집 제외 조건을 검증한다. 응답 enum 영문 code 안정성은 Task 1.3과 Task 3.1에서, `RecommendationSnapshotPort`의 persistence entity 노출 정리는 Task 2.4에서, 점수 기반 스냅샷의 `RecommendationScoreSpec` 공유 산식과 candidate pre-limit 금지는 Task 2.9에서, JPA/QueryDSL 우선 및 native SQL 제한 사용 전략은 Task 2.9와 Task 3.1에서, native query Boolean 계산 컬럼 매핑은 Task 9.1에서, 신규 엔티티 테이블 생성 SQL 문서화는 Task 7.4에서, 최근 활동의 신규 상태·이동 타입 미추가는 Task 11.2에서 검증한다.
|
||||
|
||||
---
|
||||
|
||||
## Verification Log
|
||||
|
||||
- 2026-07-30: Phase 11의 `P11-R1` 반영 상태를 Gradle 재실행 없이 2차 정적 리뷰했다. PRD Feature D와 native query/row mapping, `RecentlyActiveCreatorRecord`, facade, `HomeActiveCreatorItem`, repository/API 테스트를 다시 대조했고, 모든 활동의 non-null `creatorId`, 진행 중 LIVE의 `live_room.id`, 종료 LIVE의 명시적 null, 비 LIVE `targetId` 유지가 일치함을 확인했다. record·DTO 생성자와 조회 호출 지점, null 제외 설정, 변경 Kotlin 라인 길이, `git diff --check`를 점검했으며 신규 확정 발견 사항은 없었다. 기존 `REV-P11-001`은 수정 완료 상태를 유지하고 추가 회귀 Task/Goal은 만들지 않았다. 사용자 지시에 따라 컴파일과 테스트는 실행하지 않았으며 상세 결과는 `reviews/phase-11-review.md`의 2차 정적 재점검 절에 기록했다.
|
||||
- 2026-07-30: P11-R1을 완료했다. `HomeRecommendationControllerTest.shouldExposeNavigationIdsForRecentlyActiveLiveCreators`의 종료 LIVE `targetId` assertion에 `hasJsonPath()`를 추가하고 기존 `doesNotExist()`를 유지해 JSON path 존재와 명시적 null 값을 함께 검증하도록 보강했다. focused test는 최초 120000ms timeout에 도달해 240000ms로 재실행했고 `BUILD SUCCESSFUL`로 통과했다. 추가 검증으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest`, `./gradlew ktlintCheck`, `./gradlew tasks --all`, `git diff --check`가 모두 `BUILD SUCCESSFUL` 또는 무출력 통과했다. production DTO·facade·query는 변경하지 않았고, `REV-P11-001`은 수정 완료로 갱신했다.
|
||||
- 2026-07-30: Phase 11 구현을 테스트 재실행 없이 정적 리뷰했다. record/native query의 `creatorId` select와 row index, LIVE `targetId` 분기, DTO/facade 매핑은 PRD Feature D와 일치했다. `HomeRecommendationControllerTest.shouldExposeNavigationIdsForRecentlyActiveLiveCreators`의 종료 LIVE assertion이 `doesNotExist()`만 사용해 JSON path 누락과 null을 구분하지 못하는 테스트 공백 `REV-P11-001`을 Low로 확정하고, 완료된 Task와 Gate를 되돌리지 않은 채 신규 회귀 Task 11.3/Goal `P11-R1`을 추가했다. 사용자 지시에 따라 Gradle 컴파일과 테스트는 실행하지 않았으며, 상세 근거는 `docs/20260529_메인_홈_추천_API/reviews/phase-11-review.md`에 기록했다.
|
||||
- 2026-07-30: Phase 11 구현을 완료했다. P11-T1 RED에서 `DefaultHomeRecommendationQueryRepositoryTest.shouldFindOneLatestActivityPerCreatorWithActivityType`, `shouldIncludeInactiveLiveWithChannelNameInRecentlyActiveCreators` focused 실행이 `RecentlyActiveCreatorRecord.creatorId` 미구현으로 `compileTestKotlin` 실패하는 것을 확인했다. GREEN에서 내부 record에 non-null `creatorId`를 추가하고 최근 활동 native SQL outer select/row mapping에 `ranked.creator_id`를 포함했으며, LIVE `target_id`를 `case when lr.is_active = true then lr.id else null end`로 변경했다. focused 재실행과 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest --tests kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryServiceTest`가 `BUILD SUCCESSFUL`로 통과했다. P11-T2 RED에서는 `HomeRecommendationControllerTest.shouldExposeNavigationIdsForRecentlyActiveLiveCreators`가 `$.data.recentlyActiveCreators[0].creatorId` `PathNotFoundException`으로 실패했고, GREEN에서 `HomeActiveCreatorItem.creatorId`와 facade 매핑을 추가해 focused test와 `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest`가 `BUILD SUCCESSFUL`로 통과했다. P11-GATE로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest --tests kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryServiceTest --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest`, `./gradlew ktlintCheck`, `./gradlew tasks --all`, `git diff --check`가 모두 통과했다. 추가 광역 회귀로 `./gradlew test`를 실행했으나 300000ms와 600000ms timeout에 각각 도달해 완료 결과를 얻지 못했고, 동일 timeout 2회 후 추가 재시도하지 않았다.
|
||||
- 2026-07-30: 사용자 승인에 따라 방금 활동한 크리에이터의 모든 item에 non-null `creatorId`를 추가하고, 진행 중 LIVE는 `targetId = live_room.id`, 종료된 LIVE는 `targetId = null`로 분기하는 요구사항을 PRD Feature D와 plan-task Phase 11에 반영했다. `P11-T1`은 내부 record/native query, `P11-T2`는 공개 DTO/facade/JSON, `P11-GATE`는 focused 회귀와 lint를 각각 소유하도록 분리했다. 별도 `isOnAir`, `targetType`, 종료 전용 활동 타입과 기존 정렬 변경은 범위에서 제외했다. 문서 자체 검토로 Phase 11의 PRD coverage, 타입·테스트명·파일 경로 일치, placeholder와 상충 문구 부재를 확인했고, `git diff --check`와 `./gradlew tasks --all`이 통과했다. 이 단계에서는 제품 코드를 변경하거나 테스트를 실행하지 않았다.
|
||||
- 2026-07-10: 사용자 피드백에 따라 홈 추천 최근 활동 크리에이터의 `COMMUNITY` 활동 `targetId`를 기존 크리에이터 id에서 `creator_community.id`로 변경했다. PRD Feature D와 plan-task Phase 10을 보강했고, RED/GREEN으로 repository 테스트를 갱신했다. 검증으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest.shouldFindOneLatestActivityPerCreatorWithActivityType`, `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest`, `./gradlew ktlintCheck`, `./gradlew tasks --all`을 실행해 모두 `BUILD SUCCESSFUL`을 확인했다. `ktlintCheck`와 `tasks --all`은 sandbox의 `~/.gradle` lock 파일 접근 제한으로 최초 실패해 권한 상승으로 재실행했다.
|
||||
- 2026-06-27: Phase 9 코드 리뷰 및 검증을 진행했다. 변경 범위가 첫 오디오 콘텐츠 native query row 매핑의 Boolean 변환 보정과 운영 회귀 테스트/문서 보강에 한정되어 있는지 확인했고, `isPointAvailable`, `isAdult`, `isOriginalSeries`가 `Boolean` 또는 `Number(0/1)` 모두에서 명시적으로 Boolean으로 변환되는지 점검했다. 리뷰 결과 수정이 필요한 결함은 발견하지 못했다. 검증으로 `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest.shouldMapNumericNativeBooleanFromFirstAudioContentRows`, `./gradlew test --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest`, `./gradlew ktlintCheck`, `./gradlew tasks --all`, `git diff --check`, `git diff --check --cached`, `./gradlew test`를 실행했고 모두 `BUILD SUCCESSFUL` 또는 통과를 확인했다. `ktlintCheck`와 `tasks --all`은 sandbox의 `~/.gradle` lock 파일 접근 제한으로 최초 실패해 권한 상승으로 재실행했다.
|
||||
- 2026-06-23: Phase 8 코드 리뷰 및 검증을 진행했다. 변경 범위가 `creatorId` additive schema 추가에 한정되어 있는지 확인했고, `HomeAiCharacterRecommendationRecord.creatorId` → `HomeAiCharacterItem.creatorId` 매핑, `ChatCharacter.creatorMember` inner join과 활성/CREATOR/AI_CHARACTER 필터, 홈 통합/AI 캐릭터 전체보기 JSON 응답 검증 테스트를 점검했다. 리뷰 결과 수정이 필요한 결함은 발견하지 못했다. 검증으로 `./gradlew test --rerun-tasks --tests kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryServiceTest --tests kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.DefaultHomeRecommendationQueryRepositoryTest --tests kr.co.vividnext.sodalive.v2.api.home.dto.recommendation.HomeRecommendationResponseTest --tests kr.co.vividnext.sodalive.v2.api.home.HomeRecommendationControllerTest`, `./gradlew ktlintCheck`, `./gradlew tasks --all`, `git diff --check`, `./gradlew test`를 실행했고 모두 `BUILD SUCCESSFUL` 또는 통과를 확인했다. `ktlintCheck`와 `tasks --all`은 sandbox의 `~/.gradle` lock 파일 접근 제한으로 최초 실패해 권한 상승으로 재실행했다.
|
||||
|
||||
Reference in New Issue
Block a user