Files
sodalive-backend-spring-boot/docs/20260608_크리에이터_랭킹/prd.md

23 KiB

PRD: 크리에이터 랭킹

1. Overview

지난 주 월요일 00:00:00 KST부터 일요일 23:59:59.999999999 KST까지의 활동 데이터를 기준으로 크리에이터 랭킹 점수를 계산하고, 최종 점수 상위 20명을 조회할 수 있는 기능을 제공한다.


2. Problem

  • 크리에이터의 매출, 콘텐츠 반응, 응원, 팬 충성도를 한 번에 비교할 수 있는 주간 랭킹 기준이 필요하다.
  • 서버 시스템 timezone이 UTC로 동작하더라도 랭킹 산정 기간은 KST 기준 지난 주 월요일부터 일요일까지로 고정되어야 한다.
  • DB와 서버 timezone은 UTC이므로, KST 기준으로 산출한 랭킹 기간을 UTC 조회 조건으로 변환해 원천 데이터를 조회해야 한다.
  • 계산 산식이 여러 도메인 데이터에 걸쳐 있어 조회 API 내부에 직접 구현하면 테스트와 스냅샷 기반 성능 개선이 어려워진다.
  • 동일한 랭킹 산식을 주간 스냅샷 생성, 운영 조회, 캐시 갱신에서 재사용할 수 있도록 계산 책임과 조회 책임을 분리해야 한다.

3. Goals

  • KST 기준 지난 주 월요일부터 일요일까지의 주간 크리에이터 랭킹을 계산한다.
  • 최종 점수 기준 상위 20명의 크리에이터를 조회할 수 있다.
  • 랭킹 계산 산식은 독립된 application/domain 컴포넌트로 분리한다.
  • 계산 기간 산출은 서버 기본 timezone에 의존하지 않고 명시적으로 Asia/Seoul 기준을 사용한다.
  • KST 기준 집계 시작/종료 시각을 UTC 기준 조회 시작/종료 시각으로 변환한 뒤 DB 데이터를 조회한다.
  • 각 점수 카테고리의 원천 지표와 가중치를 테스트 가능한 형태로 관리한다.
  • 조회 시 매번 무거운 원천 집계를 수행하지 않도록 주간 랭킹 계산 결과를 스냅샷으로 저장한다.
  • 추후 성능 개선을 위해 캐시 저장소를 추가할 수 있는 포트 경계를 둔다.

4. Non-Goals

  • 이번 PRD에서는 별도 관리자 화면 신규 개발을 포함하지 않는다. 단, 기존 관리자 영역에서 호출할 수 있는 스냅샷 수동 생성/재시도용 관리자 전용 API는 포함한다.
  • 크리에이터 랭킹 산식의 머신러닝 모델화, 개인화, A/B 테스트는 포함하지 않는다.
  • 실시간 랭킹 또는 현재 주 진행 중 랭킹은 포함하지 않는다. 단, 스냅샷 테이블이 완전히 비어 있는 초기 상태에서만 제한적으로 원천 데이터 fallback 집계를 시도할 수 있다.
  • 기존 공개 API 스키마를 임의 변경하지 않는다.
  • 랭킹 결과 수동 보정 기능은 포함하지 않는다.
  • 점수 산식의 가중치를 관리자에서 동적으로 수정하는 기능은 포함하지 않는다.

5. Target Users

  • 회원: 주간 인기 크리에이터를 탐색하는 사용자
  • 앱 클라이언트: 랭킹 화면에 상위 크리에이터 목록과 순위/순위 변화 정보를 노출하는 클라이언트
  • 운영자: 주간 크리에이터 성과를 확인하고 랭킹 산식의 결과를 검증하는 내부 사용자

6. User Stories

  • 사용자는 지난 주 기준으로 가장 높은 최종 점수를 받은 크리에이터 20명을 보고 싶다.
  • 사용자는 랭킹 순위, 지난 주 대비 순위 변화, 크리에이터 프로필 이미지, 닉네임을 확인하고 싶다.
  • 앱 클라이언트는 홈 내부 랭킹 탭에서 동일한 API 응답으로 랭킹 화면을 구성하고 크리에이터 상세로 이동하고 싶다.
  • 운영자는 특정 크리에이터의 최종 점수가 어떤 카테고리 점수로 구성되었는지 추적할 수 있어야 한다.
  • 개발자는 시스템 timezone이 UTC여도 KST 기준 집계 기간이 흔들리지 않는지 테스트로 확인하고 싶다.

7. Core Features

Feature A. 주간 랭킹 기간 산출

Requirements

  • 랭킹 대상 기간은 조회 시점 기준 "지난 주 월요일 00:00:00 KST 이상, 이번 주 월요일 00:00:00 KST 미만"으로 계산한다.
  • 예를 들어 2026-06-08 월요일 KST에 조회하면 대상 기간은 2026-06-01 00:00:00 KST 이상, 2026-06-08 00:00:00 KST 미만이다.
  • 서버 기본 timezone이 UTC여도 기간 산출은 Asia/Seoul 기준으로 수행한다.
  • DB와 서버 timezone은 UTC이므로, KST 기준 기간을 UTC 기준 Instant 또는 프로젝트 표준 시간 타입으로 변환해 DB 조회 조건에 사용한다.
  • 예를 들어 2026-06-01 00:00:00 KST 이상, 2026-06-08 00:00:00 KST 미만은 2026-05-31 15:00:00 UTC 이상, 2026-06-07 15:00:00 UTC 미만으로 변환해 조회한다.

Edge Cases

  • 월요일 00:00:00 KST 직후 조회해도 방금 시작한 이번 주 데이터가 포함되지 않아야 한다.
  • 연도/월 경계를 넘어가는 주차도 동일한 규칙으로 계산한다.
  • DST가 없는 KST 기준을 사용하되, 구현은 ZoneId.of("Asia/Seoul")처럼 명시적인 timezone을 사용한다.

Feature B. 콘텐츠 + 라이브 점수

Requirements

  • 콘텐츠 + 라이브 점수는 라이브 계열 매출 합산 지표 70%, 콘텐츠 구매 합산 지표 30%로 계산한다.
  • 라이브 계열 매출 합산 지표는 CanUsage.DONATION, CanUsage.LIVE, CanUsage.SPIN_ROULETTE의 사용 캔 합계로 계산한다.
  • 콘텐츠 구매 합산 지표는 CanUsage.ORDER_CONTENT 1종의 사용 캔 합계로 계산한다.
  • 환불된 사용 내역은 점수 계산에서 제외한다.
  • 크리에이터별 기간 내 합계를 원천 지표로 보관하거나 응답 내부 추적이 가능해야 한다.

Edge Cases

  • 라이브 또는 콘텐츠 구매 데이터가 없으면 해당 지표는 0점으로 계산한다.
  • 음수 캔 또는 환불 데이터가 섞여 있으면 기존 UseCan 환불 정책과 동일한 방식으로 제외한다.

Feature C. 참여 반응 점수

Requirements

  • 참여 반응 점수는 콘텐츠 좋아요 수 50%, 콘텐츠 댓글 수 50%로 계산한다.
  • 콘텐츠 좋아요 수는 기간 내 활성 콘텐츠 좋아요 수를 크리에이터별로 합산한다.
  • 콘텐츠 댓글 수는 기간 내 활성 콘텐츠 댓글과 대댓글 수를 크리에이터별로 합산한다.
  • 해당 콘텐츠의 크리에이터가 직접 작성한 댓글과 대댓글은 콘텐츠 댓글 수에서 제외한다.
  • 비활성 콘텐츠, 삭제 또는 비활성 처리된 좋아요/댓글은 기존 도메인 정책에 맞춰 제외한다.

Edge Cases

  • 좋아요 또는 댓글이 없으면 해당 지표는 0점으로 계산한다.
  • 콘텐츠 댓글 수가 없거나 크리에이터 본인 댓글/대댓글만 있으면 댓글 지표는 0점으로 계산한다.

Feature D. 응원 점수

Requirements

  • 응원 점수는 채널 후원 캔 합계 60%, 채널 후원 수 20%, 팬 Talk 수 20%로 계산한다.
  • 채널 후원 캔 합계는 CanUsage.CHANNEL_DONATION의 사용 캔 합계로 계산한다.
  • 채널 후원 수는 CanUsage.CHANNEL_DONATION 사용 건수로 계산한다.
  • 팬 Talk 수는 기존 CreatorCheers의 최상위 등록 수로 계산하고 답글은 포함하지 않는다.
  • 환불된 채널 후원 내역은 점수 계산에서 제외한다.

Edge Cases

  • 채널 후원 또는 팬 Talk 데이터가 없으면 해당 지표는 0점으로 계산한다.
  • 팬 Talk 답글이 별도 row로 저장되어 있어도 팬 Talk 수에 포함하지 않는다.

Feature E. 팬 충성도 점수

Requirements

  • 팬 충성도 점수는 최종 팔로우 수 70%, 팔로우 증가 수 30%로 계산한다.
  • 최종 팔로우 수는 랭킹 대상 기간 종료 시점 기준 활성 팔로우 수를 의미한다.
  • 팔로우 증가 수는 랭킹 대상 기간 동안 활성 팔로우 수가 몇 명 증가했는지를 의미한다.
  • 기본 정의는 기간 내 신규 활성 팔로우 수 - 기간 내 비활성화된 팔로우 수로 한다.
  • 신규 활성 팔로우 수는 CreatorFollowing.createdAt이 랭킹 대상 기간 안에 있는 팔로우만 집계한다.
  • 비활성화된 팔로우 수는 CreatorFollowing.isActive == false이고 CreatorFollowing.updatedAt이 랭킹 대상 기간 안에 있는 팔로우만 집계한다.
  • 과거 언팔로우 후 기간 내 재팔로우한 경우는 createdAt이 과거 시점이므로 신규 증가로 반영하지 않는다.
  • 이번 산식은 현재 creator_following row의 createdAt, updatedAt, isActive 기준으로 계산하며, 한 기간 안에서 여러 번 발생한 팔로우/언팔로우 이벤트 히스토리까지 별도로 복원하지 않는다.
  • 팔로우 증가 수가 음수이면 음수 원천 지표와 음수 카테고리 점수를 허용하고, 최종 점수에 그대로 반영한다.

Edge Cases

  • 기간 내 재팔로우로 다시 활성화된 팔로우는 최종 팔로우 수에는 포함될 수 있지만 팔로우 증가 수의 신규 생성분에는 포함하지 않는다.
  • 기간 내 언팔로우 후 재팔로우해 최종 상태가 활성인 row는 isActive == false 조건에 걸리지 않으므로 비활성화된 팔로우 수에도 포함하지 않는다.

Feature F. 최종 점수 계산 및 정렬

Requirements

  • 최종 점수는 (콘텐츠/라이브 카테고리 점수 * 0.35) + (참여 반응 점수 * 0.30) + (응원 점수 * 0.25) + (팬 충성도 점수 * 0.10)으로 계산한다.
  • 최종 점수 1점 이상인 크리에이터만 랭킹에 포함한다.
  • 최종 점수 내림차순으로 최대 20명을 조회한다.
  • 동점자는 랜덤으로 추출한다.
  • 스냅샷에는 최종 점수 1점 이상인 모든 후보를 저장하지 않고, Top 20 산정에 필요한 후보만 저장한다.
  • Top 20 산정에 필요한 후보는 20위 점수보다 높은 후보와 20위 점수에 동점인 후보 전체를 의미한다.
  • 조회 시 스냅샷에 저장된 후보 중 최종 점수 동점자를 랜덤 정렬해 상위 20명을 추출한다.
  • 동점 랜덤 추출을 위한 별도 randomTieBreaker 값은 스냅샷에 저장하지 않는다.
  • 각 하위 지표는 0~100 정규화하지 않고 원천 값(raw value)을 그대로 사용한다.
  • 캔 단위 지표는 좋아요, 댓글, 팔로우 같은 개수 지표보다 최종 점수에 더 큰 영향을 줄 수 있으며, 이는 의도된 정책이다.

Edge Cases

  • 특정 지표 값이 없으면 해당 원천 값은 0으로 계산한다.
  • 최종 점수가 1점 미만이면 20명이 되지 않아도 응답에서 제외한다.

Feature G. 랭킹 조회 API

Requirements

  • 홈 내부 랭킹 탭에서 주간 크리에이터 랭킹 상위 20명을 조회하는 API를 제공한다.
  • API endpoint는 GET /api/v2/home/rankings/creators를 사용한다.
  • API는 최신 완료 주차의 스냅샷을 기준으로 조회하며 별도 query parameter 없이 기본 랭킹을 반환한다.
  • 응답에는 순위 변화 표시 여부, 순위, 지난 주 대비 순위 변화, 신규 진입 여부, 크리에이터 id, 닉네임, 프로필 이미지를 포함한다.
  • showRankChangeitems와 같은 레벨에 내려주며, 클라이언트가 순위 변화 UI를 표시할지 판단하는 값이다.
  • 각 크리에이터의 순위 변화 값은 items[].rankChange에 숫자로 내려준다.
  • 순위가 올라갔으면 양수, 순위가 내려갔으면 음수로 내려준다.
  • 예를 들어 직전 완료 주차 10위, 최신 완료 주차 5위이면 rankChange5다.
  • 예를 들어 직전 완료 주차 1위, 최신 완료 주차 10위이면 rankChange-9다.
  • 직전 완료 주차에는 순위에 없고 최신 완료 주차에 진입한 크리에이터는 items[].isNew == true로 내려주며, 클라이언트는 이를 New로 표시한다.
  • 신규 진입 크리에이터의 rankChange는 비교 가능한 이전 순위가 없으므로 null로 내려준다.
  • 응답의 크리에이터 id는 크리에이터 상세 이동에 사용한다.
  • 응답 스키마 예시는 다음과 같다.
{
  "showRankChange": true,
  "items": [
    {
      "rank": 1,
      "rankChange": 5,
      "isNew": false,
      "creatorId": 123,
      "nickname": "creator",
      "profileImageUrl": "https://cdn.example.com/profile.png"
    },
    {
      "rank": 2,
      "rankChange": null,
      "isNew": true,
      "creatorId": 456,
      "nickname": "new creator",
      "profileImageUrl": "https://cdn.example.com/profile-new.png"
    }
  ]
}
  • 운영 검증 또는 디버깅이 필요하면 카테고리별 점수와 원천 지표를 내부용 응답 또는 로그로 확인할 수 있어야 한다.
  • 비활성 및 탈퇴 크리에이터는 랭킹에 노출하지 않는다.
  • 조회자와 크리에이터 사이에 차단 관계가 있으면 랭킹 row는 유지하되 응답의 크리에이터 id는 0, 닉네임은 빈 문자열로 내려준다.
  • 차단 관계가 있는 크리에이터의 프로필 이미지는 기본 이미지 URL로 내려주고, 이동 대상 id는 0으로 내려준다.
  • 인증 사용자 조건이 필요하지 않은 공개 조회를 기본으로 하되, 차단 마스킹 정책은 인증 사용자에게 적용한다.
  • 조회 API는 스냅샷 기반 응답을 기본으로 하며, 공개 API 응답 스키마는 fallback 여부와 관계없이 변경하지 않는다.
  • 스냅샷 테이블이 완전히 비어 있는 초기 상태에서만 조회 API가 제한적으로 원천 데이터 fallback 집계를 시도할 수 있다.
  • 스냅샷 테이블에 과거 스냅샷이 하나라도 있으면 원천 데이터 fallback을 시도하지 않고 최신 완료 주차 스냅샷 기준으로 응답한다.
  • 스냅샷 테이블이 완전히 비어 있는 초기 상태에서 fallback 집계가 성공하면, 조회 API는 응답을 반환하면서 스냅샷 생성 책임을 CreatorRankingSnapshotRefreshService/CreatorRankingSnapshotJobService 쪽으로 위임해 같은 기간의 creator_ranking_snapshot 생성을 트리거한다.
  • cold-start fallback에서 스냅샷 생성 트리거는 운영 배포 직후 내부 테스트 등 초기 검증 상황을 위한 보강책이며, 장기 실시간 집계 경로로 사용하지 않는다.
  • cold-start fallback 스냅샷 생성은 동일 집계 기간에 대해 한 번만 실행되도록 기간 기반 Redisson lock을 사용하고, lock 획득 실패 시 다른 요청 또는 작업이 처리 중인 정상 skip으로 간주한다.

Edge Cases

  • 최종 점수 1점 이상인 랭킹 후보가 20명 미만이면 가능한 만큼만 내려준다.
  • 랭킹 계산 결과가 없으면 빈 배열로 성공 응답한다.
  • 최신 완료 주차 스냅샷이 없고 스냅샷 테이블도 완전히 비어 있으면 제한적 원천 데이터 fallback 집계를 시도한 뒤 결과를 응답한다.
  • fallback 성공 뒤 스냅샷 생성 트리거가 실패하더라도 공개 API 응답 스키마는 변경하지 않고, 실패는 로그/job 이력으로 추적한다.
  • 스냅샷 테이블에 과거 스냅샷이 하나라도 있으면 원천 데이터 fallback을 시도하지 않고 기존 최신 완료 주차 스냅샷 기준 응답을 유지한다.
  • 직전 완료 주차 스냅샷이 없으면 showRankChangefalse로 내려주고, 각 item의 rankChangenull, isNewfalse로 내려준다.

Feature H. 주간 랭킹 스냅샷

Requirements

  • 주간 랭킹은 조회 시 매번 원천 데이터를 집계하지 않고, 계산 결과를 스냅샷으로 저장한 뒤 조회 API는 스냅샷을 읽는다.
  • 스냅샷 생성 기준 기간은 KST 기준 지난 주 월요일 00:00:00 이상, 이번 주 월요일 00:00:00 미만이다.
  • 스냅샷 생성 시 원천 데이터 조회 조건은 KST 집계 기간을 UTC로 변환한 기간을 사용한다.
  • 스냅샷 저장 대상은 20위 점수보다 높은 후보와 20위 점수에 동점인 후보 전체로 제한한다.
  • 최종 점수 1점 이상인 후보가 20명 미만이면 해당 후보만 저장한다.
  • 스냅샷은 크리에이터 id, 최종 점수, 카테고리별 점수, 원천 지표, 집계 시작/종료 시각을 저장한다.
  • 최종 순위는 스냅샷 저장 시 고정하지 않고 조회 시 최종 점수 내림차순과 동점 랜덤 정렬 결과에 따라 부여한다.
  • 순위 변화는 최신 완료 주차 응답에서 부여된 순위와 직전 완료 주차 스냅샷 기준 순위를 비교해 계산한다.
  • 동점 랜덤 정렬 정책 때문에 동점 구간에 포함된 크리에이터의 순위와 순위 변화는 조회 결과마다 달라질 수 있으며, 이는 허용한다.
  • 스냅샷 생성은 이번 주 데이터가 포함되지 않도록 주간 집계 대상 기간이 종료된 뒤 실행한다.
  • 기본 스케줄 후보는 매주 월요일 KST 07:30이며, 스케줄러는 Asia/Seoul zone을 명시한다.
  • 다중 서버 인스턴스에서 같은 스케줄이 동시에 실행되더라도 클러스터 전체에서 한 인스턴스만 스냅샷 생성을 수행해야 한다.
  • 클러스터 단일 실행은 신규 DB 테이블을 추가하지 않고, 기존 프로젝트에 설정된 Redisson 기반 분산 lock을 우선 사용한다.
  • 주간 랭킹 스냅샷 lock key는 lock:creator-ranking-snapshot-refresh를 사용하며, lock 획득 실패 인스턴스는 스냅샷 생성을 skip한다.
  • 같은 집계 기간에 대해 스냅샷을 재생성할 수 있어야 하며, 재생성 시 기존 같은 기간 스냅샷을 중복 노출하지 않는다.
  • 조회 API는 최신 완료 주차의 스냅샷을 기준으로 응답한다.
  • 스냅샷 생성 직전 집계 시작/종료 시각을 포함한 job 이력을 생성하고, 작업 완료 후 성공/실패 상태와 처리 결과를 기록한다.
  • 스케줄러로 실행되는 주간 스냅샷 생성도 job 이력으로 기록한다.
  • 운영자는 관리자 전용 API를 통해 날짜 범위를 직접 선택해 스냅샷 생성 job을 생성할 수 있어야 한다.
  • 실패한 스냅샷 생성 job은 관리자 전용 재시도 API로 재시도할 수 있어야 하며, 기존 관리자 job 패턴과 같이 실패 상태 job을 대기 상태로 되돌려 worker가 다시 처리하도록 한다.
  • 관리자 전용 job 목록 API는 날짜 범위, 실행 트리거, 상태, 실패 사유, 재시도 가능 여부를 확인할 수 있어야 한다.
  • cold-start fallback 성공 후 스냅샷 저장은 조회 서비스가 직접 DB에 쓰지 않고, 스냅샷 refresh 책임을 가진 job/service 경계로 위임한다.
  • cold-start fallback 스냅샷 저장 트리거는 집계 기간을 포함한 Redisson lock key를 사용해 동일 기간 중복 생성을 방지한다. 예: lock:creator-ranking-snapshot-refresh:{aggregationStartAtUtc}:{aggregationEndAtUtc}.
  • lock을 획득한 요청만 refresh job/service를 실행하고, lock을 획득하지 못한 요청은 이미 다른 실행자가 처리 중인 것으로 보고 fallback 응답만 반환한다.

Edge Cases

  • 최신 완료 주차 스냅샷이 없고 스냅샷 테이블이 완전히 비어 있으면 제한적 원천 데이터 fallback 집계를 시도하고, fallback 성공/실패를 장애 추적용 로그로 남긴다.
  • fallback 성공 후 스냅샷 저장 트리거는 실패하더라도 조회 응답을 실패시키지 않되, job 상태 또는 구조화 로그로 실패를 추적할 수 있어야 한다.
  • 스냅샷 테이블에 과거 스냅샷이 하나라도 있으면 원천 데이터 fallback을 시도하지 않고 최신 완료 주차 스냅샷 기준 응답을 유지한다.
  • 스냅샷 생성 중 일부 원천 집계가 실패하면 해당 주차 스냅샷 저장을 실패 처리하고 부분 결과를 공개하지 않는다.
  • Redisson lock 획득 실패는 다른 인스턴스가 같은 작업을 수행 중인 정상 skip으로 처리하고, 스냅샷 생성 실패로 집계하지 않는다.
  • 실패 job 재시도 API는 실패 상태 job만 대상으로 하며, 이미 대기/처리 중/성공 상태인 job은 재시도 대상으로 변경하지 않는다.

Feature I. 랭킹 계산 컴포넌트 분리

Requirements

  • 랭킹 계산과 조회는 Controller나 Facade 내부에 직접 구현하지 않고 별도 application/domain 컴포넌트로 분리한다.
  • 크리에이터 랭킹 기능 본체는 추천 기능과 독립된 성격이므로 v2.recommendation가 아니라 별도 kr.co.vividnext.sodalive.v2.ranking 하위 패키지에 작성한다.
  • 예시 컴포넌트는 다음 책임을 갖는다.
    • 기간 계산 정책: KST 기준 지난 주 기간을 산출한다.
    • 점수 정책: 원천 지표의 raw value에 가중치를 적용해 카테고리/최종 점수를 계산한다.
    • 집계 포트: UseCan, 콘텐츠 반응, CreatorCheers, CreatorFollowing 원천 데이터를 조회한다.
    • 스냅샷 생성 서비스: 원천 지표를 집계하고 랭킹 스냅샷을 저장한다.
    • 조회 서비스: 저장된 스냅샷을 상위 20명 ranking 조회 결과로 조립한다.
    • 홈 API 조합 Facade: ranking 조회 결과를 클라이언트 공개 응답 DTO로 변환한다.
  • 추후 캐싱을 추가할 수 있도록 조회 서비스는 스냅샷 조회 포트와 캐시 포트를 분리할 수 있는 경계를 둔다.

Edge Cases

  • 캐시가 추가되더라도 산식 테스트는 캐시와 분리된 순수 정책 테스트로 유지한다.
  • 조회 API는 스냅샷 기반 응답을 기본으로 하며, 스냅샷 테이블이 완전히 비어 있는 초기 상태를 제외하고 원천 데이터 실시간 계산 fallback을 두지 않는다.

8. Technical Constraints

  • Kotlin, Spring Boot 2.7.14, Java 17, Gradle Wrapper 구조를 유지한다.
  • 랭킹 계산, 스냅샷 생성, 스냅샷 조회, 차단 마스킹 등 기능 본체는 kr.co.vividnext.sodalive.v2.ranking 하위에 작성한다.
  • 클라이언트 endpoint는 홈 내부 랭킹 탭에서 호출하므로 /api/v2/home/rankings/creators를 사용한다.
  • 클라이언트 공개 API 표면인 Controller와 API 조합 Facade는 기존 홈 API 관례를 따라 kr.co.vividnext.sodalive.v2.api.home 하위에 작성하고, 크리에이터 랭킹 응답 DTO는 kr.co.vividnext.sodalive.v2.api.home.dto.ranking 하위에 작성한다.
  • 기존 엔티티 후보는 UseCan, CanUsage, AudioContent, AudioContentLike, AudioContentComment, CreatorCheers, CreatorFollowing, Member 등이다.
  • 기존 공개 API 스키마는 변경하지 않는다.
  • 계산 기간은 서버 기본 timezone이 아니라 명시적인 KST 기준으로 산출하고, DB 조회 시에는 UTC 기간으로 변환한다.
  • QueryDSL 또는 native SQL 중 기존 성능/패턴에 맞는 방식을 선택하되, 산식 자체는 테스트 가능한 domain/application 정책으로 분리한다.
  • 주간 랭킹 조회는 스냅샷 기반으로 제공한다.
  • 캐싱은 이번 PRD의 필수 구현은 아니지만, 랭킹 조회 서비스가 캐시 포트를 도입할 수 있는 구조여야 한다.
  • 스냅샷 스케줄러는 기존 Redisson 설정을 재사용해 클러스터 단일 실행을 보장하고, 별도 scheduler lock용 DB 테이블은 추가하지 않는다.

9. Metrics

  • 랭킹 조회 API latency
  • 랭킹 계산 소요 시간
  • 주간 스냅샷 생성 성공/실패 수
  • 주간 스냅샷 생성 지연 시간
  • 스냅샷 job 상태별 수와 실패 job 재시도 수
  • 관리자 수동 생성 job 요청 수와 성공/실패 수
  • 스냅샷 테이블 완전 공백 fallback 시도/성공/실패 수
  • 랭킹 후보 크리에이터 수
  • 최종 점수 1점 미만으로 제외된 크리에이터 수
  • 랭킹 조회 성공/실패 로그 수
  • 캐시 도입 후 cache hit ratio

10. Open Questions

현재 PRD 기준 미결정 항목은 없다.