# Conversation Log 재설계: Event Stream 아키텍처

## 작성일
2025-10-02

## 문제 상황

### 기존 conversation_log 테이블 한계
```sql
conversation_log
- user_id (FK)
- message
- response
```

**가정**: 항상 1:1 대화 (user → robeing)

### 실제 요구사항
1. **그룹 대화**: user1, user2, user3, robeing
2. **로빙 브리핑**: robeing → 팀 전체
3. **로빙 협업**: robeing1 ↔ robeing2
4. **멀티턴 쓰레드**: user ↔ robeing (여러 왕복)

### 근본 문제
- **참여자 표현 불가**: 1:1만 가정
- **방향성 모호**: message/response 구분 애매
- **컨텍스트 부재**: 어떤 채널/쓰레드인지 불명확
- **로빙 철학 위배**: 로빙도 대화 주체인데 user 테이블에 없음

## 철학적 배경

### 로빙 철학과 DB 구조 충돌
- **user 테이블**: 인증/식별 (OAuth, email, login)
- **robeing 테이블**: 성장 주체 (level, experience, stats)
- **문제**: 로빙 봇(Slack Bot ID)이 user 테이블에 없어서 봇 메시지 저장 불가

### "대화는 이벤트의 흐름"
- **Graph DB**: 공간적 관계망 (A-B-C 연결 구조)
- **Event Stream**: 시간적 흐름 (A→B→C 순서)
- 로빙의 베이지안 성장 = 시간에 따른 업데이트 → **시간축이 핵심**

## 해결 방안: Event 테이블 (6하원칙)

### 설계 원칙
**장소(where_id) + 시간(timestamp) = 이벤트 연결**
- where_id: Slack, 이메일, 웹, 음성통화 등 모든 채널
- timestamp: 시간 순서 보장
- 6하원칙: 모든 이벤트를 표준화

### Event 테이블 구조
```sql
event
-- 기본 6하원칙
- id (PK, UUID)
- who_id (UUID)              -- 행위 주체
- who_type (VARCHAR)         -- human/robeing/system
- what_type (VARCHAR)        -- message/file_transfer/task_assign/analysis_request/reaction
- what_content (JSONB)       -- 실제 내용/데이터
- when_at (TIMESTAMPTZ)      -- 시간
- where_id (VARCHAR)         -- 장소 (channel/dm/email/system)
- where_type (VARCHAR)       -- slack/email/web/voice/internal
- why (VARCHAR)              -- intent/purpose
- how (VARCHAR)              -- method/tool

-- 확장 필드 (복잡한 관계 처리)
- to_who (JSONB)             -- [{id, type}] 수신자 목록
- using (JSONB)              -- [{id, type, resource}] 사용된 리소스/데이터
- affected (JSONB)           -- [{id, type, change}] 영향받은 대상
- parent_event_id (UUID)     -- 이전 이벤트 (인과관계)
- result (JSONB)             -- {status, outcome, data} 결과
- metadata (JSONB)           -- 기타 확장 데이터

-- 인덱스
- (where_id, when_at)        -- 시계열 조회
- (who_id, when_at)          -- 주체별 이력
- parent_event_id            -- 이벤트 체인
```

### JSONB 활용 예시

#### 1. 파일 전송
```json
{
  "who_id": "user-uuid",
  "what_type": "file_transfer",
  "what_content": {"filename": "report.pdf", "size": 1024},
  "to_who": [{"id": "user2-uuid", "type": "human"}],
  "where_id": "slack-dm-123"
}
```

#### 2. 로빙 협업
```json
{
  "who_id": "robeing1-uuid",
  "what_type": "analysis_request",
  "to_who": [{"id": "robeing2-uuid", "type": "robeing"}],
  "using": [{"id": "robeing3-uuid", "type": "robeing", "resource": "market_data"}],
  "result": {"status": "completed", "data": "..."}
}
```

#### 3. 그룹 대화
```json
{
  "who_id": "user1-uuid",
  "what_type": "message",
  "what_content": {"text": "팀 회의 시작합니다"},
  "to_who": [
    {"id": "user2-uuid", "type": "human"},
    {"id": "user3-uuid", "type": "human"},
    {"id": "robeing-uuid", "type": "robeing"}
  ],
  "where_id": "slack-channel-team"
}
```

## 이벤트 연결 메커니즘

### 간단 버전
1. **같은 장소**: where_id로 묶음
2. **같은 쓰레드**: parent_event_id 체인
3. **시간 순서**: when_at으로 정렬

### 쿼리 예시
```sql
-- 특정 채널의 모든 이벤트 (시간순)
SELECT * FROM event
WHERE where_id = 'slack-channel-123'
ORDER BY when_at;

-- 특정 이벤트 체인 (쓰레드)
WITH RECURSIVE thread AS (
  SELECT * FROM event WHERE id = 'root-event-id'
  UNION ALL
  SELECT e.* FROM event e
  JOIN thread t ON e.parent_event_id = t.id
)
SELECT * FROM thread ORDER BY when_at;
```

## Graph DB와의 관계

### Graph DB가 필요한 순간
1. **복잡한 관계 쿼리 반복**: 3-hop 이상 탐색
2. **실시간 추천**: 협업 필터링, 소셜 추천
3. **영향력 분석**: 정보 전파 경로, 네트워크 중심성
4. **다중 로빙 협업**: 최적 조합 찾기

### 현재 판단
**Event Stream만으로 충분**
- JSONB로 관계 저장 (충분히 유연)
- 시계열 분석이 핵심 (TimescaleDB 최적화)
- 나중에 필요하면 Graph DB 추가 (Read Model 패턴)

### Graph vs Event Stream
- **Graph**: "누구와 연결되었나" (공간적 관계망)
- **Event**: "언제 무엇을 했나" (시간적 흐름)
- 로빙의 핵심(성장/기억/감정) = 시간축 → **Graph는 optional**

## 마이그레이션 전략

### 1단계: Event 테이블 생성 (robeing_metrics DB)
```sql
CREATE TABLE event (
  -- 6하원칙 컬럼들
  ...
) PARTITION BY RANGE (when_at);

-- TimescaleDB 하이퍼테이블 전환
SELECT create_hypertable('event', 'when_at');
```

### 2단계: 기존 conversation_log 데이터 변환
```sql
INSERT INTO event (who_id, what_type, what_content, when_at, where_id, ...)
SELECT
  user_id as who_id,
  'message' as what_type,
  jsonb_build_object('text', message, 'response', response) as what_content,
  timestamp as when_at,
  channel_id as where_id,
  ...
FROM conversation_log;
```

### 3단계: 애플리케이션 코드 전환
- conversation_log 조회 → event 조회
- 새 대화 저장 → event INSERT

## 기대 효과

### 1. 확장성
- 모든 종류의 이벤트 저장 가능 (대화, 파일, 작업, 알림 등)
- 새로운 이벤트 타입 추가 시 스키마 변경 불필요 (JSONB)

### 2. 분석 역량
- 시계열 분석 최적화 (TimescaleDB)
- 이벤트 체인 추적 (베이지안 업데이트)
- 사용자/로빙별 이력 조회

### 3. 철학적 일관성
- 로빙도 이벤트 주체로 동등하게 취급
- user = "관계의 상대방" 명확화
- 성장과 기억의 원천 = 이벤트 흐름

## 교훈

### 기존 설계의 문제
- **conversation_log**: 챗봇 QA 로그 수준
- **1:1 가정**: 다중 참여자 협업 불가
- **user/robeing 분리**: 로빙을 도구로 취급

### 새로운 설계의 핵심
- **Event Stream**: 모든 행위를 시간순 이벤트로
- **6하원칙**: 표준화된 구조
- **JSONB**: 복잡한 관계도 유연하게
- **시간축 중심**: 베이지안 성장과 일치

## 참고사항

### 관련 문서
- `/home/admin/DOCS/300_architecture/database/tables.md`: DB 스키마
- `/home/admin/DOCS/100_philosophy/125_베이즈_성장과_관계의_철학.md`: 로빙 철학

### DB 위치
- **main_db**: user, robeing 테이블 (기존)
- **robeing_metrics**: event 테이블 (새로 추가)
- TimescaleDB 하이퍼테이블로 시계열 최적화