데이터 · ERD D--8 오픈 2026-09-16
기획 04

데이터 · ERD

판정 로그가 이 프로젝트의 산출물입니다. 게임 상태보다 로그 설계가 먼저입니다.

민 담당 장민석

9/04(D-12) 18:00 ERD FREEZE

이후 변경은 PM 승인 + 마이그레이션 + 클라이언트 대응이 세트로 따라옵니다.

이 ERD의 성격이 다릅니다

일반 서비스라면 데이터는 기능을 뒷받침합니다. 여기서는 판정 로그 자체가 산출물입니다.

  • 11.1 시스템 검증 12종이 전부 이 테이블들에서 나온다
  • 11.2 실사용 데이터, 특히 침묵 권고 채택률이 여기서만 측정된다
  • 8.8 인스펙터는 이 로그를 그대로 열어 보여주는 화면이다

기획서 11.2: 구현 비용은 로그 테이블 하나 수준이며, 초기 설계에 반드시 포함한다.

계정 테이블이 없습니다

로그인을 만들지 않습니다

12.4가 로그인·설치 없이 즉시 진입을 요구합니다. user·user_profile·refresh_token 은 전부 삭제했습니다. 대신 session 이 익명 식별자(쿠키/로컬 저장) 하나로 플레이를 묶습니다.

공통 컬럼

컬럼 타입 설명
id BIGSERIAL PK 내부 식별자
public_id UUID UNIQUE 외부 노출용
created_at TIMESTAMPTZ 생성 시각 (UTC 저장 · KST 표시)

로그 성격 테이블은 updated_at·deleted_at 을 두지 않습니다. 판정 기록은 수정하거나 지우지 않습니다.

테이블

세션 · 루프

테이블 역할 주요 컬럼
session 익명 플레이 세션 anon_key UNIQUE, domain(game·audit·career), started_at, ended_at
loop 루프 1회 session_id FK, loop_no, utterance_budget, ended_reason, ending_type
beat 하루의 비트 (5개) loop_id FK, beat_no, scene_key

loop.ending_type 은 7장의 4종 — repeat · isolation(고립) · hesitation(망설임) · handover(인계).

대화 · 판정

테이블 역할 주요 컬럼
utterance 유저 발화 1건 loop_id FK, beat_id FK, target_npc, text, delivery(전달량), exposure(노출량), budget_before/after
npc_state 루프 내 NPC 상태 loop_id FK, npc_key(minseok·chaeyeon·eunsang), suspicion, trust, probe_budget, plan_json
judgement_log 판정 1건 = 인스펙터 1줄 utterance_id FK, npc_key, kind, delta, accumulated, threshold, reason, raw_llm_json
replan_event 재계획 발동 loop_id FK, npc_key, trigger, changed(bool), before_plan, after_plan

judgement_log.kind — suspicion · trust · tool_call · tool_result · inconsistency · replan. 8.8 인스펙터 출력이 이 테이블의 한 루프 분량 그대로입니다.

도구

테이블 역할 주요 컬럼
tool_call 도구 호출 utterance_id FK, caller_npc, tool_name, arguments, result, side_effect_json, latency_ms, budget_after
부작용을 컬럼으로 남긴다

ask_npc 는 호출 자체가 상태를 바꿉니다 — 이름을 빌린 쪽의 의심도가 오릅니다. side_effect_json 이 없으면 "왜 B가 갑자기 의심하지?"의 인과가 끊깁니다.

노트 · 손상

테이블 역할 주요 컬럼
note_entry 루프 노트 (자동 기록) session_id FK, loop_id FK, kind(death_sense·event·dialogue), text, embedding
world_damage 세계 손상 — 리셋되지 않는 유일한 상태 session_id FK, depth_score, layer1_on, layer2_on, layer3_on, updated_at
damage_event 손상 발현 기록 session_id FK, loop_id FK, layer, target, detail

world_damage.depth_score 는 루프 횟수가 아니라 개입 깊이에 비례합니다 (4.8). 별도 게이지를 만들지 않고 기존 판정 로그에서 산출합니다 — 발화 수 · 신뢰도 변화량 · 결정적 발언 여부.

침묵 권고 — 측정 ②

테이블 역할 주요 컬럼
advice_log 권고 발동 1건 loop_id FK, beat_id FK, fired(bool), recommendation, rationale, state_snapshot_json, rationale_shown(bool)
— 유저 반응 user_action(accepted·ignored·none), outcome_delta
이 테이블 하나가 기획서 11.2의 핵심 지표 전부를 담당합니다
  • 권고 수용률 → user_action
  • 발동 빈도별 수용률 곡선 → fired + 시간 분포
  • 무시 vs 수용 그룹 결과 대조 → outcome_delta
  • 근거 표시 유무별 수용률 (A/B) → rationale_shown

rationale_shown 을 처음부터 넣는 이유는, 나중에 붙이면 A/B 대조군이 없어져 11.2의 마지막 행을 측정할 수 없기 때문입니다.

하네스 계측

테이블 역할 주요 컬럼
llm_call LLM 호출 1건 loop_id FK, role(planner·agent·advisor·evaluator), model, schema_ok, retry_count, tokens_in/out, latency_ms, cost

역할별 스키마 통과율 · 재시도율(9.4)이 여기서 나오고, 비용 관리도 겸합니다.

관계도

session ──1:N── loop ──1:N── beat
   │              ├──1:N── utterance ──1:N── judgement_log
   │              │             └──1:N── tool_call
   │              ├──1:N── npc_state      (루프당 3행: 민석·채연·은상)
   │              ├──1:N── replan_event
   │              ├──1:N── advice_log
   │              └──1:N── llm_call
   ├──1:N── note_entry        ← 루프를 넘어 누적
   ├──1:1── world_damage      ← 리셋되지 않음
   └──1:N── damage_event

리셋 경계가 곧 테이블 경계입니다. loop 아래는 루프마다 새로 생기고, session 직속(note_entry·world_damage)은 루프를 넘어 살아남습니다. 8.4 메모리 비대칭이 스키마에 그대로 박힙니다.

민석 예외는 스키마가 아니라 정책

npc_state 는 셋 다 같은 테이블을 씁니다. 차이는 루프 전이 시 무엇을 이월하는가뿐입니다.

NPC 이월
채연 · 은상 소거 (신뢰 5% 잔류)
민석 유지

같은 NPC 인터페이스를 구현하되 메모리 정책만 다르게 주입합니다. 포트 설계가 제대로 돼 있으면 정책 주입만으로 처리됩니다 — 아키텍처가 서사를 지탱하는 지점입니다.

인덱스

테이블 인덱스 이유
loop (session_id, loop_no) 루프 조회
utterance (loop_id, created_at) 대화 복원
judgement_log (utterance_id) 인스펙터 개봉
note_entry (session_id, loop_id) + embedding 벡터 인덱스 노트 축적 · search_notes
advice_log (user_action, rationale_shown) 11.2 집계
llm_call (role, model, schema_ok) 9.4 하네스 지표

마이그레이션

  • Alembic. 리비전 하나 = 변경 하나. downgrade 필수 작성
  • D-4(9/12) 에 downgrade → upgrade 왕복 검증
  • 오픈 직전에는 추가만 하는 마이그레이션 (컬럼 삭제·이름 변경 금지)

결정 로그

날짜 결정 이유
2026-09-03 계정 테이블 전부 삭제, 익명 session 도입 12.4 로그인 없는 즉시 진입
2026-09-03 advice_log.rationale_shown 을 초기 설계에 포함 나중에 붙이면 A/B 대조군이 사라져 11.2 측정 불가
2026-09-03 world_damage 를 session 직속으로 (loop 아래 아님) 손상은 리셋되지 않는 유일한 세계 상태 (4.8)
2026-09-03 손상 게이지를 별도 관리하지 않고 판정 로그에서 산출 4.8 원문. 중복 상태를 만들면 어긋난다
2026-09-03 tool_call.side_effect_json 필수 부작용이 안 남으면 발각의 인과가 끊긴다