Files
sodalive-backend-spring-boot/docs/20260529_메인_홈_추천_API/prd.md

23 KiB

PRD: 메인 홈 추천 API

1. Overview

메인 홈에서 여러 추천 섹션을 한 번에 조회하고, 각 섹션의 전체보기/페이징 조회와 일부 사용자 액션을 지원하는 v2 API를 제공한다.


2. Problem

  • 기존 홈/콘텐츠/라이브/AI 캐릭터/커뮤니티/후원 도메인의 데이터가 여러 화면과 API에 흩어져 있어 신규 메인 홈 구성을 한 API 계약으로 제공하기 어렵다.
  • 추천 섹션별 정렬 기준, 점수 산식, 갱신 주기, 노출 필드가 서로 달라 구현 전 명확한 요구사항 문서가 필요하다.
  • 일부 섹션은 일 단위 집계 스냅샷이 필요하고, 일부 섹션은 실시간성 또는 랜덤성이 필요하므로 조회 API와 집계 작업의 책임을 분리해야 한다.
  • kr.co.vividnext.sodalive.v2 외부 코드는 엔티티만 재활용해야 하므로 신규 API/서비스/조회 로직의 패키지 경계를 사전에 확정해야 한다.

3. Goals

  • 메인 홈 추천 섹션을 v2 패키지 하위 신규 코드로 제공한다.
  • 홈 첫 화면에서 필요한 섹션별 기본 개수를 조회할 수 있다.
  • 전체보기 요구가 있는 섹션은 별도 리스트 API로 페이징 조회할 수 있다.
  • 홈 배너는 기존 콘텐츠 홈 배너 데이터를 재활용한다.
  • 점수 기반 섹션은 요구된 산식, 기간, 신규 부스트를 반영한다.
  • 일 1회 갱신 섹션은 KST 매일 06:00에 전날 23:59:59 KST 기준 데이터로 계산된 결과를 사용한다. 서버 스케줄러 cron은 Asia/Seoul zone의 KST 06:00으로 등록한다.
  • 시간 응답은 UTC 기준으로 내려주고 앱에서 표시 포맷과 다국어를 처리한다.
  • 장르 기반 크리에이터 추천을 위해 콘텐츠 조회 이력 기록 방식을 도입한다.
  • 여러 크리에이터를 동시에 팔로우하는 API를 제공한다.

4. Non-Goals

  • 기존 kr.co.vividnext.sodalive.v2 외부의 Controller, Service, Repository 구현 코드를 직접 재사용하지 않는다.
  • 기존 홈 API, 콘텐츠 홈 API, 라이브 API, AI 캐릭터 API의 공개 스키마를 변경하지 않는다.
  • 앱 다국어 문구를 서버에서 번역해 내려주지 않는다.
  • 추천 산식의 머신러닝 모델화, 개인화 가중치 학습, A/B 테스트 플랫폼은 이번 범위에 포함하지 않는다.
  • 관리자 화면 신규 개발은 포함하지 않는다.
  • 추천 결과 수동 편집 기능은 포함하지 않는다.

5. Target Users

  • 회원: 메인 홈에서 라이브, 신규 크리에이터, 콘텐츠, AI 캐릭터, 커뮤니티, 후원 기반 추천을 탐색하는 사용자
  • 비회원: 인증 없이 조회 가능한 추천 섹션을 탐색하는 사용자
  • 앱 클라이언트: 섹션별 노출 정보와 이동 대상 id를 받아 홈 UI와 전체보기 화면을 구성하는 클라이언트

6. User Stories

  • 사용자는 메인 홈 진입 시 라이브 중인 방송 20개를 최신순으로 보고 싶다.
  • 사용자는 홈 배너를 최대 20개까지 정해진 노출 순서대로 보고 싶다.
  • 사용자는 방금 활동한 크리에이터와 활동 영역을 확인하고 해당 콘텐츠/커뮤니티로 이동하고 싶다.
  • 사용자는 최근 데뷔한 크리에이터를 추천 점수순으로 보고 전체 리스트도 확인하고 싶다.
  • 사용자는 신규 크리에이터가 올린 첫 번째 오디오 콘텐츠를 발견하고 전체보기로 더 탐색하고 싶다.
  • 사용자는 AI 캐릭터를 추천 점수순으로 보고 채팅 화면으로 이동하고 싶다.
  • 사용자는 내가 봤던 콘텐츠 장르 또는 랜덤 장르 기준으로 팔로우하지 않은 크리에이터를 추천받고 싶다.
  • 사용자는 장르 추천에서 여러 크리에이터를 한 번에 팔로우하고 싶다.
  • 사용자는 최근 응원이 많은 크리에이터를 순위로 보고 싶다.
  • 사용자는 인기 커뮤니티 게시글을 크리에이터별로 중복 없이 보고 싶다.

7. Core Features

Feature A. 메인 홈 통합 조회

Requirements

  • 신규 홈 API는 kr.co.vividnext.sodalive.v2 하위 패키지에 작성한다.
  • 메인 홈 통합 API URL prefix는 /api/v2/home/recommendations를 사용한다.
  • 홈 첫 화면 응답은 섹션별 기본 limit만 포함한다.
  • 섹션별 기본 노출 수는 다음과 같다.
    • 라이브 중인 방송: 20개
    • 홈 배너: 최대 20개
    • 방금 활동한 크리에이터: 10개
    • 최근 데뷔한 크리에이터: 10개
    • 처음부터 함께 성장: 10개
    • 크리에이터와 이야기를 나눠요: 10개
    • 장르의 크리에이터: 장르 최대 5개, 장르별 크리에이터 8명
    • 최근 응원이 많은 크리에이터: 8명
    • 인기 커뮤니티: 10개
  • 인증 회원이면 팔로우 제외, 콘텐츠 조회 이력, 본인인증 여부 등 사용자 조건을 반영한다.
  • 인증 회원이 차단했거나 인증 회원을 차단한 크리에이터의 라이브, 콘텐츠, 커뮤니티, 크리에이터 추천 데이터는 노출하지 않는다.
  • 비회원이면 회원 의존 조건을 제외한 기본 추천만 제공한다.

Edge Cases

  • 섹션별 데이터가 부족하면 부족한 개수만 내려주고 전체 API는 성공 처리한다.
  • 특정 섹션 집계 스냅샷이 없으면 해당 섹션은 빈 배열로 내려주고 장애가 전체 홈 조회를 막지 않도록 한다.
  • 앱 이동에 필요한 id가 없는 섹션은 이동 대상 필드를 nullable로 둔다.

Feature B. 라이브 중인 방송

Requirements

  • 라이브 중인 방송을 최신순으로 조회한다.
  • 홈 첫 화면은 20개를 내려준다.
  • 전체 리스트 API는 페이징으로 조회할 수 있어야 한다.
  • 노출 정보는 크리에이터 닉네임, 프로필 이미지, 라이브 번호를 포함한다.
  • 기존 LiveRoom, Member 등 엔티티는 재활용할 수 있다.

Edge Cases

  • 방송자가 비활성 회원이면 노출하지 않는다.

Feature C. 홈 배너

Requirements

  • 기존 콘텐츠 홈 배너를 재활용한다.
  • orders 기준으로 최대 20개를 조회한다.
  • 활성 배너만 노출한다.
  • 동일 orders 값이 있으면 랜덤으로 정렬한다.
  • 배너 대상 엔티티가 비활성 처리되었으면 노출하지 않는다. EVENT는 연결 이벤트가 활성인 경우만, CREATOR는 연결 크리에이터 회원이 활성인 경우만, SERIES는 연결 시리즈와 시리즈 소유 회원이 모두 활성인 경우만 노출한다. LINK는 별도 대상 엔티티가 없으므로 배너 자체 활성 상태만 적용한다.
  • 기존 배너 응답에서 앱 이동에 필요한 필드는 유지한다.

Feature D. 방금 활동한 크리에이터

Requirements

  • 최신순 10개를 조회한다.
  • 활동 타입은 enum으로 내려주며 앱에서 다국어 처리한다.
  • 활동 타입 후보는 LIVE, AUDIO, COMMUNITY, LIVE_REPLAY로 한다.
  • 오디오는 콘텐츠를 업로드한 경우를 의미한다.
  • 커뮤니티는 커뮤니티 게시글을 등록한 경우를 의미한다.
  • 라이브는 라이브 진행 후 종료한 경우를 의미한다.
  • 라이브 다시듣기는 콘텐츠 업로드 시 다시듣기 테마로 올린 경우를 의미한다.
  • 노출 정보는 크리에이터 프로필 이미지, 닉네임, 활동 타입, UTC 기반 활동 시간, 이동 대상 id를 포함한다.
  • 라이브 활동은 별도 이동 대상 id가 필요하지 않다.
  • 라이브 외 활동은 오디오/라이브 다시듣기 콘텐츠 id를 내려주며, 커뮤니티 활동은 커뮤니티 게시글 작성자 크리에이터 id를 내려준다.
  • 크리에이터당 최신 활동 1개만 노출한다.

Edge Cases

  • 다시듣기 콘텐츠는 AUDIO가 아니라 LIVE_REPLAY로 분류한다.

Feature E. 최근 데뷔한 크리에이터

Requirements

  • 홈 첫 화면은 추천순 10개를 조회한다.
  • 전체 리스트 API는 페이징으로 조회할 수 있어야 한다.
  • 데뷔일은 콘텐츠를 처음 공개한 날과 라이브를 한 날 중 빠른 날짜로 계산한다.
  • 데뷔일 계산 로직은 기존 ExplorerService.getCreatorDetaildebutDateTime 계산 방식과 동일하게 맞춘다.
  • 데뷔 후 30일 이내 크리에이터만 대상으로 한다.
  • 추천 점수는 ((팔로우 증가량 * 0.35) + (콘텐츠 활동 점수 * 0.3) + (소통 점수 * 0.2)) * 신규 부스트로 계산한다.
  • 팔로우 증가량은 최근 7일간 신규 팔로우한 유저 수로 계산한다.
  • 콘텐츠 활동 점수는 최근 30일간 업로드 콘텐츠 수와 라이브 횟수로 계산한다.
  • 소통 점수는 최근 7일간 커뮤니티 게시글 수, 커뮤니티 게시글 댓글 수, 커뮤니티 게시글 좋아요 수, 콘텐츠 댓글 수, 콘텐츠 좋아요 수로 계산한다.
  • 신규 부스트는 데뷔 후 10일 이내 1.5, 20일 이내 1.3, 30일 이내 1.2를 적용한다.
  • 추천 점수가 동일하면 랜덤으로 정렬한다.
  • 노출 정보는 크리에이터 프로필 이미지, 닉네임을 포함한다.

Feature F. 처음부터 함께 성장

Requirements

  • 신규 크리에이터가 올린 첫 번째 오디오 콘텐츠를 조회한다.
  • 신규 크리에이터는 데뷔일로부터 30일 이내인 크리에이터다.
  • 홈 첫 화면은 최대 10개를 조회한다.
  • 전체보기 API는 신규 크리에이터의 첫 번째 콘텐츠를 페이징 조회할 수 있어야 한다.
  • 첫 번째 콘텐츠 판정은 해당 크리에이터의 오디오 콘텐츠를 created_at, release_date 기준으로 정렬해 3번째 이내에 업로드된 활성 콘텐츠인 경우로 한다.
  • 앞선 비활성 콘텐츠가 2개 있고 3번째 콘텐츠가 활성이라면 첫 번째 콘텐츠로 인정한다.
  • 앞선 비활성 콘텐츠가 3개 이상이면 이후 활성 콘텐츠는 첫 번째 콘텐츠로 인정하지 않는다.
  • 최신성 점수 기준일은 release_date로 본다.
  • 최신성 점수는 3일 이내 100, 7일 이내 80, 14일 이내 60, 21일 이내 40, 30일 이내 20으로 계산한다.
  • 정렬은 최신성 점수 내림차순, 동점이면 랜덤으로 한다.

Edge Cases

  • 예약 공개 콘텐츠는 공개 전에는 노출하지 않는다.

Feature G. 크리에이터와 이야기를 나눠요

Requirements

  • AI 캐릭터 리스트를 조회한다.
  • 홈 첫 화면은 10개를 조회한다.
  • 전체 리스트 API는 페이징으로 조회할 수 있어야 한다.
  • 노출 정보는 캐릭터 이름, 캐릭터 소개, 작품명, 사용자들이 친 전체 채팅 수를 포함한다.
  • 작품명은 오리지널 작품 캐릭터인 경우에만 내려준다.
  • 1차 정렬은 AI 채팅 추천 점수 내림차순이다.
  • 2차 정렬은 동일 점수인 경우 랜덤이다.
  • AI 채팅 추천 점수는 이번 스프린트에서 ((0.45 * 최근 발생한 AI 채팅 수) + (0.35 * 최근 활성 사용자 수)) * 신규 부스트로 계산한다.
  • 최근 발생한 AI 채팅 수와 최근 활성 사용자 수는 최근 7일 데이터 기반으로 계산한다.
  • 최근 발생한 AI 채팅 수는 AI 캐릭터가 발화한 채팅 메시지 수를 의미한다.
  • 최근 활성 사용자 수는 최근 7일 안에 해당 AI 캐릭터와 1회 이상 채팅한 중복 없는 사용자 수를 의미한다.
  • AI 캐릭터의 팔로우 증가량은 팔로우 대상/관계의 정확한 정의가 확정되지 않아 이번 스프린트 산식과 집계에서 제외한다. 추후 AI 캐릭터 팔로우 정의가 확정되면 별도 요구사항으로 재도입한다.
  • 신규 부스트는 캐릭터 생성일 기준 10일 이내 1.5, 20일 이내 1.3, 30일 이내 1.2, 그 외 1을 적용한다.
  • 점수는 KST 매일 06:00에 전날 23:59:59 KST 기준 데이터로 1회 갱신한다. 스케줄러는 Asia/Seoul zone의 KST 06:00 기준으로 실행한다.

Edge Cases

  • 비활성 또는 노출 제한 캐릭터는 제외한다.

Feature H. 장르의 크리에이터

Requirements

  • 사용자가 조회한 장르가 없으면 조회 가능한 장르 중 랜덤 5개를 선별한다.
  • 사용자가 조회한 콘텐츠가 있으면 조회한 콘텐츠들의 장르 중 랜덤 5개를 선별한다.
  • 조회 이력 기반 장르가 5개 미만이면 나머지 조회 가능한 장르 중 랜덤으로 채운다.
  • 각 장르별로 해당 장르의 콘텐츠를 업로드한 크리에이터를 랜덤 8명씩 노출한다.
  • 같은 크리에이터가 서로 다른 조회 시점의 여러 장르 섹션에 노출될 수는 있다.
  • 한 번에 조회되는 5개 장르 안에서는 같은 크리에이터가 중복 노출되지 않아야 한다.
  • 사용자가 팔로우한 크리에이터는 제외한다.
  • 조회하는 사용자가 크리에이터이면 본인은 장르의 크리에이터 추천에서 제외한다.
  • 성인 콘텐츠 장르는 MemberContentPreference.isAdultContentVisible == true인 회원에게만 노출한다.
  • 노출 정보는 크리에이터 프로필 이미지, 닉네임, id를 포함한다.
  • 콘텐츠 조회 데이터는 콘텐츠 상세 진입 시점에 기록한다.

Edge Cases

  • 조회하는 크리에이터 본인만 있는 장르는 후보에서 제외한다.
  • 장르의 크리에이터 8명 중 조회자 본인이 포함되어 있으면 본인을 제외하고 다른 추천 가능한 크리에이터로 채운다.
  • 본인을 제외한 뒤 대체 가능한 크리에이터가 없으면 남은 추천 가능한 크리에이터만 내려준다.
  • 장르별 추천 가능한 크리에이터가 8명 미만이면 가능한 만큼만 내려준다.

Feature I. 여러 크리에이터 동시 팔로우

Requirements

  • 크리에이터 id 리스트를 받아 해당 id의 크리에이터 중 팔로우되어 있지 않은 크리에이터를 모두 팔로우한다.
  • 요청의 creatorIds는 1개 이상 50개 이하만 허용한다.
  • 이미 팔로우한 크리에이터와 본인 크리에이터 id는 실패 사유로 보지 않고 중복 없이 유지한다.
  • 과거 언팔로우로 비활성화된 팔로우 이력이 있으면 신규 이력을 만들지 않고 기존 이력을 다시 활성화한다.
  • 클라이언트 응답은 성공/실패 여부만 제공하고, 신규 팔로우/처리 제외 id 목록은 공개 응답에 포함하지 않는다.
  • 요청 id 중 일부라도 존재하지 않는 id, 크리에이터가 아닌 회원 id 등 유효하지 않은 값이 포함되면 전체 실패로 처리한다.

Edge Cases

  • 이미 팔로우 중인 크리에이터 id와 본인 크리에이터 id는 유효한 id로 보며 실패 사유로 처리하지 않고 서버 내부에서 제외한다.
  • 동일 회원과 동일 크리에이터의 팔로우 이력은 중복 저장하지 않는다.

Feature J. 최근 응원이 많은 크리에이터

Requirements

  • 응원 점수가 높은 크리에이터 8명을 조회한다.
  • 노출 정보는 크리에이터 프로필 이미지, 크리에이터 닉네임을 포함한다.
  • 응원 점수는 ((0.6 * 후원 금액) + (0.3 * 팬 Talk 수) + (0.1 * 후원 수)) * 신규 부스트로 계산한다.
  • 후원 금액과 후원 수는 CanUsage.CHANNEL_DONATION 데이터만 대상으로 계산한다.
  • 팬톡은 기존 CreatorCheers를 의미한다.
  • 점수는 최근 7일 데이터를 기반으로 계산한다.
  • 신규 부스트는 데뷔 후 10일 이내 1.5, 20일 이내 1.3, 30일 이내 1.2, 그 외 1을 적용한다.
  • 신규 부스트의 데뷔일은 Member.createdAt이 아니라 콘텐츠를 처음 공개한 날과 라이브를 한 날 중 빠른 날짜로 계산한다.
  • 점수는 KST 매일 06:00에 전날 23:59:59 KST 기준 데이터로 1회 갱신한다. 스케줄러는 Asia/Seoul zone의 KST 06:00 기준으로 실행한다.

Feature K. 인기 커뮤니티

Requirements

  • 홈 첫 화면은 10개를 조회한다.
  • 노출 정보는 크리에이터 프로필 이미지, 닉네임, UTC 시간, 좋아요 수, 댓글 수, 커뮤니티 내용을 포함한다.
  • 크리에이터당 1개의 커뮤니티 게시글만 노출한다.
  • 비공개 커뮤니티 게시글은 제외한다.
  • 유료 커뮤니티 게시글은 제외한다.
  • 핀으로 고정한 커뮤니티 게시글은 제외한다.
  • 성인 속성을 가진 커뮤니티 게시글은 기존 노출 조건과 동일하게 MemberContentPreference.isAdultContentVisible == true인 회원에게만 노출한다.
  • 동일 점수의 경우 스냅샷 생성 시 저장한 랜덤 tie-breaker 기준으로 노출한다.
  • 커뮤니티 인기 점수는 ((0.5 * 좋아요 수) + (0.5 * 댓글 수) + (0.1 * 팔로우 수)) * 신규 부스트로 계산한다.
  • 점수는 최근 7일 데이터를 기반으로 계산한다.
  • 신규 부스트는 데뷔 후 10일 이내 1.5, 20일 이내 1.3, 30일 이내 1.2, 그 외 1을 적용한다.
  • 신규 부스트의 데뷔일은 Member.createdAt이 아니라 콘텐츠를 처음 공개한 날과 라이브를 한 날 중 빠른 날짜로 계산한다.
  • 점수는 KST 매일 06:00에 전날 23:59:59 KST 기준 데이터로 1회 갱신한다. 스케줄러는 Asia/Seoul zone의 KST 06:00 기준으로 실행한다.

Edge Cases

  • 댓글 불가 게시글도 댓글 수 0으로 점수 계산 대상에 포함한다.

8. Technical Constraints

  • Kotlin, Spring Boot 2.7.14, Java 17, Gradle Wrapper 구조를 유지한다.
  • 신규 구현 코드는 kr.co.vividnext.sodalive.v2 하위에 둔다.
  • 신규 코드는 클라이언트 공개 API 조립 계층과 재사용 가능한 추천 기능 계층을 분리한다.
  • 클라이언트에 공개되는 메인 홈 API 조립 계층은 kr.co.vividnext.sodalive.v2.api.home 하위에 둔다.
  • 홈 API 외부에서도 재사용 가능한 추천, 점수 계산, 노출 정책, 스냅샷, 캐시, 콘텐츠 조회 이력 기능은 kr.co.vividnext.sodalive.v2.recommend 하위에 둔다.
  • 의존 방향은 v2.api.home에서 v2.recommend를 호출하는 방향으로만 둔다. v2.recommendv2.api.home의 DTO나 application service에 의존하지 않는다.
  • v2.api.homev2.recommend 모두 필요한 범위에서 경량 헥사고날 아키텍처를 적용하고, 기본 하위 패키지는 application, domain, port, adapter, dto를 사용한다.
  • Controller는 adapter.in.web, application service/use case는 application, repository/cache/scheduler 구현은 adapter.out.*, application이 외부 조회/저장 구현에 의존하는 계약은 port.out에 둔다.
  • port.in은 여러 adapter에서 같은 use case를 재사용하거나 진입 계약을 명확히 해야 할 때만 둔다.
  • 정책, 점수 계산, 노출 조건, 스냅샷 모델처럼 인프라 의존이 없는 코드는 domain에 둔다.
  • kr.co.vividnext.sodalive.v2 외부 코드는 엔티티만 재활용하고, Controller/Service/Repository/DTO는 신규 작성한다.
  • 기존 엔티티 후보는 Member, LiveRoom, AudioContent, AudioContentBanner, CreatorFollowing, CreatorCommunity, CreatorCommunityLike, CreatorCommunityComment, CreatorCheers, ChannelDonationMessage, AudioContentComment, AudioContentLike, ChatCharacter 등이다.
  • 조회 구현은 복잡도에 맞춰 선택한다. 단순 id 조회, 단건 조회, 명확한 조건 조회는 Spring Data JPA 기본 메서드 또는 @Query를 사용할 수 있고, 동적 조건/집계/서브쿼리/복합 정렬이 필요한 경우 QueryDSL을 우선 사용한다.
  • native SQL은 CTE, window function, union all, DB-side exact scoring, DB별 랜덤 tie-breaker처럼 QueryDSL/JPA 표현이 부자연스럽거나 정확도/성능을 해칠 수 있는 경우에만 사용한다. native SQL을 사용할 때는 RED 단계에서 제외 조건, null aggregate, boundary window, 정렬/limit 순서, Kotlin 정책 산식과의 parity를 촘촘히 검증한다.
  • 홈 추천 조회에는 공통 차단 필터를 적용해 내가 차단했거나 나를 차단한 크리에이터의 데이터를 제외한다.
  • 커뮤니티 게시글 조회에는 비공개 제외, 유료 글 제외, 핀 고정 글 제외, 성인 노출 조건(MemberContentPreference.isAdultContentVisible)을 공통 적용한다.
  • 일 1회 갱신 섹션은 조회 시점마다 무거운 집계를 하지 않도록 집계 테이블 또는 스냅샷 엔티티를 신규로 둔다.
  • 랜덤 정렬이 필요한 섹션은 성능을 고려해 후보군 축소 후 랜덤화하거나 스냅샷 생성 시 랜덤 tie-breaker 값을 저장한다. 단, 일 1회 점수 기반 스냅샷은 아래 candidate pre-limit 금지 규칙을 따른다.
  • 일 1회 갱신 스냅샷은 후보를 application/service 메모리로 모두 불러와 점수를 계산하지 않는다. DB 조회에서 모든 적격 후보의 최종 점수와 랜덤 tie-breaker를 계산한 뒤 score desc, randomTieBreaker asc 기준으로 정렬하고, 그 이후에만 최종 저장 개수 limit을 적용한다.
  • 최종 점수 계산 전 candidate pre-limit, 랜덤 후보 컷오프, 임의 2배수 선제 제한은 정확한 top 후보를 누락할 수 있으므로 금지한다.
  • DB score expression과 Kotlin RecommendationScorePolicy는 동일한 RecommendationScoreSpec의 가중치/부스트 구간 상수를 공유해 산식 drift를 방지한다.
  • 스냅샷 최종 저장 개수는 동점자 랜덤 노출 여지를 확보하기 위해 홈 첫 화면 노출 수의 2배인 AI 캐릭터 최대 20개, 최근 응원이 많은 크리에이터 최대 16개, 인기 커뮤니티 최대 20개로 한다. 단, 이 숫자는 최종 점수 계산과 동점 랜덤 정렬 이후 적용하는 저장 limit이며 candidate pre-limit가 아니다.
  • 공개 시간은 UTC 기준 응답을 원칙으로 한다.
  • 응답 DTO의 enum 값은 앱 다국어 처리를 위해 안정적인 영문 code로 내려준다.
  • 기존 API 스키마는 변경하지 않고 신규 v2 endpoint로 분리한다.

9. Metrics

  • 메인 홈 API 성공률과 응답 시간
  • 섹션별 빈 응답 비율
  • 전체보기 API 조회 수
  • 추천 섹션별 클릭률
  • 장르 추천 크리에이터 동시 팔로우 요청 수와 성공 수
  • 콘텐츠 조회 이력 기록 성공률
  • 일 배치 집계 성공/실패 수
  • 집계 스냅샷 생성 소요 시간

10. Decisions

  • 실제 데뷔일을 계산할 첫 공개 콘텐츠와 첫 라이브가 모두 없는 크리에이터는 Phase 2 스냅샷 후보에서 제외한다.
  • Phase 2 점수 기반 스냅샷은 DB-side exact scoring으로 계산한다. service는 기준 시각 계산과 snapshot replace만 담당하고, 최종 점수 산식/정렬/limit은 repository query에서 처리한다.
  • 조회 구현은 JPA/QueryDSL 우선, native SQL 제한 사용의 하이브리드 전략으로 진행한다. native SQL은 SQL 고급 기능이 필요한 추천/랭킹/스냅샷 산정에 한정하고, 단순 상세 조회와 대상 활성 조건은 가능하면 QueryDSL/JPA 조건으로 표현한다.

  • docs/prd/sample-prd.md
  • docs/agent-guides/작업절차.md
  • docs/agent-guides/문서유지보수.md