DOCS/plans/251114_skill_calendar_multiplatform_integration.md
Claude-51124 beae8d30b3 docs: skill-calendar Phase 5 완료 (approval 로직)
- 컨텍스트 기반 긍정 응답 감지 (그래/ㅇㅇ/네/예)
- _confirm → _approval 전환 (10분 시간 제약)
- calendar_handler.py 구현 (일정 파싱 + CalendarSkill 호출)
- TDD 테스트 10/10 통과
- 전체 플로우 완성 (Gmail 토큰만 남음)
2025-11-14 17:13:49 +09:00

9.3 KiB

skill-calendar 멀티플랫폼 캘린더 통합 스킬

작성일: 2025-11-14 작성자: Claude 목적: Google/Slack/네이버웍스 캘린더 통합 일정 관리


1. 비즈니스 시나리오

사용자 대화 플로우

사용자: "11월 24일 검진
       인천 연수구 갯벌로156
       한국생산기술연구원 200명(의사2인)
       07:40~약12시"

로빙: "11월 24일 07:40~12시 검진 일정을 구글 캘린더에 등록해드릴까요?"

사용자: "그래"

로빙: "구글 캘린더에 등록 완료했습니다.
      제목: 한국생산기술연구원 검진
      일시: 2025-11-24 07:40~12:00
      장소: 인천 연수구 갯벌로156"

요구사항

  1. 사용자(김종태, UUID: 53529291-5050-4daa-89fb-008b546feb63) 식별
  2. 51123 서버 DB에서 gmail_token 테이블 조회 → Google OAuth 토큰 획득
  3. Google Calendar API로 일정 등록
  4. rb8001 ChromaDB에 메모리 저장 (이후 "11월 24일 뭐하지?" 질문에 답변 가능)

2. 아키텍처

서비스 구조

rb8001 (51124)
  ↓ POST /api/events
skill-calendar (51124, 포트 8512)
  ↓ SELECT * FROM gmail_token WHERE user_id=?
PostgreSQL main_db (51123)
  ↓ Google Calendar API
Google Calendar (외부)

멀티 프로바이더 지원

  • GoogleCalendarService: gmail_token 테이블 사용
  • SlackCalendarService: slack_token 테이블 사용 (Slack 타임라인 기능)
  • NaverWorksCalendarService: naverworks_token 테이블 사용

3. DB 스키마 (51123 서버 main_db)

기존 테이블 활용

  • gmail_token: Google OAuth 토큰 (Calendar API scope 포함)
  • slack_token: Slack OAuth 토큰
  • naverworks_token: 네이버웍스 OAuth 토큰

신규 테이블 (선택)

-- 캘린더 이벤트 메타데이터 (선택사항, 동기화 추적용)
CREATE TABLE IF NOT EXISTS calendar_events (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES "user"(id),
  provider VARCHAR(50) NOT NULL,  -- 'google', 'slack', 'naverworks'
  external_event_id VARCHAR(255) NOT NULL,  -- 외부 API의 event_id
  title TEXT,
  start_time TIMESTAMP NOT NULL,
  end_time TIMESTAMP NOT NULL,
  location TEXT,
  description TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  UNIQUE(user_id, provider, external_event_id)
);

4. skill-calendar API 설계

포트 및 환경변수

  • PORT: 8512
  • DATABASE_URL: postgresql://robeings:robeings@192.168.219.45:5432/main_db

API 엔드포인트

POST /api/events

일정 등록

요청:

{
  "user_id": "53529291-5050-4daa-89fb-008b546feb63",
  "provider": "google",  // "google", "slack", "naverworks"
  "title": "한국생산기술연구원 검진",
  "start": "2025-11-24T07:40:00",
  "end": "2025-11-24T12:00:00",
  "location": "인천 연수구 갯벌로156",
  "attendees": ["lee.jh@example.com"]  // 선택
}

응답:

{
  "event_id": "abc123xyz",
  "provider": "google",
  "calendar_url": "https://calendar.google.com/calendar/event?eid=..."
}

GET /api/events

일정 조회 (날짜 범위)

쿼리: ?user_id=UUID&provider=google&start_date=2025-11-24&end_date=2025-11-24

DELETE /api/events/{event_id}

일정 삭제


5. rb8001 통합

의도 감지

  • app/brain/decision_engine.py: "calendar_event" 의도 추가
  • 키워드: "일정", "캘린더", "등록", 날짜 패턴 (YYYY-MM-DD, MM월 DD일)

스킬 호출

  • app/skills/calendar_skill.py (신규 생성)
  • rb8001 → skill-calendar API 호출
  • 환경변수: SKILL_CALENDAR_URL=http://localhost:8512

메모리 저장

  • ChromaDB: "11월 24일 검진 일정 등록됨" 저장
  • Neo4j: event 노드 생성 (선택)

6. TDD 테스트 계획

테스트 파일

  • skill-calendar/tests/test_google_calendar_integration.py
  • rb8001/tests/test_calendar_intent_detection.py

시나리오 1: 구글 캘린더 일정 등록

Given: 김종태(user_id) gmail_token 존재
When: POST /api/events (제목, 날짜, 시간, 장소)
Then:
  - Google Calendar API 호출 성공
  - event_id 반환
  - calendar_events 테이블 저장 (선택)

시나리오 2: rb8001 의도 감지 및 2단계 대화

Given: "11월 24일 검진..." 메시지 입력
When: rb8001 의도 분석
Then:
  - intent="calendar_event" 감지
  - entities={날짜, 시간, 장소} 추출
  - "일정 등록해드릴까요?" 응답
  - 다음 메시지 "그래" 입력  skill-calendar 호출

7. 구현 순서

Phase 1: skill-calendar 기본 뼈대 (2시간)

  1. skill-calendar 디렉토리 생성 (Gitea 레포 연동)
  2. FastAPI 앱 구조 생성
  3. GoogleCalendarService 클래스 구현
  4. POST /api/events 엔드포인트 구현
  5. DB 연결 (51123 main_db)

Phase 2: Google Calendar API 통합 (1시간)

  1. gmail_token 테이블 조회 로직
  2. google-api-python-client로 Calendar API 호출
  3. 토큰 갱신 로직 (skill_email 패턴 참조)
  4. 에러 처리 (401, 403, 429)

Phase 3: rb8001 통합 (1시간)

  1. app/skills/calendar_skill.py 생성
  2. app/brain/decision_engine.py에 calendar_event 의도 추가
  3. 2단계 대화 플로우 (확인 → 실행)
  4. ChromaDB 메모리 저장

Phase 4: TDD 테스트 (1시간)

  1. test_google_calendar_integration.py 작성
  2. Mock 테스트 (Calendar API)
  3. E2E 테스트 (실제 토큰 사용)

Phase 5: 배포 및 검증 (30분)

  1. docker-compose.yml 작성
  2. Gitea Actions 설정
  3. 실제 시나리오 테스트 (김종태 계정)

8. 참고 문서

  • DOCS/troubleshooting/250917_네이버웍스_캘린더_API_연동_가이드.md
  • DOCS/troubleshooting/250820_happybell80_Gmail패스포트시스템완성.md
  • skill_email/services/gmail_service.py:38-83 (Gmail API 패턴)
  • rb8001/app/services/naverworks_file_processor.py (스킬 호출 패턴)

9. 제약사항

Google Calendar API

  • Scope: calendar.events (gmail_token에 이미 포함 여부 확인 필요)
  • Quota: 무료 tier 하루 1백만 요청 (충분)
  • Auth: OAuth 2.0 (skill_email과 동일 토큰 공유)

보안

  • 51123 DB 접근: read-only 권장 (gmail_token 조회만)
  • 토큰 갱신: skill_email 패턴 따름
  • CORS: rb8001에서만 호출 (내부 네트워크)


10. 구현 현황

Phase 1: 기본 뼈대 구현 완료 (2025-11-14)

Git 레포: https://git.ro-being.com/ivada_Ro-being/skill-calendar.git
커밋: 15bcd9c
구현 파일:

  • services/google_calendar_service.py: Gmail 토큰 조회 + Calendar API
  • routers/calendar.py: POST/GET/DELETE /api/events
  • tests/test_google_calendar_integration.py: TDD 테스트 (Red Phase)
  • main.py: FastAPI 앱 (포트 8512)
  • docker-compose.yml: 51123 DB 연결

TDD 상태:

  • Import 성공
  • gmail_token 조회 성공
  • Calendar API 호출: invalid_grant (토큰 만료 또는 calendar scope 부족)

Phase 2: Docker 배포 및 rb8001 통합 완료 (2025-11-14)

skill-calendar:

  • Docker 빌드 성공
  • 컨테이너 시작 (포트 8512, healthy)
  • Gitea Actions 자동 배포 설정

rb8001 통합:

  • app/skills/calendar_skill.py 생성
  • SKILL_CALENDAR_URL=http://localhost:8512 추가
  • Git 푸시 완료 (커밋 7c00027)

Phase 3: rb8001 의도 감지 완료 (2025-11-14)

decision_engine 통합:

  • IntentType.CALENDAR_EVENT 추가
  • 날짜+시간 패턴 매칭 (11월 24일 07:40 등)
  • skill_sequences에 calendar_confirm 액션 추가
  • 테스트: "11월 24일 검진..." → calendar_event (신뢰도 0.9)
  • Git 푸시 완료 (커밋 477fd1c)
  • rb8001 재배포 완료

현재 동작:

  1. 사용자: "11월 24일 검진..." 입력
  2. decision_engine: calendar_event 의도 감지 (0.9)
  3. LLM: 일정 정보 파싱 및 확인 메시지 생성

Phase 4: calendar_confirm LLM 처리 완료 (2025-11-14)

LLM 통합:

  • LLMRequest task_type에 'calendar_confirm' 추가
  • llm_service.py에 calendar_confirm 처리 로직 구현
  • 시스템 프롬프트: 날짜/시간/장소 파싱 및 확인 메시지 생성
  • Git 푸시 완료 (커밋 8fb94d9)
  • rb8001 재배포 완료

현재 동작:

  1. 사용자: "11월 24일 검진 07:40~12시..." 입력
  2. decision_engine: calendar_event 의도 감지 (0.9)
  3. LLM (calendar_confirm): 일정 정보 파싱 → "일정을 구글 캘린더에 등록해드릴까요?" 응답

Phase 5: approval 로직 및 CalendarSkill 호출 완료 (2025-11-14)

컨텍스트 기반 approval:

  • analyze_intent()에 context 매개변수 추가
  • 긍정 응답("그래/ㅇㅇ/네/예") 감지 로직
  • _confirm/_request 접미사만 _approval로 전환
  • 10분 시간 제약 적용
  • TDD 테스트 10/10 통과

calendar_handler.py:

  • LLM 응답에서 일정 정보 파싱 (날짜, 시간, 장소, 제목)
  • CalendarSkill.create_event() 호출
  • 성공 메시지 생성
  • Git 푸시 완료 (커밋 b4495c3)
  • rb8001 재배포 완료

전체 플로우 완성:

  1. 사용자: "11월 24일 검진 07:40~12시..." 입력
  2. calendar_event 감지 (0.9) → calendar_confirm
  3. 로빙: "일정을 구글 캘린더에 등록해드릴까요?"
  4. 사용자: "그래"
  5. calendar_approval 감지 (0.95) → create_event
  6. CalendarSkill → skill-calendar API → Google Calendar
  7. 로빙: " 구글 캘린더에 일정을 등록했습니다!"

남은 작업:

  1. Gmail Passport calendar scope 재연동 (invalid_grant 해결)
  2. E2E 실제 테스트