All checks were successful
Build and Deploy Teams Planner Bot / build-and-run (push) Successful in 14s
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)
-
Azure AD 앱 등록 (Graph 위임 권한)
- Azure Portal → App registrations → New
- API permissions → Microsoft Graph → Delegated:
Tasks.ReadWriteGroup.Read.AllUser.Readoffline_access
- Grant admin consent
- Certificates & secrets → Client secret 발급
- 노트:
tenantId,clientId,clientSecret
-
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
- Name:
- "Test Connection" 으로 토큰이 떨어지는지 확인
-
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 관리자 센터(또는 개발자 포털)에서 사이드로딩
로컬 실행
npm install
cp .env.example .env
# .env 채우기
npm run dev
다른 터미널에서 ngrok 등으로 외부 노출:
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)
- 다중 후보일 때 카드의
다음 단계
npm install→ 의존성 받기- Azure AD 앱 등록 + Azure Bot 리소스 + OAuth Connection 설정
.env채우기npm run dev로 띄우고 ngrok 으로 노출- Teams 매니페스트 사이드로딩 → 개인 채팅으로 봇과 대화
"오늘 견적서 초안 작성 시작했어"같은 첫 발화로 테스트
Description
Languages
TypeScript
99.6%
Dockerfile
0.4%