- users → user in SQL contexts (94 occurrences) - robeings → robeing in SQL contexts - user_preferences → user_preference (14 files) - slack_workspaces → slack_workspace in SQL contexts (17 files) All table names now correctly match PostgreSQL schema
5.1 KiB
5.1 KiB
대화 히스토리 조회 플로우
작성일: 2025-09-02
대상: rb8001/rb10508_micro 대화 히스토리
상태: ✅ 구현 완료
1. 전체 플로우
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<br/>Authorization: Bearer {JWT}
G->>G: JWT 검증 (서명, 만료시간)
G->>G: JWT에서 sub(UUID) 추출
G->>G: workspace_member 테이블 조회<br/>robeing_id 확인 (rb8001)
G->>R: GET /api/history?limit=30<br/>Authorization: Bearer {JWT}<br/>X-User-Id: {UUID}
R->>R: JWT 검증 및 user_id 추출
R->>DB: SELECT * FROM conversation_log<br/>WHERE user_id = (:user_id)::uuid
DB-->>R: 대화 기록 반환
R->>R: DB row를 Frontend 형식으로 변환<br/>(user/robeing 메시지 분리)
R-->>G: {"messages": [...], "has_more": true}
G-->>F: 응답 전달
F->>F: 화면에 메시지 렌더링
2. JWT 토큰 구조
2.1 auth-server 발급 토큰
{
"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 검증
# 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 라우팅
# workspace_member 테이블 조회
SELECT robeing_id FROM workspace_member
WHERE user_id = :user_id
# 결과: rb8001 또는 rb10508_micro
3.3 헤더 전달
headers = {
"Authorization": request.headers.get("Authorization"), # JWT 전달
"X-User-Id": user_id # UUID 전달
}
4. rb8001 처리
4.1 JWT 인증
# 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 조회
# 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 응답 변환
# 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 호출
// 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 무한 스크롤
// Intersection Observer로 스크롤 감지
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && hasMore) {
const oldestMessage = messages[0];
loadMoreMessages(oldestMessage.timestamp);
}
});
6. 데이터베이스 스키마
6.1 users 테이블
CREATE TABLE user (
id UUID PRIMARY KEY,
email VARCHAR(255) UNIQUE,
username VARCHAR(50) UNIQUE,
name VARCHAR(255)
);
6.2 workspace_member 테이블
CREATE TABLE workspace_member (
user_id UUID REFERENCES user(id),
workspace_id UUID,
robeing_id VARCHAR(50) -- rb8001, rb10508_micro 등
);
6.3 conversation_log 테이블
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
JWT_SECRET_KEY=9cc562b6296b87b02dd89045a2e7e11c249713a59a5ac0160d852121f1289664
DEFAULT_ROBEING_HOST=192.168.219.52
DEFAULT_ROBEING_PORT=8001
7.2 rb8001
JWT_SECRET_KEY=9cc562b6296b87b02dd89045a2e7e11c249713a59a5ac0160d852121f1289664
MESSAGE_BATCH_SIZE=30
MAX_MESSAGES_IN_DOM=200
8. 트러블슈팅 참고
자세한 문제 해결 과정은 다음 문서 참조:
- troubleshooting/250901_rb8001_chat_history_implementation_issues.md