# 대화 히스토리 조회 플로우 ## 작성일: 2025-09-02 ## 대상: rb8001/rb10508_micro 대화 히스토리 ## 상태: ✅ 구현 완료 --- ## 1. 전체 플로우 ```mermaid sequenceDiagram participant F as Frontend participant G as Gateway participant R as rb8001 participant DB as PostgreSQL F->>F: localStorage에서 JWT 토큰 가져오기 F->>F: JWT decode하여 user_id 추출 F->>G: GET /gateway/api/history?limit=30
Authorization: Bearer {JWT} G->>G: JWT 검증 (서명, 만료시간) G->>G: JWT에서 sub(UUID) 추출 G->>G: workspace_member 테이블 조회
robeing_id 확인 (rb8001) G->>R: GET /api/history?limit=30
Authorization: Bearer {JWT}
X-User-Id: {UUID} R->>R: JWT 검증 및 user_id 추출 R->>DB: SELECT * FROM conversation_log
WHERE user_id = (:user_id)::uuid DB-->>R: 대화 기록 반환 R->>R: DB row를 Frontend 형식으로 변환
(user/robeing 메시지 분리) R-->>G: {"messages": [...], "has_more": true} G-->>F: 응답 전달 F->>F: 화면에 메시지 렌더링 ``` --- ## 2. JWT 토큰 구조 ### 2.1 auth-server 발급 토큰 ```json { "sub": "1e16e9d5-59f3-54da-a661-8abeabff4230", // UUID "email": "goeun2dc@gmail.com", "name": "김종태", "username": "happybell80", "picture": "https://...", "exp": 1759046456 } ``` ### 2.2 중요 필드 - `sub`: 사용자 UUID (users.id) - `username`: 사용자명 - `exp`: 만료 시간 (Unix timestamp) --- ## 3. Gateway 처리 ### 3.1 JWT 검증 ```python # Gateway main.py def verify_jwt_token(token: str): payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=["HS256"]) return payload["sub"] # UUID 반환 ``` ### 3.2 robeing 라우팅 ```python # workspace_member 테이블 조회 SELECT robeing_id FROM workspace_member WHERE user_id = :user_id # 결과: rb8001 또는 rb10508_micro ``` ### 3.3 헤더 전달 ```python headers = { "Authorization": request.headers.get("Authorization"), # JWT 전달 "X-User-Id": user_id # UUID 전달 } ``` --- ## 4. rb8001 처리 ### 4.1 JWT 인증 ```python # rb8001 main.py async def get_current_user(authorization: str = Header(None)): token = authorization.replace("Bearer ", "") payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=["HS256"]) return payload["sub"] # UUID ``` ### 4.2 DB 조회 ```python # database.py async def get_paginated_conversations(user_id: str, before: float = None, limit: int = 30): query = """ SELECT id, message, response, timestamp FROM conversation_log WHERE user_id = (:user_id)::uuid AND robeing_id = 'rb8001' AND (:before::timestamp IS NULL OR timestamp < :before) ORDER BY timestamp DESC LIMIT :limit """ ``` ### 4.3 응답 변환 ```python # DB row → Frontend 형식 messages = [] for row in results: # User 메시지 messages.append({ "id": f"{row['id']}_user", "text": row["message"], "sender": "user", "timestamp": row["timestamp"].isoformat() }) # Robeing 응답 messages.append({ "id": f"{row['id']}_robeing", "text": row["response"], "sender": "robeing", "timestamp": row["timestamp"].isoformat() }) ``` --- ## 5. Frontend 처리 ### 5.1 API 호출 ```typescript // robeing-api.ts export async function getHistory(before?: string, limit: number = 30) { const params = new URLSearchParams({ limit: limit.toString() }); if (before) params.append('before', before); const response = await fetch(`${API_URL}/api/history?${params}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } }); return response.json(); } ``` ### 5.2 무한 스크롤 ```typescript // Intersection Observer로 스크롤 감지 const observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting && hasMore) { const oldestMessage = messages[0]; loadMoreMessages(oldestMessage.timestamp); } }); ``` --- ## 6. 데이터베이스 스키마 ### 6.1 users 테이블 ```sql CREATE TABLE user ( id UUID PRIMARY KEY, email VARCHAR(255) UNIQUE, username VARCHAR(50) UNIQUE, name VARCHAR(255) ); ``` ### 6.2 workspace_member 테이블 ```sql CREATE TABLE workspace_member ( user_id UUID REFERENCES user(id), workspace_id UUID, robeing_id VARCHAR(50) -- rb8001, rb10508_micro 등 ); ``` ### 6.3 conversation_log 테이블 ```sql CREATE TABLE conversation_log ( id INTEGER PRIMARY KEY, robeing_id VARCHAR, message VARCHAR, response VARCHAR, timestamp TIMESTAMP, user_id UUID REFERENCES user(id) ); ``` --- ## 7. 환경변수 설정 ### 7.1 Gateway ```env JWT_SECRET_KEY=9cc562b6296b87b02dd89045a2e7e11c249713a59a5ac0160d852121f1289664 DEFAULT_ROBEING_HOST=192.168.219.52 DEFAULT_ROBEING_PORT=8001 ``` ### 7.2 rb8001 ```env JWT_SECRET_KEY=9cc562b6296b87b02dd89045a2e7e11c249713a59a5ac0160d852121f1289664 MESSAGE_BATCH_SIZE=30 MAX_MESSAGES_IN_DOM=200 ``` --- ## 8. 트러블슈팅 참고 자세한 문제 해결 과정은 다음 문서 참조: - troubleshooting/250901_rb8001_chat_history_implementation_issues.md