From 51d215f16bdea02155f92d288907ad1b820fdf27 Mon Sep 17 00:00:00 2001 From: Claude-51124 Date: Sun, 16 Nov 2025 09:06:10 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=EB=AC=B8=EC=84=9C=20=EA=B0=84=EC=86=8C?= =?UTF-8?q?=ED=99=94=20(407=EC=A4=84=20=E2=86=92=20111=EC=A4=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...14_gmail_calendar_scope_reconnect_guide.md | 392 +++--------------- 1 file changed, 48 insertions(+), 344 deletions(-) diff --git a/troubleshooting/251114_gmail_calendar_scope_reconnect_guide.md b/troubleshooting/251114_gmail_calendar_scope_reconnect_guide.md index 4b13edf..aef70f4 100644 --- a/troubleshooting/251114_gmail_calendar_scope_reconnect_guide.md +++ b/troubleshooting/251114_gmail_calendar_scope_reconnect_guide.md @@ -1,335 +1,64 @@ -# Gmail Passport Calendar Scope 재연동 가이드 +# Gmail Calendar Scope 및 Timezone 트러블슈팅 -**작성일**: 2025-11-14 +**작성일**: 2025-11-14 ~ 2025-11-16 **작성자**: Claude -**목적**: skill-calendar를 위한 Google Calendar API scope 추가 --- -## 1. 현재 상황 +## 1. Calendar Scope 추가 (2025-11-14) ### 문제 -- skill-calendar가 gmail_token 조회는 성공 -- Google Calendar API 호출 시 `invalid_grant` 에러 발생 -- 원인: 현재 Gmail Passport scope에 Calendar API 권한 없음 +- skill-calendar가 Google Calendar API 호출 시 `invalid_grant` 에러 +- 원인: Gmail Passport scope에 Calendar API 권한 없음 -### 필요한 Scope +### 해결 +**auth-server scope 수정** (`app/providers/gmail_passport.py`): ```python -# 기존 (auth-server/app/providers/gmail_passport.py) -GMAIL_API_SCOPES = [ - "https://www.googleapis.com/auth/gmail.send", - "https://www.googleapis.com/auth/gmail.readonly", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/userinfo.email", - "https://www.googleapis.com/auth/userinfo.profile" -] - -# 추가 필요 -+ "https://www.googleapis.com/auth/calendar", -+ "https://www.googleapis.com/auth/calendar.events" -``` - ---- - -## 2. 재연동 방법 - -### 방법 1: auth-server scope 수정 후 재인증 (권장) - -#### Step 1: auth-server scope 수정 -```bash -# 51123 서버 접속 (auth-server는 51123에서 실행) -ssh admin@192.168.219.45 - -# auth-server 디렉토리로 이동 -cd /home/admin/auth-server - -# gmail_passport.py 수정 -vi app/providers/gmail_passport.py -``` - -**수정 내용**: -```python -# Line 찾아서 수정 (대략 30-40줄) GMAIL_API_SCOPES = [ "https://www.googleapis.com/auth/gmail.send", "https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/gmail.modify", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", - "https://www.googleapis.com/auth/calendar", # 추가 - "https://www.googleapis.com/auth/calendar.events" # 추가 + "https://www.googleapis.com/auth/calendar", # 추가 + "https://www.googleapis.com/auth/calendar.events" # 추가 ] ``` -#### Step 2: auth-server 재배포 +**재배포 및 재인증**: ```bash -# Git 커밋 +cd /home/admin/auth-server git add app/providers/gmail_passport.py -git commit -m "feat: Gmail Passport에 Calendar scope 추가" +git commit -m "feat: Calendar scope 추가" git push origin main - -# Gitea Actions가 자동 배포 (30초 소요) -# 또는 수동 배포: -docker compose restart ``` -#### Step 3: 사용자별 재인증 - -**웹 브라우저에서**: -1. https://ro-being.com 로그인 (김종태 계정) -2. 설정 > 아이템 > Gmail -3. "재인증" 버튼 클릭 -4. Google 권한 동의 화면에서 Calendar 권한 확인 -5. "허용" 클릭 -6. 자동으로 인벤토리 페이지로 리다이렉트 -7. gmail_token 테이블에 새로운 scope 저장됨 - -**확인**: -```bash -# 51124 서버에서 -cd /home/admin/ivada_project/skill-calendar -python3 tests/test_google_calendar_integration.py -``` - -### 방법 2: DB 직접 수정 (비권장, 임시) - -#### 주의 -- OAuth 토큰은 발급 시 scope가 고정됨 -- DB만 수정해도 Google API는 scope 부족으로 거부 -- 반드시 재인증 필요 - -#### 확인용 쿼리 -```sql --- 현재 scope 확인 -SELECT user_id, scopes FROM gmail_token -WHERE user_id = '53529291-5050-4daa-89fb-008b546feb63'; - --- scope 추가 (효과 없음, 재인증 필요) -UPDATE gmail_token -SET scopes = scopes || '["https://www.googleapis.com/auth/calendar"]'::jsonb -WHERE user_id = '53529291-5050-4daa-89fb-008b546feb63'; -``` +웹에서 Gmail 재인증 → Google 권한 동의 → Calendar scope 확인 → 허용 --- -## 3. Google Cloud Console 설정 확인 +## 2. Calendar CRUD Timezone 이슈 (2025-11-16) -### OAuth 동의 화면 - Calendar Scope 추가 (중요!) +### 문제 +- **CREATE**: 성공 +- **READ**: 방금 등록한 일정 조회 실패 +- **DELETE**: 성공하지만 잘못된 날짜 표시 -**현재 상태**: Gmail scope만 있음 (gmail.modify, userinfo.email 등) - -**추가 절차**: -1. https://console.cloud.google.com/apis/credentials/consent -2. 화면 하단 "범위 추가 또는 삭제" 버튼 클릭 -3. 필터에서 "calendar" 검색 -4. 다음 2개 체크: - - ✅ `.../auth/calendar` - 캘린더 보기, 수정, 공유, 영구 삭제 - - ✅ `.../auth/calendar.events` - 캘린더 일정 보기 및 수정 -5. "업데이트" 버튼 클릭 -6. "저장 후 계속" 클릭 -7. 완료 확인: "민감한 범위" 또는 "제한된 범위"에 Calendar 표시됨 - -### API 활성화 -1. "API 및 서비스" > "라이브러리" -2. "Google Calendar API" 검색 -3. "사용 설정" 클릭 (이미 활성화되어 있을 수 있음) - ---- - -## 4. 테스트 시나리오 - -### E2E 테스트 -``` -1. auth-server scope 수정 완료 -2. 김종태 계정 Gmail 재인증 -3. ro-being.com 로그인 -4. 로빙에게 메시지: "11월 24일 검진 07:40~12시 인천 연수구 갯벌로156" -5. 로빙 응답: "일정을 구글 캘린더에 등록해드릴까요?" -6. 사용자 응답: "그래" -7. 로빙 응답: "✅ 구글 캘린더에 일정을 등록했습니다!" -8. Google Calendar 웹에서 확인: 2025-11-24 07:40~12:00 일정 존재 -``` - ---- - -## 5. 트러블슈팅 - -### invalid_grant 계속 발생 -- Gmail Passport 재인증 확인 -- gmail_token.scopes 필드에 calendar 포함 확인 -- access_token 갱신 시도 (refresh_token 사용) - -### Calendar API 403 Forbidden -- Google Cloud Console에서 Calendar API 활성화 확인 -- OAuth 동의 화면에 Calendar scope 추가 확인 - -### 일정 등록 성공했지만 Calendar에 없음 -- 다른 Google 계정으로 로그인했을 가능성 -- primary calendar 대신 다른 캘린더 ID 사용 여부 확인 - ---- - -## 6. 참고 문서 - -- DOCS/troubleshooting/250820_happybell80_Gmail패스포트시스템완성.md -- DOCS/plans/251114_skill_calendar_multiplatform_integration.md -- Google Calendar API: https://developers.google.com/calendar/api/guides/overview - ---- - ---- - -## 7. 테스트 결과 (2025-11-14) - -### Calendar Scope 추가 성공 ✅ -- auth-server에 calendar scope 추가 완료 -- 김종태 계정 Gmail 재인증 완료 -- Google Cloud Console Calendar API 활성화 완료 -- skill-calendar → Google Calendar API 이벤트 생성 성공 - -### Calendar 통합 테스트 결과 ⚠️ - -#### 성공 케이스 (4/10) -- ✅ "11월 30일 오후 2시 서울역에서 클라이언트 **미팅**" → calendar_event 감지됨 -- ✅ "11월 18일 오전 11시 사무실에서 **회의**" → calendar_event 감지됨 -- ✅ skill-calendar API 직접 호출 시 정상 작동 -- ✅ Google Calendar에 실제 이벤트 생성 확인 - -#### 실패 케이스 (6/10) -- ❌ "11월 20일 오후 3시에 팀 미팅" → intent 감지 실패 (LLM으로 우회) -- ❌ "11월 23일 오후 3시 **카페**" → intent 감지 실패 ("카페"는 패턴에 없음) -- ❌ "11월 18일 14시 개발팀 **스프린트**" → intent 감지 실패 ("스프린트"는 패턴에 없음) -- ❌ 승인 응답 ("네", "좋아", "ㅇㅇ") → approval로 변환 안됨 (컨텍스트 비어있음) - -### 근본 원인 분석 - -#### 1. Intent 패턴 부족 +### 원인 +naive datetime (timezone 없음) 사용: ```python -# decision_engine.py의 calendar_event 패턴 -IntentType.CALENDAR_EVENT: [ - r"\d+월\s*\d+일.*(검진|미팅|회의|회식|약속|일정)", # 현재 - # 부족: 카페, 스프린트, 약속, 미팅, 회의, 점심, 저녁, 피팅 등 -] -``` - -**문제**: 일정 키워드가 제한적이라 다양한 표현 감지 못함 -**해결**: 패턴 확장 + LLM fallback 활용 - -#### 2. Recent Conversations 로딩 실패 -``` -[DecisionEngine] 의도 분석 시작: '네' -Loaded 0 recent conversations for user ... -[Approval] 직전 intent 없음 → UNKNOWN -``` - -**문제**: -- PostgreSQL `conversation_log_pk` 중복 키 에러 발생 중 -- 따라서 conversation_log에 저장이 안 되고, 조회도 빈 배열 -- approval 로직은 recent_conversations에 의존하므로 작동 불가 - -**근본 원인**: -- `conversation_log` 테이블의 `id` 시퀀스가 out-of-sync -- 이미 존재하는 id (1149, 1151, 1153 등)를 insert하려고 시도 - -**해결 방안**: -```sql --- 51123 서버에서 -SELECT MAX(id) FROM conversation_log; -- 현재 최대값 확인 -SELECT nextval('conversation_log_id_seq'); -- 시퀀스 현재값 확인 --- 시퀀스를 MAX(id) + 1로 재설정 -SELECT setval('conversation_log_id_seq', (SELECT MAX(id) FROM conversation_log) + 1); -``` - -### 개선 사항 - -#### 우선순위 1: DB 시퀀스 수정 (필수) -- 없이는 approval 로직 완전 불능 -- PostgreSQL 시퀀스 재정렬 필요 - -#### 우선순위 2: Intent 패턴 확장 -```python -IntentType.CALENDAR_EVENT: [ - # 기존 - r"\d+월\s*\d+일.*(검진|미팅|회의|회식|약속|일정)", - # 추가 - r"\d+월\s*\d+일.*\d{1,2}시", # 시간만 있으면 일정으로 간주 - r"(내일|모레|다음주).*(시|점심|저녁|미팅|회의|약속)", - r"\d+월\s*\d+일", # 날짜만 있어도 일정 가능성 고려 -] -``` - -#### 우선순위 3: LLM Fallback 강화 -- calendar_confirm이 이미 LLM 기반으로 파싱 수행 -- Intent 감지 실패 시 LLM에게 "일정인가?" 질문 후 calendar_confirm 호출 - ---- - -**작업 완료**: Gmail Calendar 재인증 성공, skill-calendar API 작동 확인 -**다음 단계**: -1. PostgreSQL `conversation_log` 시퀀스 수정 (필수) -2. calendar_event 패턴 확장 (선택) -3. 전체 E2E 재테스트 - ---- - -## 8. 추가 관찰 (2025-11-14 19:00) - -### 신규 개선 사항 -- `conversation_log` 조회 시 intent 값 포함 → approval 로직이 다시 작동하여 `calendar_approval → create_event` 흐름이 복구됨 -- `calendar_handler`가 `calendar_confirm` 대화 기록을 직접 찾고, Markdown 필드가 없어도 날짜/시간/장소를 추출하도록 보완함 -- Slack/Frontend에서 들어온 승인 메시지(네/좋아/ㅇㅋ 등)는 즉시 캘린더 이벤트 생성으로 이어지고 Google Calendar에도 등록 확인 - -### 남은 문제 -- 승인 직후에도 LLM fallback이 한 번 더 호출되어 “응답을 생성할 수 없습니다.” 메시지가 덧붙음 → approval 분기에서 LLM 재호출을 막아야 함 -- 동일한 일정 문구를 반복 입력하면 매번 새로운 이벤트가 생성됨 → 일정 중복 체크 로직 필요 -- 문서화 미완료: 위 보완 사항을 정리했으나, Slack/Frontend 사용자 가이드는 아직 업데이트되지 않음 (향후 DOCS/guide 추가 필요) - -### 후속 TODO -1. approval 완료 후에는 LLM을 재호출하지 않고 "등록 완료" 응답을 직접 반환 -2. 일정 중복 감지(최근 N분 내 같은 날짜/시간이면 안내만) 기능 추가 -3. 사용자용 가이드 문서(DOCS/guide)에 승인 흐름 및 실패 메시지 내용을 반영 - ---- - -## 9. Calendar CRUD Timezone 이슈 해결 (2025-11-16) - -### 문제 상황 -- **CREATE**: 일정 등록 성공 (event_id 반환, Google Calendar 확인됨) -- **READ**: 방금 등록한 일정 조회 실패 ("11월 17일에 등록된 일정이 없습니다") -- **DELETE**: 삭제는 성공하지만 잘못된 날짜 표시 ("2025-11-18 00:00" 대신 "2025-11-17 15:00"이어야 함) - -### 근본 원인 -```python -# 문제: naive datetime (timezone 없음) 사용 +# 문제 start_iso = f"{date}T{start_hour}:{start_min}:00" # "2025-11-17T15:00:00" -end_iso = f"{date}T{end_hour}:{end_min}:00" # "2025-11-17T16:00:00" -# Google Calendar API는 timezone 없는 datetime을 어떻게 해석할지 불확실 -# skill-calendar 서비스가 Asia/Seoul로 해석하지만, -# rb8001에서 보내는 query datetime은 naive여서 매칭 실패 +# Google Calendar API는 timezone 없으면 해석 불확실 +# rb8001 → skill-calendar 전송 시 timezone 불일치 ``` -### 증상 -1. **CREATE API 호출**: - - 전송: `{"start": "2025-11-17T15:00:00", "end": "2025-11-17T16:00:00"}` - - Google Calendar: Asia/Seoul timezone으로 저장됨 +### 해결 +**rb8001/app/router/calendar_handler.py 수정**: -2. **READ API 호출**: - - 전송: `{"start_date": "2025-11-17T00:00:00", "end_date": "2025-11-17T23:59:59"}` - - skill-calendar: 이 datetime을 어떤 timezone으로 해석? - - 결과: 조회 실패 (timezone 불일치) - -### 해결 방법 - -#### 수정 파일: `rb8001/app/router/calendar_handler.py` - -**1. parse_time_range() 함수 (Line 397-432)** +**parse_time_range()** (Line 397): ```python -# Before -start_iso = f"{date}T{start_hour.zfill(2)}:{start_min}:00" -end_iso = f"{date}T{end_hour.zfill(2)}:{end_min}:00" - -# After from datetime import datetime from zoneinfo import ZoneInfo @@ -340,67 +69,42 @@ start_dt = datetime(year, month, day, int(start_hour), int(start_min), 0, tzinfo end_dt = datetime(year, month, day, int(end_hour), int(end_min), 0, tzinfo=tz) return start_dt.isoformat(), end_dt.isoformat() -# Result: "2025-11-17T15:00:00+09:00", "2025-11-17T16:00:00+09:00" +# "2025-11-17T15:00:00+09:00" ``` -**2. handle_calendar_query() 함수 (Line 228-312)** +**handle_calendar_query()** (Line 228): ```python -# Before -today = datetime.now() -target_date = datetime(year, month, day) - -# After -from zoneinfo import ZoneInfo - today = datetime.now(ZoneInfo("Asia/Seoul")) target_date = datetime(year, month, day, tzinfo=ZoneInfo("Asia/Seoul")) - -start_time = target_date.replace(hour=0, minute=0, second=0) -end_time = target_date.replace(hour=23, minute=59, second=59) -# Result: start_time.isoformat() = "2025-11-17T00:00:00+09:00" ``` ### 테스트 결과 +**Before (67%)**: +- ✅ CREATE +- ❌ READ (조회 실패) +- ✅ DELETE -**CRUD 테스트 (test_calendar_crud_proper.py)**: -```bash -docker exec rb8001 python3 /code/test_calendar_crud_proper.py -``` +**After (100%)**: +- ✅ CREATE +- ✅ READ (조회 성공) +- ✅ DELETE (정확한 날짜 표시) -**Before (67% 통과)**: -``` -✅ PASS CREATE -❌ FAIL READ - "11월 17일에 등록된 일정이 없습니다" -✅ PASS DELETE -통과율: 2/3 (67%) -``` +--- -**After (100% 통과)**: -``` -✅ PASS CREATE -✅ PASS READ - "11월 17일 일정: • 15:00 TDD 테스트 일정" -✅ PASS DELETE - "TDD 테스트 일정 (2025-11-17 15:00)" -통과율: 3/3 (100%) -``` +## 3. 교훈 -### 교훈 - -#### 1. Datetime은 항상 timezone-aware로 -- Python에서 `datetime.now()` 대신 `datetime.now(ZoneInfo("Asia/Seoul"))` 사용 -- ISO 8601 전송 시 반드시 timezone offset 포함 (`+09:00`) -- Google Calendar API는 timezone 정보 없으면 예측 불가능하게 동작 - -#### 2. Microservice 간 datetime 전송 규칙 +### Datetime 규칙 - **절대 금지**: naive datetime (timezone 없음) -- **권장**: ISO 8601 with timezone (`2025-11-17T15:00:00+09:00`) -- **대안**: UTC로 통일 후 각 서비스에서 로컬 변환 +- **필수**: `datetime.now(ZoneInfo("Asia/Seoul"))` +- **전송**: ISO 8601 with timezone (`2025-11-17T15:00:00+09:00`) -#### 3. 테스트 시 timezone 검증 필수 -- CREATE/READ/DELETE 모두 같은 timezone 기준 사용 확인 -- 컨테이너 시스템 timezone과 코드 timezone 일치 여부 확인 -- `docker exec rb8001 date` → "KST" 확인 +### Microservice 간 통신 +- 모든 datetime은 timezone offset 포함 +- UTC 통일 또는 명시적 timezone 사용 +- 컨테이너 시스템 timezone 확인: `docker exec [컨테이너] date` -### 관련 커밋 +--- + +## 4. 관련 커밋 - `4cd0990`: fix: Add timezone awareness to calendar operations - `fd7ec1c`: Revert README.md documentation changes -