- 2025년 8월 9일 테스트용 하드코딩 UUID가 문제의 시작 - gen_random_uuid() 사용하지 않고 가짜 UUID 사용한 것이 원인 - 테스트 데이터가 프로덕션에 남아 연쇄 문제 발생 - PostgreSQL UUID 올바른 사용법 교훈 추가
214 lines
7.0 KiB
Markdown
214 lines
7.0 KiB
Markdown
# 카톡 스타일 대화 히스토리 구현
|
|
|
|
**날짜**: 2025-08-18
|
|
**작업자**: happybell80 & Claude
|
|
**관련 프로젝트**: rb10508_micro, frontend-customer
|
|
|
|
## 오후 12시 00분 - 요구사항 분석
|
|
|
|
### 사용자 요구사항
|
|
- 카카오톡처럼 대화 히스토리를 볼 수 있도록 구현
|
|
- 날짜 구분선 표시 (오늘, 어제, 날짜 형식)
|
|
- 무한 스크롤로 이전 대화 로드
|
|
- 읽지 않은 메시지나 대화방 개념은 불필요
|
|
|
|
### 시스템 구조 파악
|
|
- 독립적인 로빙들 (rb8001, rb10508_micro, rb10408)
|
|
- 로그인 시 사용자별 로빙 배정
|
|
- Gateway가 라우팅 (프론트엔드 → Gateway → 로빙)
|
|
- 각 로빙이 독립적인 ChromaDB 보유
|
|
|
|
## 오후 12시 30분 - 백엔드 구현
|
|
|
|
### 1. 환경변수 설정 추가
|
|
```python
|
|
# app/config.py
|
|
MESSAGE_BATCH_SIZE: int = int(os.getenv("MESSAGE_BATCH_SIZE", 30))
|
|
SCROLL_THRESHOLD: int = int(os.getenv("SCROLL_THRESHOLD", 100))
|
|
MAX_MESSAGES_IN_DOM: int = int(os.getenv("MAX_MESSAGES_IN_DOM", 200))
|
|
```
|
|
|
|
### 2. API 엔드포인트 구현
|
|
```python
|
|
# app/api/endpoints.py
|
|
@router.get("/messages") # 페이지네이션된 메시지 조회
|
|
@router.get("/config") # 프론트엔드 설정 동기화
|
|
```
|
|
|
|
**함수형 프로그래밍 원칙 준수**:
|
|
- 환경변수로 설정 관리 (하드코딩 없음)
|
|
- 순수 함수로 구현
|
|
- 불변성 유지
|
|
|
|
## 오후 1시 00분 - 프론트엔드 구현
|
|
|
|
### 1. robing-api.ts 확장
|
|
- `getConfig()`: 백엔드 설정 가져오기
|
|
- `getMessages()`: 페이지네이션 지원 메시지 조회
|
|
|
|
### 2. ChatInterface 컴포넌트 개선
|
|
- Intersection Observer로 무한 스크롤
|
|
- 날짜 구분선 렌더링 로직
|
|
- 기존 파일 수정만으로 구현 (새 파일 생성 없음)
|
|
|
|
## 오후 1시 15분 - API 경로 문제 발견
|
|
|
|
### 문제
|
|
- API 호출 시 404 Not Found
|
|
- `/rb10508/api/config` 접근 불가
|
|
|
|
### 원인
|
|
```python
|
|
# app/main.py
|
|
app.include_router(api_router, prefix="/api") # 라우터 프리픽스
|
|
|
|
# app/api/endpoints.py
|
|
@router.get("/api/config") # 잘못된 경로 (중복)
|
|
```
|
|
|
|
결과: `/api` + `/api/config` = `/api/api/config`
|
|
|
|
### 해결
|
|
```python
|
|
@router.get("/config") # 올바른 경로
|
|
@router.get("/messages") # 올바른 경로
|
|
```
|
|
|
|
## 교훈
|
|
|
|
### 1. **라우터 프리픽스 확인 필수**
|
|
- 엔드포인트 추가 전 main.py에서 라우터 등록 방식 확인
|
|
- 프리픽스와 엔드포인트 경로 중복 주의
|
|
|
|
### 2. **함수형 프로그래밍 원칙**
|
|
- 설정값 하드코딩 금지 → 환경변수 사용
|
|
- 새 파일 생성 최소화 → 기존 파일 수정
|
|
- 코드 재사용성 확인
|
|
|
|
### 3. **테스트 환경 관리**
|
|
- 로컬 포트 충돌 주의 (서버 포트와 겹치지 않도록)
|
|
- 테스트 파일은 즉시 삭제
|
|
- 불필요한 의존성 추가 금지 (Playwright 같은)
|
|
|
|
### 4. **Git 커밋 원칙**
|
|
- `git add .` 사용 (선택적 add 대신)
|
|
- 의존성 변경은 신중하게 검토
|
|
|
|
## 최종 결과
|
|
|
|
### 구현된 기능
|
|
1. **무한 스크롤**: 위로 스크롤 시 이전 메시지 30개씩 로드
|
|
2. **날짜 구분선**: "오늘", "어제", "2024년 12월 25일 월요일" 형식
|
|
3. **설정 동기화**: 백엔드에서 배치 크기 등 설정 제공
|
|
|
|
### 배포 상태
|
|
- rb10508_micro: b0003cd (API 경로 수정)
|
|
- frontend-customer: c3a38e7 (카톡 스타일 UI)
|
|
|
|
### API 엔드포인트
|
|
- GET `/rb10508/api/config` - 설정 조회
|
|
- GET `/rb10508/api/messages?before={timestamp}&limit={number}` - 메시지 조회
|
|
|
|
## 오후 1시 30분 - 사용자 매핑 문제 발견
|
|
|
|
### 문제 1: Username 변환 누락
|
|
- API가 `user_id="default_user"`로 검색
|
|
- 실제 데이터는 `rb10508_test_happybell80_episodic` 컬렉션에 저장
|
|
- `search_memories`가 username 파라미터를 받지 못함
|
|
|
|
### 해결
|
|
```python
|
|
# app/config.py에 매핑 테이블 추가
|
|
USER_MAPPING: dict = {
|
|
"default_user": "happybell80",
|
|
"U0925SXQFDK": "happybell80", # Slack ID
|
|
"goeun2dc@gmail.com": "happybell80", # Email
|
|
}
|
|
|
|
# app/api/endpoints.py에 헬퍼 함수 추가
|
|
def resolve_username(user_id: str) -> str:
|
|
"""user_id를 실제 username으로 변환"""
|
|
if user_id in settings.USER_MAPPING:
|
|
return settings.USER_MAPPING[user_id]
|
|
if "_user" in user_id:
|
|
return user_id.replace("_user", "")
|
|
return user_id
|
|
```
|
|
|
|
## 오후 1시 45분 - UUID vs Username 문제
|
|
|
|
### 문제 2: ChromaDB where 조건 불일치
|
|
- Slack 저장 시: `user_id = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"` (UUID)
|
|
- 프론트 검색 시: `user_id = "happybell80"` (username)
|
|
- where 조건 `{"user_id": user_id}` 일치하지 않음
|
|
|
|
### 근본 원인 발견
|
|
**2025년 8월 9일의 잘못된 결정이 문제의 시작**:
|
|
|
|
```sql
|
|
-- 잘못된 예: 테스트용 UUID 하드코딩 (250809_happybell80_robing-gateway구현.md)
|
|
INSERT INTO users (id, email, name) VALUES
|
|
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'::uuid, 'goeun2dc@gmail.com', '김종태'),
|
|
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'::uuid, '0914eagle@gmail.com', '전희재'),
|
|
('cccccccc-cccc-cccc-cccc-cccccccccccc'::uuid, 'hhyong91@gmail.com', '황한용');
|
|
|
|
-- 올바른 방법: gen_random_uuid() 사용
|
|
INSERT INTO users (id, email, name, username) VALUES
|
|
(gen_random_uuid(), 'goeun2dc@gmail.com', '김종태', 'happybell80');
|
|
-- 실제 UUID 생성: 'e7a9f3c2-8b4d-4f2e-a1b3-9c8d7e6f5a4b'
|
|
```
|
|
|
|
### 문제의 연쇄 반응
|
|
1. **테스트 데이터가 프로덕션에**: 임시 UUID가 영구 사용
|
|
2. **프론트엔드 혼란**: user_id 불명확 → "default_user" 하드코딩
|
|
3. **ChromaDB 컬렉션명 혼란**: UUID? username? email?
|
|
4. **매핑 지옥**: 여러 식별자 연결하는 복잡한 시스템 필요
|
|
|
|
### 왜 이런 실수를 했나
|
|
- OAuth 로그인 시 UUID 자동 생성 대신
|
|
- 개발 편의를 위해 알아보기 쉬운 UUID 사용
|
|
- aaaa..., bbbb..., cccc... 패턴으로 테스트
|
|
- username 시스템은 나중에 급하게 추가 (8월 9일)
|
|
|
|
### 해결
|
|
```python
|
|
# app/core/memory/storage.py 수정
|
|
# username으로 검색하도록 where 조건 변경
|
|
where_clause = {"username": username} if username else {"user_id": user_id}
|
|
|
|
results = collection.query(
|
|
query_texts=[query],
|
|
n_results=n_results,
|
|
where=where_clause
|
|
)
|
|
```
|
|
|
|
## 교훈 (추가)
|
|
|
|
### 5. **User ID 체계 통일 필수**
|
|
- UUID, username, email 3가지 혼재 문제
|
|
- 각 시스템이 다른 ID 사용하여 반복적 오류
|
|
- 트러블슈팅 문서 확인 습관 필요
|
|
|
|
### 6. **ChromaDB 메타데이터 일관성**
|
|
- 저장 시와 검색 시 키 일치 확인
|
|
- username vs user_id 명확히 구분
|
|
- where 조건 디버깅 로그 추가 권장
|
|
|
|
### 7. **테스트 데이터를 프로덕션에 사용 금지**
|
|
- 개발 편의를 위한 하드코딩 UUID 사용 금지
|
|
- 항상 `gen_random_uuid()` 같은 실제 함수 사용
|
|
- 테스트 데이터는 명확히 구분하고 제거
|
|
|
|
### 8. **PostgreSQL UUID 올바른 사용법**
|
|
```sql
|
|
-- ❌ 잘못된 방법: 하드코딩
|
|
INSERT INTO users (id) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa');
|
|
|
|
-- ✅ 올바른 방법: 함수 사용
|
|
INSERT INTO users (id) VALUES (gen_random_uuid());
|
|
-- 또는 테이블 정의 시 DEFAULT 설정
|
|
CREATE TABLE users (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid()
|
|
);
|
|
``` |