docs(content): 최근 댓글 오디오 중복 저장 정책을 문서화한다
This commit is contained in:
@@ -34,6 +34,7 @@
|
|||||||
- New & Hot 점수: 최신성 35%, 상세 조회수 35%, 좋아요 15%, 댓글 수 15%. 상세 조회수는 `creator_content_view_history`의 `content_id`별 count를 사용한다.
|
- New & Hot 점수: 최신성 35%, 상세 조회수 35%, 좋아요 15%, 댓글 수 15%. 상세 조회수는 `creator_content_view_history`의 `content_id`별 count를 사용한다.
|
||||||
- 추천 오디오 점수: 상세 조회수 45%, 좋아요 25%, 댓글 수 20%, 최신성 10%.
|
- 추천 오디오 점수: 상세 조회수 45%, 좋아요 25%, 댓글 수 20%, 최신성 10%.
|
||||||
- 최근 댓글 많은 오디오 점수: 댓글 수 80%, 댓글 최신성 20%.
|
- 최근 댓글 많은 오디오 점수: 댓글 수 80%, 댓글 최신성 20%.
|
||||||
|
- 최근 댓글 많은 오디오 스냅샷 저장 정책: 같은 크리에이터의 오디오 후보가 여러 개이면 최근 댓글 많은 오디오 점수가 가장 높은 1개만 저장한다.
|
||||||
- 조회수/좋아요/댓글 수는 후보 내 정규화 없이 원본 count를 그대로 사용한다.
|
- 조회수/좋아요/댓글 수는 후보 내 정규화 없이 원본 count를 그대로 사용한다.
|
||||||
- 무료/포인트/추천 오디오 섹션 사이에는 같은 콘텐츠가 중복 노출될 수 있다.
|
- 무료/포인트/추천 오디오 섹션 사이에는 같은 콘텐츠가 중복 노출될 수 있다.
|
||||||
- `isOriginalSeries`는 시리즈 미소속 오디오이면 `false`로 내려준다.
|
- `isOriginalSeries`는 시리즈 미소속 오디오이면 `false`로 내려준다.
|
||||||
@@ -608,9 +609,32 @@ interface AudioRecommendationQueryPort {
|
|||||||
- `git diff --check`: 출력 없음.
|
- `git diff --check`: 출력 없음.
|
||||||
- `./gradlew ktlintCheck`: sandbox 환경에서는 Gradle wrapper lock 파일 접근 제한으로 실패했으나, 승인 후 sandbox 밖에서 재실행해 `BUILD SUCCESSFUL` 확인.
|
- `./gradlew ktlintCheck`: sandbox 환경에서는 Gradle wrapper lock 파일 접근 제한으로 실패했으나, 승인 후 sandbox 밖에서 재실행해 `BUILD SUCCESSFUL` 확인.
|
||||||
|
|
||||||
|
### Phase 9: 최근 댓글 많은 오디오 크리에이터 중복 저장 정책
|
||||||
|
|
||||||
|
- [x] **Task 9.1: 같은 크리에이터의 최근 댓글 많은 오디오 후보는 최고 점수 1개만 저장**
|
||||||
|
- 작성일: 2026-07-12
|
||||||
|
- Files:
|
||||||
|
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationSnapshotRefreshService.kt`
|
||||||
|
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt`
|
||||||
|
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationSnapshotRefreshServiceTest.kt`
|
||||||
|
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt`
|
||||||
|
- RED: 같은 크리에이터의 오디오 2개가 최근 댓글 많은 오디오 스냅샷 후보에 들어올 때, `AudioRecommendationSnapshotRefreshService.replaceMostCommentedSnapshots` 또는 `DefaultAudioRecommendationQueryRepository.findMostCommentedSnapshots` 결과에 더 높은 최근 댓글 많은 오디오 점수의 1개만 남는 repository/service 테스트를 먼저 작성한다.
|
||||||
|
- 실패 확인:
|
||||||
|
- Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationSnapshotRefreshServiceTest`
|
||||||
|
- Run: `./gradlew test --tests kr.co.vividnext.sodalive.v2.content.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest`
|
||||||
|
- GREEN: repository 후보 산정 SQL 또는 service 후보 선택 단계에서 `creatorId`별 최고 점수 후보만 남기고 `RecommendationSnapshotPort.replaceSnapshots(...)`에는 중복 제거가 끝난 후보만 전달한다.
|
||||||
|
- REFACTOR: 점수 동률과 `randomTieBreaker` 정렬 정책이 기존 `score desc`, `randomTieBreaker asc` 규칙을 유지하는지 회귀 테스트로 확인하고, `MOST_COMMENTED_LIMIT` 최대 5개 정책과 SAFE/ALL visibility 조건을 변경하지 않는다.
|
||||||
|
- 기대 결과: `MOST_COMMENTED_AUDIO_SAFE/ALL` 스냅샷에는 같은 크리에이터의 오디오가 최대 1개만 저장되고, 공개 API 응답 스키마는 변경되지 않는다.
|
||||||
|
- 검증 기록: 구현 완료 시 실행 명령, 결과, 실패 시 원인과 수정 내용을 이 task 아래에 한국어로 누적 기록한다.
|
||||||
|
- 2026-07-12 문서화 기록: 이번 변경은 PRD/plan-task 문서만 갱신했으며 source code와 test code는 아직 변경하지 않았다. 따라서 위 RED/GREEN/REFACTOR 구현 task는 미완료 상태로 남긴다.
|
||||||
|
- 2026-07-12 구현 검증 기록:
|
||||||
|
- RED: `./gradlew test --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest.shouldKeepOnlyHighestScoredMostCommentedSnapshotPerCreator'` 실행 결과 `expected: <[2, 3]> but was: <[2, 1, 3]>`로 실패해 같은 크리에이터의 낮은 점수 후보가 함께 반환되는 기존 동작을 확인했다.
|
||||||
|
- GREEN: `DefaultAudioRecommendationQueryRepository.findMostCommentedSnapshots(...)`가 `creatorId`별 `row_number()`로 최고 점수 후보 1개만 남긴 뒤 최종 limit을 적용하도록 수정했다. 같은 명령 재실행 결과 `BUILD SUCCESSFUL`을 확인했다.
|
||||||
|
- 회귀: `./gradlew test --tests kr.co.vividnext.sodalive.v2.content.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest`와 `./gradlew test --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationSnapshotRefreshServiceTest` 모두 `BUILD SUCCESSFUL`로 통과했다.
|
||||||
|
|
||||||
### Phase 8: 회귀 검증과 문서 기록
|
### Phase 8: 회귀 검증과 문서 기록
|
||||||
|
|
||||||
- [ ] **Task 8.1: 전체 관련 테스트와 ktlint 실행**
|
- [x] **Task 8.1: 전체 관련 테스트와 ktlint 실행**
|
||||||
- Files:
|
- Files:
|
||||||
- Verify: `docs/20260623_메인_콘텐츠_추천_탭_API/prd.md`
|
- Verify: `docs/20260623_메인_콘텐츠_추천_탭_API/prd.md`
|
||||||
- Verify: `docs/20260623_메인_콘텐츠_추천_탭_API/plan-task.md`
|
- Verify: `docs/20260623_메인_콘텐츠_추천_탭_API/plan-task.md`
|
||||||
@@ -623,8 +647,14 @@ interface AudioRecommendationQueryPort {
|
|||||||
- Run: `./gradlew ktlintCheck`
|
- Run: `./gradlew ktlintCheck`
|
||||||
- 기대 결과: 모든 관련 테스트와 ktlint가 `BUILD SUCCESSFUL`이다.
|
- 기대 결과: 모든 관련 테스트와 ktlint가 `BUILD SUCCESSFUL`이다.
|
||||||
- 검증 기록: 구현 완료 시 실행 명령, 결과, 실패 시 원인과 수정 내용을 이 task 아래에 한국어로 누적 기록한다.
|
- 검증 기록: 구현 완료 시 실행 명령, 결과, 실패 시 원인과 수정 내용을 이 task 아래에 한국어로 누적 기록한다.
|
||||||
|
- 2026-07-12 Phase 9 이후 검증 기록:
|
||||||
|
- `./gradlew test --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.*'`: `BUILD SUCCESSFUL`.
|
||||||
|
- `./gradlew test --tests 'kr.co.vividnext.sodalive.v2.api.content.recommendation.*'`: `BUILD SUCCESSFUL`.
|
||||||
|
- `./gradlew test --tests kr.co.vividnext.sodalive.v2.api.home.dto.recommendation.HomeRecommendationResponseTest`: `BUILD SUCCESSFUL`.
|
||||||
|
- `./gradlew test --tests kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceServiceTest`: `BUILD SUCCESSFUL`.
|
||||||
|
- `./gradlew ktlintCheck`: `BUILD SUCCESSFUL`.
|
||||||
|
|
||||||
- [ ] **Task 8.2: 문서/스키마 영향 최종 확인**
|
- [x] **Task 8.2: 문서/스키마 영향 최종 확인**
|
||||||
- Files:
|
- Files:
|
||||||
- Verify: `docs/20260623_메인_콘텐츠_추천_탭_API/prd.md`
|
- Verify: `docs/20260623_메인_콘텐츠_추천_탭_API/prd.md`
|
||||||
- Verify: `docs/20260623_메인_콘텐츠_추천_탭_API/plan-task.md`
|
- Verify: `docs/20260623_메인_콘텐츠_추천_탭_API/plan-task.md`
|
||||||
@@ -638,6 +668,12 @@ interface AudioRecommendationQueryPort {
|
|||||||
- Run: `./gradlew tasks --all`
|
- Run: `./gradlew tasks --all`
|
||||||
- 기대 결과: 공개 API endpoint와 응답 필드명이 문서/코드/테스트에서 일치하고, 신규 DB 테이블 DDL이 필요하지 않으며, 코드의 최종 패키지 구조가 `content.recommendation` 기준이고, v2 성인 콘텐츠 조회 정책 계산 경로가 service 메서드로 통일됐음이 확인된다.
|
- 기대 결과: 공개 API endpoint와 응답 필드명이 문서/코드/테스트에서 일치하고, 신규 DB 테이블 DDL이 필요하지 않으며, 코드의 최종 패키지 구조가 `content.recommendation` 기준이고, v2 성인 콘텐츠 조회 정책 계산 경로가 service 메서드로 통일됐음이 확인된다.
|
||||||
- 검증 기록: 구현 완료 시 문서와 코드 검색 결과를 이 task 아래에 한국어로 누적 기록한다.
|
- 검증 기록: 구현 완료 시 문서와 코드 검색 결과를 이 task 아래에 한국어로 누적 기록한다.
|
||||||
|
- 2026-07-12 Phase 9 이후 검증 기록:
|
||||||
|
- `rg -n "GET /api/v2/audio/recommendations|AudioRecommendationsResponse|NEW_AND_HOT_AUDIO_SAFE|RECOMMENDED_AUDIO_ALL" docs src/main/kotlin src/test/kotlin`로 endpoint, DTO, section enum 참조가 문서/코드/테스트에 남아 있음을 확인했다.
|
||||||
|
- `rg -n "api\.audio\.recommendation|v2\.audio\.recommendation|api/audio/recommendation|v2/audio/recommendation" src/main/kotlin src/test/kotlin`로 production/test의 최종 추천 API 패키지가 `content.recommendation` 기준임을 확인했다.
|
||||||
|
- `rg -n "isAdultVisibleByPolicy|getStoredPreference\([^\n]*\)\.isAdult" src/main/kotlin/kr/co/vividnext/sodalive/v2 src/test/kotlin/kr/co/vividnext/sodalive/v2` 실행 결과 출력 없음으로 v2 경로의 구 성인 콘텐츠 정책 직접 사용이 없음을 확인했다.
|
||||||
|
- `rg -n "isAdultVisibleByPolicy|resolveCountryCodeByPolicy" src/main/kotlin src/test/kotlin` 실행 결과 기존 비-v2 콘텐츠/테스트 경로의 레거시 사용만 남아 있음을 확인했다.
|
||||||
|
- `./gradlew tasks --all`: `BUILD SUCCESSFUL`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -682,3 +718,6 @@ interface AudioRecommendationQueryPort {
|
|||||||
- 2026-06-25 후속 보정: `DefaultAudioRecommendationQueryRepositoryTest.shouldFindNewAndHotSnapshotsWithVisibility`의 score 비교 실패 원인은 repository native SQL의 `timestampdiff(day, c.release_date, :snapshotAt)` 최신성 계산이 DB 날짜 경계 기준에 의존해 `AudioRecommendationScorePolicy`의 24시간 경과 기준 `ChronoUnit.DAYS` 계산과 어긋날 수 있는 점으로 확인했다. `DefaultAudioRecommendationQueryRepository`의 New & Hot/추천 오디오 공개일 최신성 계산을 `floor(timestampdiff(hour, c.release_date, :snapshotAt) / 24)`로 변경해 Kotlin 정책과 일치시켰고, `SAFE` 성인 콘텐츠 제외 조건은 기존 `(:includeAdult = true or c.is_adult = false)` 구현이 올바른 것으로 확인했다. 검증은 `./gradlew test --rerun-tasks --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest.shouldFindNewAndHotSnapshotsWithVisibility'`, `./gradlew test --rerun-tasks --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioRecommendationScorePolicyTest'`, `./gradlew ktlintCheck` 모두 `BUILD SUCCESSFUL`로 완료했다.
|
- 2026-06-25 후속 보정: `DefaultAudioRecommendationQueryRepositoryTest.shouldFindNewAndHotSnapshotsWithVisibility`의 score 비교 실패 원인은 repository native SQL의 `timestampdiff(day, c.release_date, :snapshotAt)` 최신성 계산이 DB 날짜 경계 기준에 의존해 `AudioRecommendationScorePolicy`의 24시간 경과 기준 `ChronoUnit.DAYS` 계산과 어긋날 수 있는 점으로 확인했다. `DefaultAudioRecommendationQueryRepository`의 New & Hot/추천 오디오 공개일 최신성 계산을 `floor(timestampdiff(hour, c.release_date, :snapshotAt) / 24)`로 변경해 Kotlin 정책과 일치시켰고, `SAFE` 성인 콘텐츠 제외 조건은 기존 `(:includeAdult = true or c.is_adult = false)` 구현이 올바른 것으로 확인했다. 검증은 `./gradlew test --rerun-tasks --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.adapter.out.persistence.DefaultAudioRecommendationQueryRepositoryTest.shouldFindNewAndHotSnapshotsWithVisibility'`, `./gradlew test --rerun-tasks --tests 'kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioRecommendationScorePolicyTest'`, `./gradlew ktlintCheck` 모두 `BUILD SUCCESSFUL`로 완료했다.
|
||||||
- 2026-07-12 후속 정책 변경: 콘텐츠 추천 탭의 `latestAudios`, `freeAudios`, `pointAudios` 기본 노출 수를 각각 15개로 확정했다. PRD/plan-task의 섹션별 기본 노출 수와 관련 task 설명을 15개 정책으로 갱신했고, service 테스트는 `AudioRecommendationQueryService` 상수 기준으로 limit 전달을 검증하도록 정리했다. 검증은 `./gradlew --no-daemon test --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationQueryServiceTest`, `./gradlew --no-daemon ktlintCheck`, `./gradlew --no-daemon tasks --all` 모두 `BUILD SUCCESSFUL`로 완료했다. 단, `tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 파일 접근 제한으로 실패해 승인 후 재실행했다.
|
- 2026-07-12 후속 정책 변경: 콘텐츠 추천 탭의 `latestAudios`, `freeAudios`, `pointAudios` 기본 노출 수를 각각 15개로 확정했다. PRD/plan-task의 섹션별 기본 노출 수와 관련 task 설명을 15개 정책으로 갱신했고, service 테스트는 `AudioRecommendationQueryService` 상수 기준으로 limit 전달을 검증하도록 정리했다. 검증은 `./gradlew --no-daemon test --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationQueryServiceTest`, `./gradlew --no-daemon ktlintCheck`, `./gradlew --no-daemon tasks --all` 모두 `BUILD SUCCESSFUL`로 완료했다. 단, `tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 파일 접근 제한으로 실패해 승인 후 재실행했다.
|
||||||
- 2026-07-12 후속 정책 변경: 콘텐츠 추천 탭의 `recommendedAudios`와 `RECOMMENDED_AUDIO_SAFE/ALL` 스냅샷 후보 저장 수를 최대 20개로 확정했다. PRD의 섹션별 기본 노출 수와 추천 오디오 요구사항, plan-task의 개요와 Task 4.3 후보 산정 설명을 20개 정책으로 갱신했다. 해당 개수는 정책값으로 이후 변경될 수 있으므로 테스트는 `assertEquals(20, RECOMMENDED_AUDIO_LIMIT)`처럼 숫자 자체를 고정하지 않고, 기존 service/refresh 테스트에서 `RECOMMENDED_AUDIO_LIMIT`가 snapshot 조회와 후보 산정 port 호출에 전달되는 흐름을 검증하는 방식으로 유지했다. 검증은 이전 개수 정책 문구 잔존 검색 결과 없음, `./gradlew --no-daemon test --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationQueryServiceTest --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationSnapshotRefreshServiceTest` `BUILD SUCCESSFUL`, `git diff --check` 출력 없음, `./gradlew --no-daemon tasks --all` `BUILD SUCCESSFUL`로 완료했다. 단, `tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 파일 접근 제한으로 실패해 승인 후 재실행했다.
|
- 2026-07-12 후속 정책 변경: 콘텐츠 추천 탭의 `recommendedAudios`와 `RECOMMENDED_AUDIO_SAFE/ALL` 스냅샷 후보 저장 수를 최대 20개로 확정했다. PRD의 섹션별 기본 노출 수와 추천 오디오 요구사항, plan-task의 개요와 Task 4.3 후보 산정 설명을 20개 정책으로 갱신했다. 해당 개수는 정책값으로 이후 변경될 수 있으므로 테스트는 `assertEquals(20, RECOMMENDED_AUDIO_LIMIT)`처럼 숫자 자체를 고정하지 않고, 기존 service/refresh 테스트에서 `RECOMMENDED_AUDIO_LIMIT`가 snapshot 조회와 후보 산정 port 호출에 전달되는 흐름을 검증하는 방식으로 유지했다. 검증은 이전 개수 정책 문구 잔존 검색 결과 없음, `./gradlew --no-daemon test --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationQueryServiceTest --tests kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationSnapshotRefreshServiceTest` `BUILD SUCCESSFUL`, `git diff --check` 출력 없음, `./gradlew --no-daemon tasks --all` `BUILD SUCCESSFUL`로 완료했다. 단, `tasks --all`은 일반 sandbox에서 `~/.gradle` wrapper lock 파일 접근 제한으로 실패해 승인 후 재실행했다.
|
||||||
|
- 2026-07-12 문서 전용 후속 정책 기록: `mostCommentedAudios` 스냅샷 저장 시 같은 크리에이터의 오디오 후보는 최근 댓글 많은 오디오 점수가 가장 높은 1개만 저장하도록 PRD Feature H와 조회 정책, plan-task 확정 정책과 Phase 9 후속 구현 task를 갱신했다. 이번 작업은 문서만 작성했으므로 source code와 test code는 변경하지 않았고, 관련 RED/GREEN/REFACTOR 구현은 Task 9.1 미완료 상태로 남겼다.
|
||||||
|
|
||||||
|
- 2026-07-12 Phase 9 선행 구현 및 Phase 8 회귀 검증: 최근 댓글 많은 오디오 스냅샷 후보에서 같은 크리에이터의 여러 오디오 중 최고 점수 1개만 남기도록 repository dedupe를 구현했다. RED에서 같은 크리에이터 낮은 점수 후보가 함께 반환되는 실패를 확인했고, GREEN 후 Phase 9 focused test, Phase 8 관련 test/ktlint/tasks 검증이 모두 `BUILD SUCCESSFUL`로 통과했다.
|
||||||
|
|||||||
@@ -146,6 +146,7 @@
|
|||||||
- 최근 7일 댓글 데이터를 기반으로 최종 점수를 산출한다.
|
- 최근 7일 댓글 데이터를 기반으로 최종 점수를 산출한다.
|
||||||
- 데이터가 없으면 섹션을 표시하지 않도록 빈 배열로 내려준다.
|
- 데이터가 없으면 섹션을 표시하지 않도록 빈 배열로 내려준다.
|
||||||
- 최대 5개를 표시한다.
|
- 최대 5개를 표시한다.
|
||||||
|
- 스냅샷 저장 후보에 같은 크리에이터의 오디오가 여러 개 있으면 최근 댓글 많은 오디오 점수가 가장 높은 1개만 저장한다.
|
||||||
- 오디오별 가장 최신 댓글 1개의 본문과 글쓴이 프로필 이미지를 함께 내려준다.
|
- 오디오별 가장 최신 댓글 1개의 본문과 글쓴이 프로필 이미지를 함께 내려준다.
|
||||||
|
|
||||||
#### Edge Cases
|
#### Edge Cases
|
||||||
@@ -285,6 +286,7 @@ data class CommentedAudioResponse(
|
|||||||
- New & Hot lazy 보강은 스냅샷 row가 없을 때 Redis marker 기준 KST 날짜별 1회만 시도하고, 보강 후 후보가 0개인 정상 상황에서는 같은 날짜의 다음 조회가 전체 refresh를 반복하지 않는다.
|
- New & Hot lazy 보강은 스냅샷 row가 없을 때 Redis marker 기준 KST 날짜별 1회만 시도하고, 보강 후 후보가 0개인 정상 상황에서는 같은 날짜의 다음 조회가 전체 refresh를 반복하지 않는다.
|
||||||
- 공통 오디오 카드 응답의 `isOriginalSeries`는 시리즈 미소속 오디오이면 클라이언트 편의를 위해 `false`로 내려준다.
|
- 공통 오디오 카드 응답의 `isOriginalSeries`는 시리즈 미소속 오디오이면 클라이언트 편의를 위해 `false`로 내려준다.
|
||||||
- 무료/포인트/추천 오디오처럼 서로 다른 추천 섹션에 같은 콘텐츠가 동시에 포함되어도 서버에서 중복 제거하지 않는다.
|
- 무료/포인트/추천 오디오처럼 서로 다른 추천 섹션에 같은 콘텐츠가 동시에 포함되어도 서버에서 중복 제거하지 않는다.
|
||||||
|
- `mostCommentedAudios` 스냅샷 저장은 같은 크리에이터의 오디오를 최대 1개만 포함한다. 같은 크리에이터 후보가 여러 개이면 `findMostCommentedSnapshots`의 최근 댓글 많은 오디오 점수가 가장 높은 후보를 남기고, `AudioRecommendationSnapshotRefreshService.replaceMostCommentedSnapshots`는 그 결과만 저장한다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user