teams_planner_bot/README.md
윤정민 fd504738eb
All checks were successful
Build and Deploy Teams Planner Bot / build-and-run (push) Successful in 14s
initial: teams planner bot with gemini classifier and docker deploy
2026-05-15 16:53:08 +09:00

112 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Teams Planner Bot
MS Teams 봇. 사용자의 자연어 작업 보고를 LLM으로 분류해서 Microsoft Planner에 자동으로 task를 생성하거나 업데이트한다.
## 동작 개요
```
사용자 (Teams) → 봇 → OAuthPrompt 로그인 (최초 1회)
→ Graph로 본인 Plans/Buckets/최근 Tasks 조회
→ LLM(Claude 또는 Azure OpenAI)에게 발화 + 컨텍스트 전달
→ tool/function call로 {action, planId, ...} JSON 강제 추출
→ Planner Graph API로 create / patch
→ Adaptive Card로 결과 응답
```
## 구성
```
src/
index.ts # restify 서버, CloudAdapter
config/index.ts # 환경변수 로딩/검증
bot/PlannerBot.ts # 메시지 핸들러 + OAuth 다이얼로그 + 오케스트레이션
graph/
graphClientFactory.ts # 사용자 토큰을 받아 Graph Client 생성
plannerClient.ts # Plans/Buckets/Tasks 조회·생성·업데이트 (ETag 처리 포함)
llm/
types.ts # ClassifiedAction 등 공용 타입
prompt.ts # 시스템 프롬프트 + tool/function 스키마
coerce.ts # LLM JSON → ClassifiedAction 검증
claudeClassifier.ts # Anthropic Claude 구현 (tool_use 강제)
azureOpenAiClassifier.ts # Azure OpenAI 구현 (function calling 강제)
factory.ts # LLM_PROVIDER 기반 분기
cards/confirmationCard.ts # 결과 Adaptive Card
appPackage/manifest.json # Teams 앱 매니페스트 (개발자 포털에 업로드)
```
## 사전 준비 (Azure / Microsoft 365)
1. **Azure AD 앱 등록** (Graph 위임 권한)
- Azure Portal → App registrations → New
- API permissions → Microsoft Graph → Delegated:
- `Tasks.ReadWrite`
- `Group.Read.All`
- `User.Read`
- `offline_access`
- Grant admin consent
- Certificates & secrets → Client secret 발급
- 노트: `tenantId`, `clientId`, `clientSecret`
2. **Azure Bot 리소스**
- Azure Portal → Create resource → Azure Bot (Multi Tenant)
- Microsoft App ID/Password 발급 → 노트
- **Configuration → OAuth Connection Settings → Add**
- Name: `GraphConnection` (이 이름이 `.env``OAUTH_CONNECTION_NAME`)
- Service Provider: `Azure Active Directory v2`
- Client id / secret: 1번에서 만든 값
- Tenant ID: 1번의 tenantId
- Token Exchange URL: 비워두기 (SSO 안 쓸 경우)
- Scopes: `Tasks.ReadWrite Group.Read.All User.Read offline_access`
- "Test Connection" 으로 토큰이 떨어지는지 확인
3. **Teams 앱 매니페스트**
- `appPackage/manifest.json``REPLACE_WITH_YOUR_BOT_APP_ID` 를 Azure Bot의 App ID로 치환
- `color.png` (192×192), `outline.png` (32×32) 아이콘을 `appPackage/`에 추가
- 폴더를 zip 으로 압축 → Teams 관리자 센터(또는 개발자 포털)에서 사이드로딩
## 로컬 실행
```bash
npm install
cp .env.example .env
# .env 채우기
npm run dev
```
다른 터미널에서 ngrok 등으로 외부 노출:
```bash
ngrok http 3978
```
ngrok URL을 Azure Bot의 **Messaging endpoint**`https://<ngrok>/api/messages` 형태로 설정.
## LLM 교체
`.env``LLM_PROVIDER` 만 바꾸면 됨:
- `claude``ANTHROPIC_API_KEY`, `CLAUDE_MODEL` 사용
- `azure-openai``AZURE_OPENAI_*` 사용
두 구현 모두 동일한 `LlmClassifier` 인터페이스를 구현하므로 호출부 변경 없음.
## 알아두면 좋을 점 / 함정
- **Planner write는 ETag 필수.** `plannerClient.ts` 가 PATCH 직전 항상 GET으로 ETag를 받아 `If-Match`에 넣는다. 만약 동시 편집이 잦은 환경이면 412 에러를 retry 로 감싸야 한다.
- **`/me/planner/plans` 는 사용자가 속한 그룹의 Plan 만 반환한다.** 봇이 "보이지 않는다" 면 Teams 채널에 그 사용자가 멤버인지부터 확인.
- **OAuthPrompt 의 토큰은 Bot Framework 의 토큰 서비스(token.botframework.com)에 캐시된다.** `logout` 명령으로 강제 갱신 가능.
- **MemoryStorage** 는 개발용. 프로덕션은 CosmosDB/Blob 백엔드로 교체.
- **확장 아이디어**:
- 다중 후보일 때 카드의 `Action.Submit` 으로 사용자가 직접 plan 선택
- Plans/Buckets 캐시 (현재는 매 발화마다 다시 조회)
- 일/주간 요약 발송 (proactive messaging)
## 다음 단계
1. `npm install` → 의존성 받기
2. Azure AD 앱 등록 + Azure Bot 리소스 + OAuth Connection 설정
3. `.env` 채우기
4. `npm run dev` 로 띄우고 ngrok 으로 노출
5. Teams 매니페스트 사이드로딩 → 개인 채팅으로 봇과 대화
6. `"오늘 견적서 초안 작성 시작했어"` 같은 첫 발화로 테스트