Appearance
[서버] 캐릭터 관계 레벨 시스템 PRD
Backlog grooming 단계의 산출물. 무엇을 만들지·왜 만들지·핵심 비즈니스 룰을 정의한다. 화면별 디테일(컴포넌트·상태·인터랙션)은 spec.md로.
Status: draft Created: 2026-05-13 Last updated: 2026-05-22 (DM/Soul 정책 반영: Episode Character 임시 적립·Soul 이관·개인화 선톡 source·노출 surface 정렬)
본 PRD의 성공 정의: "완성된 관계 경험" 아님. 추적 가능한 관계 이벤트 데이터 자산 + DM 캐릭터 상세/에피소드 상세 Episode Character 정보 섹션 최소 노출까지. 감정 가중치·관계 효과·정교한 톤 변화 같은 sharp한 경험은 후속 PRD가 이 데이터 위에 올린다. Linear Issue: DEE-71 [앱] 캐릭터 관계 레벨 시스템Author: agent (momo) 시스템/표면: 서버 foundation + 앱/웹 노출 surface(DM 캐릭터 상세, 에피소드 캐릭터 정보)
0. 요약
- 유저가 에피소드에서 Episode Character가 등장하는 씬을 생성하거나, DM에서 Soul 응답/개인화 선톡을 받는 등 star가 차감되는 Soul 상호작용이 성공하면 Bond Exp가 쌓인다. 대전제는
delta_exp = consumed_star이며, 멀티 Episode Character scene은 등장 Episode Character 수로 균등 분배한다. - 이 Exp를 Soul과 연결된 관계에서만
관계 Lv.N+ 진행바로 최소 노출한다. 노출 surface는 DM 캐릭터 프로필 상세와 에피소드 상세의 Episode Character 정보 섹션 두 곳이며, Exp 숫자 자체는 유저에게 직접 노출하지 않는다. - 본 PRD의 핵심은 예쁜 관계 경험을 완성하는 것이 아니라, 나중에 DM 선톡·톤 변화·잠금해제·관계 효과 같은 기능이 쓸 수 있는 raw 이벤트 데이터 자산을 만드는 것이다.
- 그래서 (user, Soul) 총합 Exp만 저장하는 형태는 금지.
source / delta / timestamp가 있는 이벤트 로그를 진실원천(source of truth) 으로 남기는 게 핵심. 감사·분석·운영 안정성을 위해 어떤 상호작용에서 어떤 Exp가 발생했는지 추적 가능해야 한다.
1. 목표 및 배경
1.1 문제
- 사용자 정의 (segment): 캐릭터 중심 콘텐츠 소비를 하는 모든 플레이어 + DM/관계형 기능을 만들려는 제품팀.
- 상황 (when, where): 플레이어가 한 캐릭터를 반복적으로 만나거나, DM에서 자주 대화함에도 그 누적이 어디에도 반영되지 않는 상황.
- 불편 / 미충족 needs: 캐릭터-유저 유대 관계가 데이터로 존재하지 않아 (1) 플레이어가 "내가 이 캐릭터와 얼마나 가까운지" 시각적으로 확인할 수 없고, (2) DM 선톡·톤 변화·잠금해제 같은 후속 기능을 깔 데이터 기반이 없다.
1.2 근거
- 이니셔티브 방향: "캐릭터 관계/메신저 경험 기반 구축". 본 PRD는 그 안의 사전작업 — 후속 관계형 기능들이 올라설 raw 데이터·최소 노출을 깐다.
- 인접 grilling: 2026-05-13 모모 grilling에서 DM 메신저(DEE-72)와 에피소드 상세 캐릭터 섹션(DEE-66/79) ship 결정. 두 기능 모두 "이 캐릭터와 얼마나 가까운가"의 데이터 표현을 요구.
- DM 검증 속도 우선: DM(DEE-72) 시장 검증을 빠르게 돌리는 것이 상위 우선순위. 유대 체계는 DM 발 끌지 않게 MVP 수준으로 단순·기능적으로 가져가되, 데이터는 후속 튜닝이 가능하게 남긴다.
- 현재 우회: 디렉터들이 캐릭터 정보를 미리보기 이미지에 텍스트로 박는 식으로 우회 중 (DEE-66 Background) — 관계 표현 자리 자체가 없음.
1.3 아이디어 (해결 방향)
유저-Soul 누적 상호작용을 이벤트 단위 raw 기록(source, delta, timestamp 포함) 으로 적재하고, 그 합산으로 관계 Lv.N과 진행바를 산출해 노출한다. Episode Character 상호작용은 linked Soul로 귀속하며, Soul 미연결 상태에서는 Episode Character side에 임시 적립 후 연결/패치 시점에 1회 이관한다. Bond Exp 숫자 자체는 유저에게 노출하지 않는다.
- 옵션 1 (채택): 이벤트 로그 + 파생 총합 Bond Exp + 관계 레벨 노출. 구현·이해 단순. 후속 기능은 raw 이벤트/Exp를 직접 참조할 수 있고, 감사·분석·운영 확인이 가능.
- 옵션 2 (기각): 의미 가중치(긍정/부정/감정 톤)로 계산하는 복합 점수. MVP 가설·튜닝 비용 과다 + DM 시장검증 속도 저하.
- 옵션 3 (기각): 총합 Exp 정수만 저장(이벤트 로그 X). 사후 정책 튜닝 시 재계산 불가 → foundation의 확장성 요구에 위배.
- 옵션 4 (기각): 단계만 노출 (숫자 X). 노출 정책 자체는 옵션 1 안에서 결정 (본 PRD는
관계 Lv.N+ 진행바만 노출, Exp 숫자는 비노출).
채택 근거: foundation 단계는 추적 가능한 관계 데이터 자산을 정확히 쌓는 게 1차 목표. raw 이벤트가 남아 있어야 운영 중 적재 누락·이상치·source mix를 감사/분석할 수 있고, 후속 기능도 같은 진실원천을 안정적으로 참조할 수 있다. 노출은 동기 부여 + 후속 기능 신뢰도 빌딩용으로 최소 표면만.
1.4 가설 (직접 검증은 후속 PRD)
본 PRD는 foundation 성격이라 가설 1·2는 후속 PRD(DM 선톡, DEE-66 ship 후 재진입 분석 등) 시점에 검증. 본 PRD는 데이터 자산이 정확히 쌓이는 것까지 책임진다.
- 플레이어는 누적된 유대가 시각적으로 보이면 같은 캐릭터의 다른 에피소드/DM으로 재진입할 동기를 갖는다 → DEE-66 ship 후 측정 가능.
- 유대 데이터가 존재하면 DM 선톡·톤 변화·잠금해제 같은 후속 기능이 ship 가능해진다 → 각 후속 PRD에서 enablement 확인.
1.5 성공 지표
| 지표 | 현재 | 목표 | 측정 방법 |
|---|---|---|---|
| Bond Exp 적재 손실률 | n/a | 허용 손실률 ≤ 정책 임계 (정책·임계 spec에서 확정) | 카운트 소스 이벤트 대비 Exp 증가 트랜잭션 비율 |
| 단계 분포 합리성 | n/a | 분포가 §3-1 곡선 의도와 ±X% 이내 일치 (헤비 cap-hit 유저 기준 Lv.100 ≈ 6.5개월, Lv.200 ≈ 2.2년) | 단계별 (user, Soul) 쌍 분포 모니터링 |
- 메인 지표: Bond Exp 적재 손실률 (정책 임계 안에서 손실).
- UI 노출 surface의 진입률·이탈률은 DEE-66/79(에피소드 상세 캐릭터 섹션) 지표로 본다. 본 PRD의 핵심 분석은 DB에 쌓인 Bond Exp/Level 기준.
2. 타깃 사용자
2.1 주요 사용자
- 캐릭터를 중심으로 콘텐츠를 즐기는 플레이어 (특정 캐릭터가 등장하는 에피소드를 반복 플레이하거나 DM 대화를 즐기는 사용자).
- 빈도: 에피소드 상세 진입 시마다 자연스럽게 노출. 별도 진입 경로 없음.
2.2 핵심 시나리오
- 플레이어가 Episode Character A가 등장하는 에피소드 3편을 클리어한 후, 같은 Soul에 연결된 Episode Character가 등장하는 다른 에피소드 상세에 들어가
관계 Lv.2+ 다음 단계까지의 진척바를 본다. - 플레이어가 DM에서 Soul B와 충분히 대화한 후, 에피소드 상세에서 진척바가 다음 단계 가까이 가 있는 걸 본다.
- 후속 PRD(DM 선톡 등)에서 Bond Exp/Bond Level을 조건으로 기능을 분기시킨다 (본 PRD 범위 외, foundation 사용 예시).
3. 핵심 기능 요구사항
3-1. 클라이언트 (앱)
유대 표시 (DM 캐릭터 상세 + 에피소드 상세 캐릭터 정보 섹션)
- 주요 동작: DM 캐릭터 프로필 상세(DEE-72)와 에피소드 상세의 Episode Character 정보 섹션(DEE-66/79)에서, 대상 Episode Character/Soul이 linked Soul 조건을 만족할 때 유대 상태를 노출한다.
- 표시 요소:
- 단계 라벨 (
관계 Lv.N— 단계명 카피 동반 여부는 §7) - 진척바 (현 단계 시작 → 다음 단계 진입까지 비율)
- Bond Exp 숫자는 직접 노출하지 않는다. (디버그/어드민용만)
- 단계 라벨 (
- 비즈니스 룰:
- 유대는 (user, Soul) 쌍 단위, 글로벌. 같은 Soul에 여러 Episode Character가 연결될 수 있으며, Episode Character 출연 이벤트는 linked Soul에 귀속한다.
- 노출 조건: 로그인 사용자 + linked Soul + Bond 기능/데이터 사용 가능 조건에서만 관계 Lv/progress를 노출한다. 에피소드 상세의 Episode Character 정보 섹션은 기존 DM Thread 존재를 요구하지 않는다. linked Soul이 없거나 비로그인 상태이면 관계 UI를 숨긴다.
- Bond Level/진척바는 누적 Bond Exp에서 매번 파생 (저장하지 않음). 곡선이 바뀌면 표시값이 자동 재계산.
- 노출 위치: (1) DM 캐릭터 프로필 상세, (2) 에피소드 상세 Episode Character 정보 섹션. 다른 표면(MY/홈/캐릭터 카드 등) 확장은 §7.
Ship 순서: 본 PRD는 데이터 적재 + 컴포넌트만 정의. UI가 실제 유저에게 노출되려면 DEE-66 (에피소드 상세 캐릭터 섹션)이 함께 ship 되어야 한다 (의존성 표 참조). 본 PRD 단독 ship 시에는 데이터만 쌓이고 노출은 없는 상태가 될 수 있음.
Bond Exp 누적 (count source)
Bond Exp가 증가하는 소스. episode_scene_appearance, dm_response_generated, personalized_proactive_message_received는 source/event record로 분리 저장하고, 표시용 Bond Exp/Level은 (user, Soul) 기준으로 aggregate한다. Episode Character source는 linked Soul에 귀속하되, Soul 미연결 상태에서는 Episode Character side에 임시 적립 후 연결/패치 시점에 Soul로 1회 이관한다.
공통 단가 공식 (확정):
delta_exp = consumed_star(멀티 Episode Character scene은 등장 Episode Character 수로 균등 분배 후 적용). 즉 해당 상호작용에서 실제로 소비된 star 양 자체가 그대로 Exp가 된다. 소수 Exp 허용 — Exp는 유저에게 직접 노출하지 않으므로 별도 반올림/표시 정책 불필요.consumed_star = 0이면delta_exp = 0.free/paid·프로모/보너스 생성 구분 없음: 무료/보너스 생성이라도 실제로 star 소비가 기록되면 그 소비량 기준으로 Exp가 발생한다. star 소비 자체가 0이면 Exp도 0. 개인화 선톡도 유저 측 수신 성공 시 star가 차감되면 동일 원칙으로 Bond Exp 적립 대상이다.
소스 A — 에피소드 씬 등장(Scene Appearance)
- 정의: 생성된 에피소드의 한 scene에서 Episode Character가 등장하거나 발화함. 해당 source_ref(예: scene_id) 안에서 scene당 Episode Character당 1회로 카운트 — 같은 Episode Character가 한 scene 안에서 여러 번 발화해도 1회 entry.
- Exp 단가: 고정값 아님. 그 scene 생성에서 실제 소비된 star를 등장 Episode Character 수로 균등 분배한 값.
- 멀티 Episode Character scene 정책: 한 scene에 여러 Episode Character가 등장하면
scene_consumed_star / 등장 Episode Character 수를 각 Episode Character의 allocated consumed star로 보고, 각 Episode Character별delta_exp = allocated_consumed_star를 적립한다. 같은 scene 내 동일 Episode Character의 중복 발화는 추가 적립하지 않는다.
소스 B — DM 응답 생성(DM Response)
- 정의: DM Thread에서 Soul 응답이 성공적으로 1회 생성될 때마다 1회로 카운트. 응답이 여러 말풍선으로 분할되더라도 1회.
- Exp 단가: 고정값 아님. 그 응답 생성에서 실제 소비된 star 값 그대로.
소스 C — 개인화 선톡 수신(Personalized Proactive Message)
- 정의: 유저가 개인화 선톡을 유저 측 수신 성공 상태로 받은 경우. 전체 발송/무료 선톡처럼 star 차감이 없는 메시지는
consumed_star = 0이므로 Bond Exp도 0. - Exp 단가: 고정값 아님. 수신 성공 시 실제 차감된 star 값 그대로.
- 정의: 유저가 개인화 선톡을 유저 측 수신 성공 상태로 받은 경우. 전체 발송/무료 선톡처럼 star 차감이 없는 메시지는
첫 출시 정책 (확정): 단가는
consumed_star자체(멀티 Episode Character scene만 등장 Episode Character 수로 균등 분배). 첫 출시는 §3-1 일일 cap만 적용하고, 추가 diminishing·소스간 balancing은 포함하지 않는다. 이벤트 로그는 감사·분석·운영 안정성을 위해 raw delta·source·source_ref·timestamp를 보존한다.
단계 곡선 (확정 — 공식 기반)
공식:
required_exp_for_level(N) = 300 × (N − 1)²(N ≥ 1, Lv.1 임계 = 0).레벨 산출:
total_bond_exp >= required_exp_for_level(N)을 만족하는 가장 큰 N.Max level (첫 출시):
max_level = 200.진행바: 현재 레벨 임계 → 다음 레벨 임계 구간 비율. Lv.200 도달 후에도 Bond Exp는 계속 누적되지만, 유저 노출 레벨은 200으로 고정한다.
설계 근거: Exp 적립 단위를
consumed_star기준으로 확정하면서, 기존 성장 체감 속도를 유지하기 위해 곡선 계수와 일일 cap을 함께 스케일했다. 일일 cap 15,000 Exp를 매일 채우는 헤비 유저 기준 Lv.100 도달 ≈ 6.5개월, Lv.200 도달 ≈ 2.2년. 초기 레벨은 빠르게 오르고 후반은 의도적으로 여러 달~수년에 걸쳐서만 도달 가능.주요 레벨 도달 필요 누적 Exp / 소요일:
Level 필요한 누적 Bond Exp Max 기준(15,000 Exp/day) 평균 기준 Lv.1 0 0일 0일 Lv.2 300 1일 300 ÷ avg_daily_credited_expLv.3 1,200 1일 1,200 ÷ avg_daily_credited_expLv.10 24,300 2일 24,300 ÷ avg_daily_credited_expLv.50 720,300 49일 720,300 ÷ avg_daily_credited_expLv.100 2,940,300 197일 2,940,300 ÷ avg_daily_credited_exp평균 기준 소요일은 출시/분석 기준
avg_daily_credited_exp확정 후 산출한다. 현재 PRD 확정값으로 바로 계산 가능한 기준은 일일 cap max(15,000 Exp/day)다.
일일 cap (확정): (user, Soul, day) 1일 최대 15,000 Bond Exp credited. 하루 기준은 KST 오전 6시 reset (
06:00:00~익일 05:59:59). raw 이벤트 자체는 cap 초과분도 이벤트 로그에 그대로 남기되, credit 되는delta_exp는 일일 누적이 15,000을 넘지 않도록 절단/부분 적립 (cap 경계의 이벤트는 부분 credit, 이후는 0 credit). 정확한 적재 형태(별도 flag / 부분 credit 컬럼 등)는 spec.- 설계 근거:
consumed_star기준 적립에서도 기존 성장 속도 의도를 유지하려면 15,000 Exp/일 cap이 필요하다. D0 scene 생성 q3 ≈ 52건/일 데이터 기준, 15,000 Exp/일 cap은 정상~상위 D0 활동을 막지 않고 극단 outlier만 통제하는 수준.
- 설계 근거:
데이터 모델 (확장성 요구):
- 이벤트 로그 우선: (event_id, user_id, soul_id, source_type, source_ref, consumed_star, delta_exp, credited_delta_exp, occurred_at, server_received_at, linked_episode_character_id?) 단위로 적재. source_type =
episode_scene_appearance/dm_response_generated/personalized_proactive_message_received/migration_backfill/ (향후 추가). source_ref는 episode_id+scene_id 또는 dm_response_id 같은 원본 추적 키. rawdelta_exp는consumed_star기준(멀티 Episode Character scene은 균등 분배값) 그대로 저장,credited_delta_exp는 일일 cap을 반영한 실제 가산분. - 총합 Exp는 파생/캐시: (user, Soul) 총합 Bond Exp(
total_exp)는 조회 성능을 위해 캐시할 수 있으나 이벤트 로그가 진실원천. 정책(곡선·가중치·cap)이 바뀌면 이벤트 로그에서 재집계해 캐시 갱신. - 불투명 단일 총합만 저장하는 형태는 금지. 후속 정책 튜닝 시 재계산 불가 → foundation 목적 위배.
- 이벤트 로그 우선: (event_id, user_id, soul_id, source_type, source_ref, consumed_star, delta_exp, credited_delta_exp, occurred_at, server_received_at, linked_episode_character_id?) 단위로 적재. source_type =
누적 룰:
- 트랜잭션: scene 생성 성공 후 / DM 응답 생성 성공 후 / 개인화 선톡 유저 측 수신 성공 후 동기 적재 (해당 트랜잭션의
consumed_star확정 이후). 실패 시 retry. 최종 실패 시 손실로 집계되어 §1.5 메인 지표(허용 손실률)로 관측. 사용자에게 노출되는 동작은 없다. - 같은 (user, Soul, scene_id, linked_episode_character_id?) 또는 (user, Soul, dm_response_id) 또는 (user, Soul, proactive_message_delivery_id)는 중복 방지 키로 이중 적재 방지.
- 일일 cap을 초과하는 credited delta는 0 또는 부분 credit으로 절단 (raw 이벤트는 보존).
- 트랜잭션: scene 생성 성공 후 / DM 응답 생성 성공 후 / 개인화 선톡 유저 측 수신 성공 후 동기 적재 (해당 트랜잭션의
3-2. 어드민
본 PRD 범위 어드민 화면 없음 (§3-5 Out of scope). 운영 incident 발생 시 DB 직접 조정.
3-3. 딥링크 / URL 구조
신규 path 없음. 노출 surface는 기존 /episode/:episodeId 안의 캐릭터 섹션.
3-4. Scope
포함 (In scope)
- (user, Soul) Bond 이벤트 로그 + 파생 총합 Bond Exp 데이터 모델·적재 파이프라인 (source/ref/consumed_star/timestamp 포함, 사후 재계산 가능 형태).
- 에피소드 scene 등장 → scene consumed star를 등장 Episode Character 수로 균등 분배한
allocated_consumed_star를 Bond Exp로 적재 (scene·Episode Character당 1 entry, 같은 scene 내 동일 Episode Character 중복 발화는 1회로 절단). - DM 응답 생성 →
consumed_star를 Bond Exp로 적재 (응답당 1회, 말풍선 분할 무관). - 개인화 선톡 유저 측 수신 성공 → star가 차감된 경우
consumed_star를 Bond Exp로 적재. - 일일 cap 15,000 Bond Exp / (user, Soul, day) — credit 절단, raw 로그는 보존.
- 단계 곡선 공식
300 × (N − 1)², max_level = 200. - DM 캐릭터 프로필 상세 + 에피소드 상세 Episode Character 정보 섹션 내 유대 표시 (
관계 Lv.N+ 진척바) — linked Soul 조건 충족 시에만. - 기존 유저 대상 과거 scene·DM 생성 이력 기반 migration/backfill (§ Migration 참조).
- Soul 미연결 Episode Character side Exp의 Soul 연결 후 1회 이관 정책.
제외 (Out of scope)
- DM 내 효과: 선톡, 톤 변화, 잠금해제 (각 후속 PRD).
- 다른 surface 노출: MY 탭, 캐릭터 카드, 홈 등.
- 어드민 수동 조정 화면.
- 추가 가중치·Exp 감소·만료·diminishing 룰 (이벤트 로그 보존으로 사후 도입 가능).
- 감정/톤 분석 기반 점수 산출 (sentiment weighting).
- DM 메모리/컨텍스트가 유대에 미치는 효과 (DEE-115 범위).
- 통계·랭킹·소셜 비교 (친구의 유대 노출 등).
- 캐릭터 정보 섹션 자체의 UI/정보 구조 (= DEE-66/79의 PRD 범위).
4. 에러 처리 및 예외 상황
| 상황 | 처리 방향 |
|---|---|
| 비로그인 상태에서 에피소드 상세 진입 | 관계 UI 숨김 |
| Bond Exp 적재 이벤트 실패 (네트워크/서버 오류) | 서버 트랜잭션 retry → 최종 실패는 손실로 집계, §1.5 메인 지표로 관측. 사용자 노출 없음 |
| 단계 곡선 공식 변경 (배포 후) | 누적 Bond Exp는 그대로, 표시 단계만 자동 재계산 |
| Episode Character가 에피소드에서 제거되거나 비공개 | linked Soul의 누적 Bond Exp는 보존. 해당 Episode Character 노출 surface가 사라질 뿐 |
| 같은 Episode Character가 한 scene에서 여러 번 발화 | scene·Episode Character당 1회로 절단 (중복 방지 키) |
| DM 응답 1건이 여러 말풍선으로 분할 | 응답 1건 = 1회로 절단 |
| 일일 cap(15,000) 초과 | credited delta를 0 또는 부분 credit으로 절단, raw 이벤트는 로그에 남김 |
| 한 scene에 여러 Episode Character 등장 | scene consumed star를 등장 Episode Character 수로 균등 분배한 뒤, 각 Episode Character별 allocated_consumed_star 적립 |
consumed_star = 0 (무료/보너스 생성에서 실제 star 차감 0) | delta_exp = 0. 이벤트 entry는 남길 수도, 생략할 수도 — spec |
| Lv.200 도달 후 추가 Exp | Bond Exp는 계속 누적하되, 유저 노출 레벨은 200으로 고정 |
| Episode Character ↔ Soul 연결 적용 | Studio draft/자동 저장 단계는 영향 없음. [적용] 성공 후 active connection으로 취급하되, Episode Character side Exp의 Soul 이관은 유저 컨텍스트 기반 데이터 패치/리드 시점에 1회 수행. 이관 후 Episode Character side exp reset, rollback 없음 |
| user 또는 Soul 삭제 | Bond 레코드도 함께 정리 — 세부 cascade 정책은 spec |
5. 데이터 분석
본 PRD는 DB에 적재된 이벤트 로그 + 파생 총합 Bond Exp를 진실원천으로 한다. 별도 클라이언트 로깅 이벤트는 본 PRD에서 추가하지 않는다 (필요 시 후속 PRD에서). 아래 모든 지표는 DB에서 직접 도출.
5.1 핵심 지표
- Bond Exp 적재 손실률 (§1.5 메인) — 카운트 소스(scene 생성 / DM 응답 생성) 이벤트 대비 Bond Exp 적재 트랜잭션 비율.
- Bond Level 분포 — 단계별 (user, Soul) 쌍 수. max_level = 200 기준 분포, 곡선 의도(대다수 저레벨)와의 fit.
- 레벨 도달 시간 — (user, Soul)별 Lv.N → Lv.N+1 진입까지 걸린 일수, 누적 Lv.100 / Lv.200 도달 시간 분포.
- 일별 획득 Bond Exp 분포 — (user, Soul) day별 credited delta 합 분포. 일일 cap(15,000) 도달 빈도.
- 소스 mix — Bond Exp 누적의 source_type 비율 (
episode_scene_appearancevsdm_response_generatedvspersonalized_proactive_message_receivedvsmigration_backfill). - Cap-hit rate — 일일 cap 15,000에 도달한 (user, Soul, day) 비율.
- Stalled level — 일정 기간 같은 레벨에 머무는 (user, Soul) 비율 (곡선 후반부 의도 검증).
- Migration validation — backfill 후 총 Exp / 레벨 분포 합리성, 상위 유저·캐릭터 spot check, source_type별 카운트 매칭.
- Outlier monitoring — 비정상적으로 빠른 레벨 진입, 단일 (user, Soul, day) raw delta 폭주, abuse 패턴 알람.
5.2 로깅 이벤트
본 PRD에서는 별도 신규 클라이언트 로깅 이벤트를 추가하지 않는다. 모든 분석은 DB(이벤트 로그 테이블 + 캐시 테이블) 기준. 클라이언트 노출 측 funnel은 DEE-66 (에피소드 상세 캐릭터 섹션) PRD의 책임.
6. Ubiquitous Language
| Term | Korean | Definition | Do Not Confuse With | Primary Domain | 상태 |
|---|---|---|---|---|---|
| Soul | 소울 | Studio의 Soul Management에서 디렉터가 만들고 운영하는 DM 가능한 지속 인격체. DM Thread, 선톡, Bond, DM 메모리/프롬프트의 기준 entity. 하나 이상의 Episode Character와 연결될 수 있다. | 에피소드 내 등장 인물 Episode Character | DM / Studio | 신규 |
| Episode Character | 에피소드 캐릭터 | 에피소드 콘텐츠와 플레이에 등장하는 episode-local 인물. 씬 등장·에피소드 상세 섹션·출연 정보의 기준 entity. Soul과 연결되면 Bond 적립/노출이 (user, Soul)로 귀속된다. Soul 미연결 상태에서는 Episode Character side에 임시 Exp가 쌓일 수 있다. | Soul(위), 유저 프로필 | Episode Content | 기존 |
| Bond | 유대 / 관계 | (user, Soul) 쌍의 관계 상태를 표현하는 상위 도메인 entity. 이벤트 로그 기반으로 누적되는 Bond Exp를 원천값으로 가지며, 유저 노출용 Bond Level은 Bond Exp에서 파생된다. 유저에게는 "유대" / "관계 Lv.N"으로 노출. | 캐릭터 일반 평판·작품 인기도 | Bond (신규 도메인) | 신규 |
| Bond Exp | 유대 Exp | Bond의 raw 누적 카운트. 소수 허용, 단조 증가. delta_exp = consumed_star(멀티 Episode Character scene은 균등 분배값). (user, Soul, day) 일일 credit cap 15,000. 유저에게는 숫자로 직접 노출하지 않는다. | 일반 경험치(없음), Credit/star 자체 | Bond | 신규 |
| Bond Level | 유대 단계 (관계 Lv.N) | Bond Exp에 공식 300 × (N − 1)²을 적용해 얻은 단계 라벨. 저장하지 않고 파생. max_level = 200. 유저 노출 표기는 관계 Lv.N. | Bond Exp 자체 | Bond | 신규 |
| Bond Source Event | 관계 적립 이벤트 | Bond Exp를 부여하는 카운트 가능한 이벤트. source: (A) 에피소드 scene 등장 — scene·Episode Character당 1 entry, 멀티 Episode Character scene은 scene consumed star를 등장 Episode Character 수로 균등 분배. (B) DM 응답 생성 — 응답당 1회. (C) 개인화 선톡 수신 성공 — star 차감이 발생한 경우. Exp 단가는 각 event의 consumed_star. | 일반적 "언급" / 단순 발화 횟수 / 고정 단가 | Play / DM | 신규 |
7. Open Questions
- [ ] 유저 노출 한국어 네이밍 최종 확정 — "유대", "관계 Lv.N", 진척바 라벨 등 카피의 최종 표기. PRD 단계 작업 가정값은
관계 Lv.N+ "유대". — PM + 카피. - [ ] 단계 라벨 카피 동반 여부 —
관계 Lv.N만 쓸지, 의미 있는 단계명(예: 낯선 사이 → 친한 사이)을 함께 노출할지. 동반한다면 카피는 spec/카피 단계에서. — PM. - [ ] 다른 surface 노출 후속 결정 — MY 탭(내 유대 톱), 캐릭터 카드, 홈 추천 등. 본 PRD 범위 외지만 본 PRD ship 직전 후속 PRD 큐 점검. — PM + 디자이너.
- [ ] 모니터링/운영 임계 — §1.5 메인 지표 허용 손실률 임계 + 가드레일 회귀 폭, cap-hit rate / stalled level / outlier 알람 임계. 베이스라인 수치는 출시 직전. — PM + 엔지니어.
부록: 메타 정보
Required artifacts
- [x] BE implementation handoff (
needs-be-handoff) — 본 PRD의 §3-1 정책을 기준으로 구현. 세부 hook 위치, 중복 방지 키, cap 집계 테이블/뷰, Episode Character side Exp 이관, backfill 실행 방식, DB cascade 정책은 백엔드 구현 설계에서 확정. - [x] Design (
needs-design) — Figma:관계 Lv.N라벨 + 진척바 컴포넌트 + 빈/저레벨 상태. DEE-66 캐릭터 섹션에 통합. - [ ] QA scenarios (
needs-qa-scenarios) — Sprint planning에서 작성. - [x] Migration plan (
needs-migration) — 신규 이벤트 로그 테이블 + (user, Soul, total_exp, last_event_at) 캐시 테이블 + (user, Soul, day) 일일 cap 집계 테이블/뷰. 기존 유저 backfill 포함: 과거 episode scene 생성·DM 응답 생성 이력에서 (a) Episode Character ↔ Soul 매핑과consumed_star가 복원 가능한 경우 원래 source_type/source_ref로 이벤트 로그 entry 생성, (b) source_ref까지는 복원 불가하지만 (user, Soul) 단위로 누적 star가 복원 가능한 경우migration_backfillsource_type의 집계 entry로 적재 (occurred_at = backfill 시점 또는 기간 대표값, backfill 메타데이터 포함). Episode Character id 재발행 정책: 새 id 발급 이후 신규 play/generation부터 새 id 기준으로 적립하며, 과거 play를 재트리거해도 새 id에 소급 적립하지 않는다. Soul 미연결 기간에 Episode Character side에 쌓인 Exp는 Soul 연결 후 유저 컨텍스트 기반 데이터 패치/리드 시점에 1회 Soul로 이관하고, 이관 후 Episode Character side exp는 reset한다. Backfill 후 §5 migration validation 지표로 총 Exp / 레벨 분포 및 상위 유저·캐릭터 spot check. - [ ] Tracking events (
needs-tracking) — 본 PRD는 신규 클라이언트 로깅 이벤트 없음. 모든 분석은 DB 기준 (§5).
Size & Risks
- Size: M
- Confidence: medium
- 추정 근거: 신규 테이블 1~2개 + 이벤트 3 소스 hook + 노출 surface 2곳 연동 + 기존 유저 backfill/이관 1회성 작업. 단계 곡선 공식·단가 공식·cap·멀티 Episode Character 균등 분배 정책이 확정되어 구현 자체는 단순.
주요 위험 요소
| 위험 | 영향 | 대응 |
|---|---|---|
| scene·DM 응답 hook 누락 또는 중복 적재 | 적재 손실 / 단계 분포 왜곡 | 중복 방지 키 + retry. ship 후 1~2주 모니터링하며 곡선·cap 튜닝 (raw 이벤트 로그 보존으로 재집계 가능). |
| 후속 기능이 Bond Level에 강결합 | 곡선 튜닝 비용 ↑ | 후속 기능은 raw Bond Exp 임계값 또는 이벤트 로그로 분기. Bond Level은 UI 노출 전용. |
| 총합 Bond Exp만 저장된 채 ship → 사후 정책 튜닝 시 재계산 불가 | foundation 목적 실패 (데이터 리셋 필요) | 이벤트 로그를 진실원천으로 박는 §3-1 데이터 모델 룰을 spec/구현에서 어겨선 안 됨. spec 리뷰 게이트. |
의존성
- DEE-66 / DEE-79 (에피소드 상세 캐릭터 정보 섹션): 본 PRD의 UI 노출 surface 중 하나. linked Soul 조건에서 관계 Lv/progress 노출 룰을 함께 반영해야 함. design merge point 협의 필요.
- DEE-72 (DM 메신저): 카운트 소스 B 및 DM 캐릭터 프로필 상세 노출 surface 제공자. DM ship 전에도 소스 A 단독으로 본 PRD ship 가능. DM ship 시 소스 B 및 개인화 선톡 source 연동.
- DEE-115 (DM 메모리/컨텍스트): 유대 데이터를 컨텍스트로 참조할 가능성이 높은 후속 PRD. 본 PRD는 이벤트 로그·총합 Bond Exp를 read API로 제공할 수 있는 형태로 적재 (스키마는 spec/구현 단계 확정).
References
- Frontia UL wiki:
wiki/foundation/ubiquitous-language.md— Character, Episode, Scene, Play 정의 - Linear:
- DEE-66 / DEE-79 [앱/웹] 에피소드 상세 페이지 내 캐릭터 정보 섹션 — 노출 surface
- DEE-72 [앱] DM 메신저 기능 — 카운트 소스 B
- DEE-115 [앱] DM 메모리/컨텍스트 — 유대 데이터를 컨텍스트로 참조할 후속 PRD
prd-review 보기
Review log
2026-05-13 (auto-review, agent 단독 적용)
prd-writer 직후 prd-review 1회. momo 부재 상황이라 메인 agent가 low-risk·obvious 정리만 적용, 진짜 product decision은 §7 OQ로 남김.
채택 (PRD 본문 갱신)
- Q: 메인 지표 "적재율 100%"가 가설 검증 지표가 아니다 + 100%는 단일 PRD 도달 불가
- A: 메인 지표를 적재 손실률 ≤ 정책 임계로 정정. 가설 1·2는 foundation 성격상 후속 PRD에서 검증한다고 §1.4에 명시.
- → §1.4 가설 헤더 변경, §1.5 표·메인 지표 문장 교체.
- Q: 가설 1 검증은 노출 surface 의존(DEE-66) — ship 순서 불명
- A: §3-1에 "본 PRD 단독 ship 시 데이터만 쌓이고 노출 안 됨" 문장 + 부록 의존성에 명시.
- → §3-1, 부록 의존성.
- Q: 백엔드/시스템 §3-3은 API/저장소 설계라 PRD 범위 아님
- A: §3-3 삭제. "단계 라벨/진척바 파생" 같은 비즈니스 룰만 §3-1로 흡수.
- → §3-3 제거, §3-1 비즈니스 룰에 흡수.
- Q: Negative spec 다수 ("어드민 화면 없음", "외부 시스템 연동 없음", "다른 팀 없음" 등)
- A: §3-5 Out of scope로 통폐합. §3-2는 한 줄로 축소. 부록 의존성의 "없음" 라인 제거.
- → §3-1, §3-2, §3-5, 부록.
- Q: §🔍 검토 필요 / 🚨 / ⚠️ / ❓ 4개 메타 섹션이 §7 OQ와 중복
- A: 모두 §7 OQ로 통합 + owner 필드로 외부 agent 호출 흡수. §🔍 섹션 전체 삭제.
- → §7로 통합, 섹션 삭제.
- Q: 부록 "진행 패턴 Spec → Design"은 SKILL 정의 메타
- A: 삭제.
- → 부록 Required artifacts.
- Q: §7 OQ 중 단계명 카피(디자인/카피), retention 법무, 어드민 운영 의례는 PRD 단계 OQ 아님
- A: 단계명 카피는 "단계 라벨 카피 동반 여부"로 PRD 단계 의사결정 1줄만 남김(spec에서 카피 확정). retention·어드민 OQ 삭제.
- → §7.
- Q: §1.5 가드레일 임계·베이스라인 placeholder
- A: §7에 "허용 손실률 임계 + 가드레일 회귀 폭" OQ로 추가, 책임자 명시. 본문은 임계만 결정·수치는 출시 직전 채움 정책 명시.
- → §1.5, §7.
- Q: §5.2 로깅 이벤트 그룹·재사용 판단을 spec으로 미룸
- A: event-docs.frontia.dev는 Cloudflare Access로 sprint-prep 세션에서 fetch 불가. 노트에 그 사실 명시 + §7에 momo 세션 확인 OQ 추가. 멘션·메시지 이벤트 자체는 "기존 재사용 가정"으로 표에서 빠짐.
- → §5.2 노트, §7.
- Q: 메인 지표 단위가 engagement·후속 ship 가능성이라는 가설과 불일치
- A: 가설은 foundation 특성상 본 PRD 직접 검증 X로 §1.4 헤더에 명시. 메인 지표는 데이터 품질(적재 손실률)에 한정하는 것이 일관됨.
- → §1.4, §1.5.
Skip
- (없음 — momo 부재라 product decision은 모두 §7 OQ로 보존)
진짜 product decision으로 §7에 보존된 항목
- 단계 곡선 함수 (선형/지수/수동, 단계 수)
- 멘션 카운트 단위 (frame/scene/turn/episode 클리어당 N)
- DM 메시지 단가 1:1 적정성
- 단계 라벨 카피 동반 여부
- 다른 surface 노출 후속 결정
- 적재 손실률 임계 + 가드레일 회귀 폭
- 로깅 이벤트 재사용 매핑 (Cloudflare Access 세션 필요)
momo 인라인 피드백 (criteria 후보)
- (없음 — agent 단독 세션. criteria.md 갱신 보류, momo walk-through 시 재논의 권장.)
2026-05-15 (PM direction pass, agent 적용)
momo의 PM direction 메모를 기준으로 PRD 정합성 재검토. 핵심: DM 검증 속도 우선 + 친밀도는 단순/MVP + 데이터는 확장 가능하게. "완성된 관계 경험"이 아니라 재튜닝 가능한 관계 데이터 자산 + 최소 노출이 본 PRD의 성공 정의임을 명시.
채택 (PRD 본문 갱신)
- Q: PRD 성공 정의가 모호 — "데이터 자산 + 최소 노출" vs "완성된 관계 경험"
- A: 상단 메타에 박스 추가: "완성된 관계 경험 아님. 재튜닝 가능한 관계 데이터 자산 + 에피소드 상세 1곳 최소 노출까지."
- → 상단 status 블록 직후.
- Q: 데이터 모델이 "raw XP 단일 숫자"로 기술되어, 후속 정책 튜닝 시 재계산 불가 위험 → foundation의 확장성 요구 위배
- A: §1.3에 옵션 1 정의 재정의(이벤트 로그 + 파생 총합 XP), 옵션 3(총합만 저장) 신규 기각. §3-1에 데이터 모델 (확장성 요구) 블록 신규 — 이벤트 로그 진실원천, 총합은 캐시, 불투명 단일 총합 저장 금지. Migration plan 항목도 "이벤트 로그 + 캐시"로 정정. Risks에 "총합만 저장 시 foundation 실패" 항목 추가.
- → §1.3, §3-1, 부록 Required artifacts/Risks.
- Q: +1/+1 XP가 MVP로 acceptable 하지만 cap/diminishing/volume balancing이 블로킹처럼 보일 수 있음
- A: §3-1에 "MVP 단가 정책" 노트 — 출시 차단 아닌 정책 결정 게이트. §7 DM 단가 OQ를 "단가 + cap/diminishing/balancing"으로 확장하며 "ship 후 재계산 가능" 명시.
- → §3-1, §7.
- Q: 비로그인/0 XP 표시가 단정적으로 박혀 있음 — recommendation/open decision으로 격하 권장
- A: §3-1 비즈니스 룰 문장을 "권장값" + "디자인/스펙에서 재검토"로 완화. §4 표 행도 동일. §7에 "비로그인 영역 표시 정책" OQ 신규.
- → §3-1, §4, §7.
- Q: Out of scope에 sentiment weighting + DM 메모리(DEE-115) 효과가 명시 안 됨
- A: §3-5 Out of scope에 "감정/톤 분석 기반 점수 산출", "DM 메모리/컨텍스트 효과(DEE-115)" 추가. 가중치 룰 항목에 "이벤트 로그 보존으로 사후 도입 가능" 보강.
- → §3-5.
- Q: 의존성에 DEE-115 누락, DEE-79도 함께 언급 필요
- A: 부록 의존성·References에 DEE-115 추가, DEE-66을 DEE-66/79로 병기.
- → 부록.
Skip
- Q: 가설 검증 지표를 본 PRD에서 더 단단히 만들 것
- 사유: foundation 특성상 가설 1·2 직접 검증은 후속 PRD에서 한다는 이전 결정 유지. PM direction도 "complete relationship experience 아님"이라 일관.
- Q: §5.2 로깅 이벤트 재정의
- 사유: PM direction에 직접 신호 없음. 기존 §7 OQ(Cloudflare Access 세션 확인)로 충분.
본 세션에서 추가/강화된 §7 OQ
- DM 메시지 단가 OQ → "단가 + cap/diminishing/소스간 volume balancing" 정책 게이트로 확장 (출시 차단 아님 명시).
- 비로그인/XP=0 영역 표시 정책 (0 XP 노출 vs 영역 숨김) — 디자이너 + PM.
momo 인라인 피드백 (criteria 후보)
- foundation/사전작업 성격 PRD는 "성공 정의"를 본문 상단에 박을 것 — "완성된 경험"으로 오독될 수 있는 PRD는 상단 박스로 scope를 좁혀 선언. (criteria 후보로 momo walk-through에서 컨펌 필요.)
- 데이터 모델이 사후 재계산 가능한가 — foundation PRD는 raw 이벤트 보존 형태인지 명시적으로 검사 — 단일 총합/스칼라만 저장하는 형태는 정책 튜닝 시 데이터 리셋 비용. (criteria 후보.)
남은 PM 결정 (walk-through 필요)
- 단계 곡선 함수 (선형/지수/수동) + 단계 수.
- 멘션 카운트 단위 (frame/scene/turn/episode 클리어당 N).
- DM 단가 + cap/diminishing/balancing — MVP는 +1/+1로 ship, 정책은 ship 후 도입?
- 비로그인/XP=0 친밀도 영역 표시 정책.
- 단계 라벨 카피 동반 여부.
- 다른 surface 노출 후속 결정 (MY/카드/홈).
- 적재 손실률 임계 + 가드레일 회귀 폭.
- 로깅 이벤트 재사용 매핑 (Cloudflare Access 세션).
2026-05-20 (PM decision update, momo 요청 반영)
채택 (PRD 본문 갱신)
- Q: Bond Exp 적립 단위에서
consumed_star / 3을 제거하고 star 소비량을 그대로 Exp로 적립하려면 기존 성장 밸런스가 깨지지 않는가?- A: 적립 단위가 3배 커지므로, 기존 성장 체감 속도를 유지하기 위해 일일 cap과 Lv threshold를 모두 3배 스케일한다.
- → Exp 적립:
consumed_star자체(멀티 캐릭터 scene은 등장 캐릭터 수로 균등 분배), 일일 cap:15,000 Bond Exp, Lv 공식:300 × (N − 1)², max_level=200 유지.
남은 결정
- 없음. 본 변경은 기존 성장 속도 의도를 유지하는 단위 재정의로 확정.
2026-05-20 Soul/Character terminology update
- 상위 도메인 term을 Character Bond에서 Bond로 정렬.
- Bond Exp/Level은 episode_scene_appearance와 dm_response_generated를 source별 저장 후 (user, Soul) 기준 aggregate.
- 관계 Lv/progress는 linked Soul + DM Thread 조건에서만 노출.
- Episode Character ↔ Soul mapping 변경에 따른 aggregate 변동은 별도 유저 안내/보상/롤백 없이 처리.
2026-05-22 (DM spec feedback 반영 — Soul 연결/선톡/노출 surface 정렬)
채택 (PRD 본문 갱신)
- 제목을
[앱]에서[서버]로 변경. 본 PRD의 핵심은 서버 foundation/Bond 이벤트 로그·집계이며, 앱/웹은 노출 surface로 명시. - 관계 Lv/progress 노출 surface를 DM 캐릭터 프로필 상세 + 에피소드 상세 Episode Character 정보 섹션 두 곳으로 정렬. 에피소드 surface는 linked Soul 조건을 사용하며 기존 DM Thread 필수 조건을 제거.
- Bond Exp 적립 대전제를
star consumed → Bond Exp로 명시하고, 개인화 선톡도 유저 측 수신 성공 시 star가 차감되면 적립 source에 포함. - DM source 명칭은
dm_response_generated로 유지하고, spec 쪽의 애매한dm_message표현은dm_response_generated기준으로 맞춘다. - Soul 미연결 Episode Character side Exp 임시 적립 → Soul 연결 후 유저 컨텍스트 기반 데이터 패치/리드 시점 1회 이관 → Episode Character side reset 정책 추가.
- Episode Character id 재발행/중복 migration 정책 추가: 새 id 발급 이후 신규 play/generation부터 새 id 기준 적립, 과거 play 소급 적립 없음.
- 공식
300 × (N − 1)²기준 주요 레벨 도달 필요 누적 Exp와 max 기준 소요일 표 추가. 평균 기준은avg_daily_credited_exp확정 후 산출하도록 보존.