o2o-site-AEO/solution/backend/scripts/kakao_event_send_test.py
김성경 983c05b3c3 [feat] solution/backend: 카카오 챗봇 Event API 클라이언트와 테스트 발송 스크립트 (승인 알림 카톡 발송 1단계)
미니블로그 승인 알림을 메일에 더해 연결된 카카오톡으로도 보내기 위한 첫 단계.
승인 방식은 인라인 버튼 + 연결된 계정 신원 확인으로 정했고(링크가 없어 메신저
미리보기가 먼저 열어 승인되는 문제가 없다), 이 커밋은 발송 통로와 규격 확인까지다.

- services/external/kakao_event.py: POST bot-api.kakao.com/v2/bots/{botId}/talk.
  예외 문구(str)에는 키·발화자 ID·응답 원문을 넣지 않고 진단용은 detail 에만 둔다
- KAKAO_BOT_REST_API_KEY 를 기존 KAKAO_REST_API_KEY(카카오 로컬 API)와 갈랐다 —
  Event API 는 채널을 연결한 비즈니스 인증 앱의 키를 써야 해서 앱이 다를 수 있다
- KAKAO_EVENT_DEV=1 이면 봇 ID 뒤에 "!"(개발 채널). KAKAO_BOT_ID 자체는 웹훅이
  bot.id 대조에 쓰므로 고쳐 쓰지 않는다
- scripts/kakao_event_send_test.py: 실제 카톡으로 한 건 보내 규격을 확인하는 스크립트

실제 발송으로 확인함(요청 성공 + 카톡 수신). 이벤트 미배포 시 "Invalid Event name" 404 를
돌려주는 것도 확인했다.

test_kakao_event.py 7건, 카카오·설정 관련 스위트 75 passed
2026-09-29 15:25:06 +09:00

52 lines
2.4 KiB
Python

"""카카오 챗봇 Event API 테스트 발송 — 규격을 실제로 한 번 확인하는 1회성 스크립트.
cd solution/backend && .venv/bin/python scripts/kakao_event_send_test.py --key <botUserKey>
★ 무엇을 확인하나: 콘솔 설정(채널 연결·월렛·이벤트 블록·배포)이 제대로 끝났는지, 그리고
요청/응답 모양이 문서와 같은지. 성공하면 카톡에 이벤트 블록의 말풍선이 뜬다.
★ botUserKey 는 그 사장님이 채널에 연결 코드를 보낸 뒤 owner_kakao_links.channel_user_key 에
저장된 값이다. 아직 연결 전이면 발송할 대상이 없다.
SELECT channel_user_key FROM owner_kakao_links WHERE status='LINKED' AND deleted=false;
★ 필요한 설정(.env): KAKAO_BOT_ID · KAKAO_BOT_REST_API_KEY (개발 채널이면 KAKAO_EVENT_DEV=1).
키·발화자 ID 는 출력하지 않는다.
"""
import argparse
import asyncio
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
os.environ.setdefault("APP_ENV", "local")
import httpx # noqa: E402
from services.external import kakao_event # noqa: E402
async def main(key: str, event: str, text: str) -> int:
if not kakao_event.is_configured():
print("KAKAO_BOT_ID · KAKAO_BOT_REST_API_KEY 가 .env 에 없습니다.")
return 1
async with httpx.AsyncClient(timeout=10.0) as client:
try:
task_id = await kakao_event.send(
key, event, data={"text": text}, params={"test": "1"}, client=client
)
except kakao_event.KakaoEventError as ex:
print(f"실패 — {ex}")
print(f"카카오 응답: {ex.detail}")
return 1
print(f"요청 성공 — taskId={task_id}")
print("카톡에 메시지가 왔는지 확인하세요. 안 오면 이벤트 블록 연결·배포·채널 친구 여부를 봅니다.")
return 0
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--key", required=True, help="수신자 botUserKey")
parser.add_argument("--event", default="post_approval", help="오픈빌더에 정의한 이벤트 이름")
parser.add_argument("--text", default="Event API 테스트입니다.", help="event.data.text 로 실려 갈 문구")
args = parser.parse_args()
raise SystemExit(asyncio.run(main(args.key, args.event, args.text)))