운영자 broadcast (Teams DM)
AI 요청 프롬프트
https://docs.axelabs.ai/ops/runbook/operator-broadcast 따라
임직원 [수신자 email list] 에게 다음 공지 broadcast 해줘:
[공지 본문 paste]
진행:
1. 본 페이지의 Prereq 확인 (Blueprint LIVE + CRON_SECRET 접근 가능)
2. Step 1..4 순서대로 — 매 step 결과 받고 다음
3. 함정 발생 시 페이지 "함정 정리" 표 따라 우회
4. Step 4 결과 (3 messageId) 받으면 종료 + Ship Log 한 줄 (선택)본인 AI session = Claude Code / Cursor / ChatGPT 데스크탑 / Claude.app / 기타.
페이지 본문 = 사람이 직접 read 도 가능, AI 도 참고. AI 가 본 페이지 fetch 후 위 진행 순서대로 사용자와 step-by-step interactive 풀어나감.
Prereq
- 운영자 자격 (AXE org Owner — 본 broadcast 가 정당 operational 공지인지 본인 판단)
- axe-macmini 에서 실행 (Blueprint LIVE 가
http://blueprint.local:3100으로 접근 가능) /Users/axe/blueprint/.env의CRON_SECRET환경변수 존재 (Blueprint deploy 시 자동 set)- 수신자 email list (
@axellc.com도메인 — 운영자 자체 broadcast 가 cross-tenant 안 함) - 본문 = plain text 또는 escaped html (default text — 권장)
Step 1: 사전 확인 (Blueprint LIVE + CRON_SECRET + bot identity)
# (a) Blueprint health
curl -sf -o /dev/null -w 'blueprint http=%{http_code}\n' http://blueprint.local:3100/api/health
# (b) CRON_SECRET 길이 (값 출력 X)
SECRET=$(grep '^CRON_SECRET=' /Users/axe/blueprint/.env | cut -d= -f2- | tr -d '"' | tr -d "'")
echo "secret_len=${#SECRET}"
# (c) bot identity = ai@ 인지 self-DM 거부 응답으로 검증 (실제 메시지 발송 X)
curl -sf -X POST http://blueprint.local:3100/api/admin/broadcast-dm \
-H "Authorization: Bearer $SECRET" \
-H 'Content-Type: application/json' \
-d '{"emails":["[email protected]"],"text":"self-test","contentType":"text"}' \
| jq '.results[0]'
# 기대: {email:"[email protected]", status:"skipped", reason:"target AAD id matches bot — refusing self-DM"}
# → reason 안에 "matches bot" 보이면 bot = ai@ 정상3개 다 통과해야 진행. 실패 시 함정 표 참조.
Step 2: 본문 + payload JSON 작성
본문 = plain text (default contentType). 줄바꿈 \n, 특수문자 escape 불필요 (text mode 라 client 가 그대로 렌더). bullet 은 - 또는 • 등 plain.
# 본문을 한 변수에 — heredoc 이 가독성 ↑
BODY=$(cat <<'EOF'
[제목 1줄]
[본문 내용]
- bullet 1
- bullet 2
링크: https://...
EOF
)
# payload JSON 작성 (jq 가 \n + 특수문자 자동 escape)
EMAILS_JSON='["[email protected]","[email protected]","[email protected]"]'
jq -n --argjson emails "$EMAILS_JSON" --arg text "$BODY" \
'{emails:$emails, contentType:"text", text:$text}' > /tmp/bcast.json
# 확인 (수신자 + 본문 길이만 — 본문 풀 출력 안 함)
jq '{emails, text_len: (.text | length)}' /tmp/bcast.jsonStep 3: POST 호출
SECRET=$(grep '^CRON_SECRET=' /Users/axe/blueprint/.env | cut -d= -f2- | tr -d '"' | tr -d "'")
curl -s -X POST http://blueprint.local:3100/api/admin/broadcast-dm \
-H "Authorization: Bearer $SECRET" \
-H 'Content-Type: application/json' \
-d @/tmp/bcast.json \
-w '\nHTTP_%{http_code}\n'기대 응답:
{
"summary": {"total":3, "sent":3, "skipped":0, "error":0},
"results": [
{"email":"[email protected]", "status":"sent", "chatId":"19:[email protected]", "messageId":"1779..."},
{"email":"[email protected]", "status":"sent", "chatId":"19:...", "messageId":"1779..."},
{"email":"[email protected]", "status":"sent", "chatId":"19:...", "messageId":"1779..."}
]
}sent=3 + HTTP 200 = 정상. cleanup:
rm -f /tmp/bcast.jsonStep 4: 결과 검증 + Ship Log (선택)
각 수신자가 Teams 앱 (phone + desktop) 에서 [email protected] 로부터 1:1 DM push 알림 받았는지 본인이 확인 (수신자 회신 또는 운영자 본인 Teams 의 sent items 확인).
운영 회고용 Ship Log 한 줄 (broadcast 가 의미 있는 일이면 — vault 공지 / 신규 customer launch 등):
| YYYY-MM-DD HH:MM | broadcast (axe org) | (operator action) | **broadcast title** — 3 임직원 (soohun/taehun/jinwoo) Teams DM 발송. broadcast-dm REST + bot ai@. 본문 핵심: [한 줄 요약]. messageId: 1779..., 1779..., 1779... |추가하면 /Users/axe/axelabs-docs/content/ops/updates.mdx Ship Log 표 최상단에 한 줄. axe ship docs 로 배포.
함정 정리
| # | 증상 | 원인 | 우회 |
|---|---|---|---|
| 1 | 외부 7cb41f76 MCP 의 노출 tool list 에 send_mail / send_email / graph_send_email 없음 | 의도된 분리 — Blueprint 의 32+ graph_* tool 중 send 계열은 blueprint-graph 내부 MCP 에만 등록, 외부 connector 는 read-only 격리 | 본 페이지의 broadcast-dm REST 사용 (admin 채널 별도) |
| 2 | az rest --uri /me/sendMail → 403 Forbidden ErrorAccessDenied | az CLI 의 first-party app (04b07795) 이 Mail.Send scope 받을 권한 없음 (Microsoft 자사 앱 간 consent preauthorization 정책) | az CLI 경유 mail send 영구 불가 — broadcast-dm 또는 Outlook 수동 |
| 3 | az account get-access-token --scope https://graph.microsoft.com/Mail.Send → AADSTS65002 | (#2 와 동일 root cause) | (#2 와 동일) |
| 4 | /api/admin/broadcast-dm → {status:"skipped", reason:"target AAD id matches bot — refusing self-DM"} | bot identity = [email protected] — 본인에게 DM 시도 거부 | 수신자 list 에서 ai@ 제거. 또는 self-test 용도 (Step 1 의 (c)) 일부러 의도적 |
| 5 | {status:"skipped", reason:"no AAD object id for user"} | 수신자가 Blueprint 에 한 번도 로그인한 적 없음 — NextAuth callback 의 User.aadObjectId populate 안 됨 | 수신자가 https://blueprint.axelabs.ai 1회 SSO 로그인 → 자동 fill → 재시도 |
| 6 | 401 Unauthorized | CRON_SECRET 헤더 잘못 / .env 에 미설정 / Bearer prefix 빠짐 | Authorization: Bearer $SECRET 정확. .env 의 CRON_SECRET 값 직접 변수에 |
| 7 | Connection refused http://blueprint.local:3100 | Blueprint 미실행 (PC 부팅 직후 / launchd 미가동) | ps aux | grep blueprint 확인, 필요 시 launchctl kickstart -k gui/$(id -u)/com.axe.blueprint |
| 8 | 본문 줄바꿈 깨짐 (Teams 한 줄로 표시) | contentType: "html" 인데 plain text 넣음 — <br> 없으니 collapse | contentType: "text" 명시 (default 권장) |
| 9 | 본문 안 * 강조 등이 안 보임 | Teams 는 markdown 미해석 (text contentType) | bullet 은 - plain, 강조는 대문자 or === 줄 구분 |
| 10 | customer 직원 (@truvia.co.kr 등) 에게 보내려고 시도 → skip | broadcast-dm 의 bot = AXE tenant 의 ai@, cross-tenant chat 생성 불가 | customer 측은 본인 운영자 (Truvia 의 broadcast 채널) 자체 보냄 — sovereignty 원칙 |
관련 use case (참고)
- vault 운영 공지 — KDF rotation / setup 안내 (D-ops-40, 2026-05-26 첫 실 사용)
- 신규 customer launch 안내 — 새 service 가 LIVE 됐을 때
- 시스템 변경 통보 — Blueprint major upgrade, frame schema migration 등
- D-day 직전 사전 안내 — onboard step 차단 가능성 등 사전 경고
NOT for: 일반 잡담 (channel 사용), 1:1 코칭 (Teams 직접 chat), customer 측 공지 (customer 자체 채널).
매 작업 시 사전 작업
| 빈도 | 작업 | 자동화 |
|---|---|---|
| 매 broadcast | Step 1 사전 확인 (Blueprint LIVE + bot identity 검증) | ❌ (사람 판단) |
CRON_SECRET 회전 시 | Blueprint .env + axe-macmini launchd 재시작 | B-blueprint-secret-rotation 참조 |
참조
- D-ops-40 — vault axe.3 release (본 broadcast 의 첫 use case, 2026-05-26)
- /architecture/vault-policies — vault 3 layer 정책 모델 (broadcast 본문 안 참조 patterns)
- /services/blueprint — Blueprint 서비스 개요
src/app/api/admin/broadcast-dm/route.ts— REST 구현src/lib/teams/graph-client.ts— bot Graph client (getSharedClient()가 ai@ 정합)- B-blueprint-broadcast-mail — 실 SMTP email 발송 route 추가 (M5, 사용 빈도 보고 진행)
- /ops/known-gaps — Microsoft 첫 당사자 app consent policy (az CLI Mail.Send 영구 차단)
Last updated on