docs: 타임존 버그 및 스크롤 위치 문제 해결 문서 추가
- naive/aware datetime 비교 버그 해결 과정 - 스크롤 위치 유지 구현 - 함수형 프로그래밍 원칙 적용 사례
This commit is contained in:
parent
382f51d365
commit
d8d2948c36
123
troubleshooting/250819_happybell80_타임존버그및스크롤.md
Normal file
123
troubleshooting/250819_happybell80_타임존버그및스크롤.md
Normal file
@ -0,0 +1,123 @@
|
||||
# 이전 대화 불러오기 타임존 버그 및 스크롤 위치 문제 해결
|
||||
|
||||
**날짜**: 2025-08-19
|
||||
**작업자**: happybell80 & Claude
|
||||
**관련 프로젝트**: rb10508_micro, frontend-customer, robeing-gateway
|
||||
|
||||
## 오전 12시 30분
|
||||
|
||||
### 문제 1: 이전 대화 불러오기 버튼이 작동하지 않음
|
||||
|
||||
#### 증상
|
||||
- "이전 대화 불러오기" 버튼 클릭 시 빈 배열 반환
|
||||
- `/gateway/api/history?before=2025-08-18T02:22:30.707Z&limit=30` → `{"messages":[],"has_more":false}`
|
||||
- 8월 16, 17일 대화가 분명히 존재하는데도 못 가져옴
|
||||
|
||||
#### 원인 분석
|
||||
1. **프론트엔드 시간 변환 문제**
|
||||
- 서버가 보낸 `2025-08-18T11:22:30.707422` (타임존 없음)
|
||||
- JavaScript `new Date()` → 로컬 시간(KST)으로 해석
|
||||
- `toISOString()` → UTC로 변환하며 -9시간 → `2025-08-18T02:22:30.707Z`
|
||||
|
||||
2. **서버 타임존 비교 버그 (핵심 원인)**
|
||||
```python
|
||||
# rb10508_micro/app/core/memory/storage.py
|
||||
msg_time = datetime.fromisoformat(timestamp_str) # naive datetime
|
||||
before_time = datetime.fromisoformat(before.replace('Z', '+00:00')) # aware datetime
|
||||
if msg_time >= before_time: # TypeError 발생!
|
||||
```
|
||||
- Python 에러: `can't compare offset-naive and offset-aware datetimes`
|
||||
- 265번 라인 `except: continue`로 에러 무시 → 모든 메시지 건너뜀
|
||||
|
||||
#### 해결 방법
|
||||
**서버 코드 수정** - 모든 datetime을 UTC aware로 통일
|
||||
```python
|
||||
def to_utc_aware(dt_str: str) -> datetime:
|
||||
"""모든 datetime 문자열을 UTC aware datetime으로 통일하는 순수 함수"""
|
||||
if not dt_str:
|
||||
return None
|
||||
dt = datetime.fromisoformat(dt_str.replace('Z', '+00:00'))
|
||||
return dt.replace(tzinfo=timezone.utc) if dt.tzinfo is None else dt
|
||||
|
||||
# 사용
|
||||
msg_time = to_utc_aware(timestamp_str)
|
||||
before_time = to_utc_aware(before)
|
||||
```
|
||||
|
||||
### 문제 2: Gateway 우회 접근
|
||||
|
||||
#### 증상
|
||||
- 초기: `/rb10508/api/history` 직접 호출 (JWT 검증 우회)
|
||||
- 수정 후: `/gateway/api/history` 정상 호출
|
||||
|
||||
#### 해결 방법
|
||||
- `.gitea/workflows/deploy.yml` 수정
|
||||
- 서버 .env 파일에서 환경변수 읽도록 변경
|
||||
```yaml
|
||||
# 기존
|
||||
export VITE_ROBING_API_URL=https://ro-being.com/rb10508
|
||||
|
||||
# 수정
|
||||
if [ -f /home/admin/frontend-customer/.env ]; then
|
||||
export $(cat /home/admin/frontend-customer/.env | grep -v '^#' | xargs)
|
||||
fi
|
||||
```
|
||||
|
||||
### 문제 3: 이전 대화 로드 시 스크롤이 맨 아래로 이동
|
||||
|
||||
#### 증상
|
||||
- 이전 대화 불러오기 → 스크롤이 맨 아래로 → 방금 불러온 대화 안 보임
|
||||
|
||||
#### 원인
|
||||
- `useEffect`가 `messages` 변경 시마다 `scrollToBottom()` 실행
|
||||
|
||||
#### 해결 방법
|
||||
**스크롤 위치 기억 방식** (카톡과 동일)
|
||||
```javascript
|
||||
const oldHeight = messagesContainerRef.current?.scrollHeight || 0;
|
||||
// ... 메시지 로드 ...
|
||||
requestAnimationFrame(() => {
|
||||
if (messagesContainerRef.current) {
|
||||
messagesContainerRef.current.scrollTop +=
|
||||
(messagesContainerRef.current.scrollHeight - oldHeight);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 교훈
|
||||
|
||||
### 1. **타임존은 명시적으로 처리**
|
||||
- 서버는 항상 타임존 정보 포함 (Z 또는 +09:00)
|
||||
- naive datetime 절대 사용 금지
|
||||
- 비교 전 모든 datetime을 동일 타임존으로 통일
|
||||
|
||||
### 2. **예외 처리는 구체적으로**
|
||||
- `except:` 같은 광범위한 예외 처리 금지
|
||||
- 최소한 `except Exception as e:` + 로깅
|
||||
- 타임존 에러를 "데이터 없음"으로 착각하는 상황 방지
|
||||
|
||||
### 3. **함수형 프로그래밍 원칙 준수**
|
||||
- `to_utc_aware()` 같은 순수 함수로 분리
|
||||
- 부작용 없이 테스트 가능한 코드
|
||||
- 하드코딩 없는 재사용 가능한 로직
|
||||
|
||||
### 4. **스크롤 UX는 세심하게**
|
||||
- 새 메시지: 맨 아래로 스크롤
|
||||
- 이전 대화: 현재 위치 유지
|
||||
- `requestAnimationFrame`으로 DOM 업데이트 타이밍 맞추기
|
||||
|
||||
### 5. **디버깅 순서**
|
||||
1. 브라우저 Network 탭에서 실제 요청/응답 확인
|
||||
2. 서버 로그로 에러 확인
|
||||
3. 간단한 테스트 코드로 로직 검증
|
||||
4. 수정 후 전체 플로우 재테스트
|
||||
|
||||
## 최종 결과
|
||||
- 타임존 버그 해결 → 8월 16, 17일 대화 정상 로드
|
||||
- 스크롤 위치 유지 → 사용자 경험 개선
|
||||
- JWT 인증 경로 정상화 → 보안 강화
|
||||
|
||||
---
|
||||
|
||||
*작성 시간: 2025년 8월 19일 오전 12시 30분*
|
||||
*관련 커밋: rb10508_micro(d6e9044), frontend-customer(9e01f72)*
|
||||
Loading…
x
Reference in New Issue
Block a user