docs(ranking): 홈 API 패키지 계획을 갱신한다

This commit is contained in:
2026-06-08 20:45:45 +09:00
parent 31d5e0be0f
commit f9bc0ffe99
2 changed files with 35 additions and 25 deletions

View File

@@ -4,7 +4,7 @@
**Goal:** 홈 내부 랭킹 탭에서 `GET /api/v2/home/rankings/creators`로 KST 기준 지난 주 크리에이터 랭킹 상위 20명을 조회한다.
**Architecture:** 공개 endpoint는 home 하위 URL을 사용하지만 구현 코드는 추천 기능과 분리된 `kr.co.vividnext.sodalive.v2.ranking` 하위에 둔다. 주간 스냅샷 생성 작업이 KST 기간을 UTC DB 조회 조건으로 변환해 원천 데이터를 집계하고, 조회 API는 최신 완료 주차 스냅샷만 읽어 응답을 조립한다.
**Architecture:** 공개 endpoint는 home 하위 URL을 사용하고, 클라이언트 API 표면(Controller, API 조합 Facade, DTO)은 기존 홈 API 관례에 맞춰 `kr.co.vividnext.sodalive.v2.api.home` 하위에 둔다. 랭킹 기능 본체(domain/application/port/persistence/scheduler)는 추천 기능과 분리된 `kr.co.vividnext.sodalive.v2.ranking` 하위에 둔다. 주간 스냅샷 생성 작업이 KST 기간을 UTC DB 조회 조건으로 변환해 원천 데이터를 집계하고, 조회 API는 최신 완료 주차 스냅샷만 읽어 응답을 조립한다.
**Tech Stack:** Kotlin, Spring Boot 2.7.14, Java 17, Spring Data JPA, QueryDSL 또는 native SQL, JUnit 5, Gradle Wrapper
@@ -13,7 +13,8 @@
## 0. 구현 전 확정 사항
- API endpoint: `GET /api/v2/home/rankings/creators`
- 구현 패키지: `kr.co.vividnext.sodalive.v2.ranking`
- 랭킹 기능 본체 패키지: `kr.co.vividnext.sodalive.v2.ranking`
- 홈 공개 API 조립 패키지: `kr.co.vividnext.sodalive.v2.api.home`
- 집계 기간: 조회/스냅샷 생성 시점 기준 KST 지난 주 월요일 00:00:00 이상, 이번 주 월요일 00:00:00 미만
- DB 조회 기간: KST 집계 기간을 UTC 기준 `LocalDateTime` 또는 프로젝트 표준 시간 타입으로 변환한 기간
- 스냅샷 생성 스케줄 후보: 매주 월요일 KST 07:30, `@Scheduled(cron = "0 30 7 * * MON", zone = "Asia/Seoul")`
@@ -46,9 +47,12 @@
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/port/out/CreatorRankingSnapshotPort.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/port/out/CreatorRankingBlockPort.kt`
### 신규 API / scheduler / persistence
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/in/web/CreatorRankingController.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/in/web/CreatorRankingResponse.kt`
### 신규 API 조립 계층
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/adapter/in/web/CreatorRankingController.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeCreatorRankingFacade.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/dto/ranking/CreatorRankingResponse.kt`
### 신규 scheduler / persistence
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/out/scheduler/CreatorRankingSnapshotScheduler.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/out/persistence/CreatorRankingSnapshot.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/out/persistence/CreatorRankingSnapshotRepository.kt`
@@ -67,7 +71,7 @@
- Create: `src/test/kotlin/kr/co/vividnext/sodalive/v2/ranking/application/CreatorRankingQueryServiceTest.kt`
- Create: `src/test/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/out/persistence/DefaultCreatorRankingAggregationRepositoryTest.kt`
- Create: `src/test/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/out/persistence/DefaultCreatorRankingSnapshotRepositoryTest.kt`
- Create: `src/test/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/in/web/CreatorRankingControllerTest.kt`
- Create: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/CreatorRankingControllerTest.kt`
---
@@ -225,7 +229,7 @@
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.ranking.application.CreatorRankingQueryServiceTest`
- GREEN: 최신 스냅샷 후보를 최종 점수 내림차순과 동점 랜덤 정렬로 최대 20명 선정하고, 직전 스냅샷 순위와 비교해 순위 변화를 계산한다.
- REFACTOR: 동점 랜덤으로 인해 같은 동점 구간의 순위 변화가 조회마다 달라질 수 있음을 테스트에서 허용 범위로 표현한다.
- 기대 결과: API 응답에 필요한 `showRankChange`와 item 목록이 application service에서 완성된다.
- 기대 결과: API Facade가 사용할 `showRankChange`와 item 목록이 ranking application service에서 완성된다.
- [ ] **Task 5.2: 차단 관계 마스킹 port 구현**
- Files:
@@ -239,25 +243,27 @@
- REFACTOR: 기본 이미지 URL은 기존 프로젝트 상수/설정이 있으면 재사용하고, 없으면 ranking service 내부 상수로 분리한다.
- 기대 결과: 차단 관계가 있어도 순위 row 수는 유지되고 개인 식별 정보만 가려진다.
### Phase 6: API endpoint DTO
### Phase 6: API endpoint, Facade, DTO
- [ ] **Task 6.1: 랭킹 조회 DTO Controller 추가**
- [ ] **Task 6.1: 랭킹 조회 DTO, 홈 API Facade, Controller 추가**
- Files:
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/in/web/CreatorRankingResponse.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/in/web/CreatorRankingController.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/in/web/CreatorRankingControllerTest.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/dto/ranking/CreatorRankingResponse.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeCreatorRankingFacade.kt`
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/adapter/in/web/CreatorRankingController.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/CreatorRankingControllerTest.kt`
- RED: `GET /api/v2/home/rankings/creators``showRankChange`, `items[].rank`, `rankChange`, `isNew`, `creatorId`, `nickname`, `profileImageUrl`만 반환하고 날짜와 `finalScore`를 반환하지 않는 controller 테스트를 작성한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.ranking.adapter.in.web.CreatorRankingControllerTest`
- GREEN: controller response DTO를 구현하고 `CreatorRankingQueryService`를 호출한다.
- REFACTOR: URLhome 하위지만 코드 패키지`v2.ranking`에 유지한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.CreatorRankingControllerTest`
- GREEN: controller, API Facade, response DTO를 구현하고 Facade가 `CreatorRankingQueryService`를 호출해 홈 API 응답으로 변환한다.
- REFACTOR: URL과 클라이언트 API 표면은 `v2.api.home` 하위에 두고, 랭킹 DTO는 `v2.api.home.dto.ranking` 하위에 둔다. 랭킹 계산/조회 본체`v2.ranking`에 유지한다.
- 기대 결과: 클라이언트 홈 랭킹 탭에서 사용할 공개 API 계약이 테스트로 고정된다.
- [ ] **Task 6.2: 인증/비인증 조회와 차단 마스킹 연결**
- Files:
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/in/web/CreatorRankingController.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/ranking/adapter/in/web/CreatorRankingControllerTest.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/adapter/in/web/CreatorRankingController.kt`
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeCreatorRankingFacade.kt`
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/CreatorRankingControllerTest.kt`
- RED: 비회원 조회는 기본 랭킹을 반환하고, 인증 회원 조회는 차단 관계 마스킹을 적용하는 controller 테스트를 작성한다.
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.ranking.adapter.in.web.CreatorRankingControllerTest`
- 실패 확인: `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.CreatorRankingControllerTest`
- GREEN: 기존 인증 주입 패턴을 확인해 member nullable 흐름을 service에 전달한다.
- REFACTOR: 기존 API 응답 wrapper 관례와 상태 코드를 맞춘다.
- 기대 결과: 인증 여부에 따라 차단 마스킹만 달라지고 endpoint 계약은 동일하다.
@@ -280,15 +286,17 @@
- Files:
- Verify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/ranking/**`
- Verify: `src/test/kotlin/kr/co/vividnext/sodalive/v2/ranking/**`
- Verify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/**`
- Verify: `src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/**`
- Modify: `docs/20260608_크리에이터_랭킹/plan-task.md`
- RED: 테스트 작성 예외. `TDD 예외 사유`: 구현 완료 후 회귀 검증 task다.
- 대체 검증 방법:
- `./gradlew test --tests 'kr.co.vividnext.sodalive.v2.ranking.*'`
- `./gradlew test --tests 'kr.co.vividnext.sodalive.v2.ranking.*' --tests 'kr.co.vividnext.sodalive.v2.api.home.*'`
- `./gradlew ktlintCheck`
- `./gradlew test`
- GREEN: 실패하는 테스트가 있으면 해당 phase task로 돌아가 수정하고, 모든 명령을 통과시킨다.
- REFACTOR: plan-task 하단 검증 기록에 실행 명령, 목적, 결과를 누적한다.
- 기대 결과: ranking 기능 단위 테스트, 포맷, 전체 회귀 테스트가 통과한다.
- 기대 결과: ranking 기능 본체와 홈 API 조립 계층 테스트, 포맷, 전체 회귀 테스트가 통과한다.
---
@@ -300,9 +308,9 @@
- Feature D: Task 1.2, Task 3.3, Task 4.1에서 채널 후원 캔/건수와 최상위 팬 Talk 집계를 검증한다.
- Feature E: Task 1.2, Task 3.4, Task 4.1에서 최종 팔로우 수와 `createdAt`/`updatedAt` 기반 팔로우 증가 수를 검증한다.
- Feature F: Task 1.2, Task 4.1, Task 5.1에서 raw value 최종 점수, 1점 미만 제외, 20위 동점 후보 저장, 동점 랜덤 조회를 검증한다.
- Feature G: Task 5.1, Task 5.2, Task 6.1, Task 6.2에서 API endpoint, 응답 스키마, 순위 변화, 신규 진입, 차단 마스킹을 검증한다.
- Feature G: Task 5.1, Task 5.2에서 ranking 조회 결과와 차단 마스킹을 검증하고, Task 6.1, Task 6.2에서 API endpoint, 응답 스키마, 인증/비인증 연결을 검증한다.
- Feature H: Task 2.1, Task 2.2, Task 4.1, Task 4.2, Task 4.3에서 주간 스냅샷 저장, 스케줄, 클러스터 단일 실행 lock을 검증한다.
- Feature I: 모든 task에서 `v2.ranking` 패키지 경계를 유지하고, Task 6.1에서 endpoint만 home 하위 둔다.
- Feature I: Phase 5의 ranking 기능 본체는 `v2.ranking` 패키지 경계를 유지하고, Phase 6의 클라이언트 API 표면은 `v2.api.home` 하위 둔다.
---