diff --git a/troubleshooting/20251002_conversation_log_redesign.md b/troubleshooting/20251002_conversation_log_redesign.md new file mode 100644 index 0000000..0f442a5 --- /dev/null +++ b/troubleshooting/20251002_conversation_log_redesign.md @@ -0,0 +1,229 @@ +# 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 하이퍼테이블로 시계열 최적화 \ No newline at end of file