카톡봇 구조 설명 (알림이용)

포비·2026년 3월 8일

알아보자

목록 보기
25/111
  1. NotificationListener가 알림 수신
  2. SessionManager가 방 세션 캐싱
  3. BotManager가 JS 스크립트 관리
  4. SessionReplier가 실제 회신 전송

이 글은 이 4개를 역할, 동작 순서, 실패 지점, 개선 포인트 기준으로 자세히 설명한다.


0) 전체 흐름 먼저 한 번에 보기

카톡봇 메시지 1건이 처리되는 흐름은 보통 이렇게 간다.

  1. 카카오톡 알림 도착
  2. NotificationListener가 알림 이벤트 수신
  3. 메시지/방/발신자 파싱
  4. SessionManager가 해당 방의 답장 세션 저장/갱신
  5. BotManager가 활성화된 JS 스크립트 목록 조회
  6. 각 스크립트의 responseFix(...) 실행
  7. 스크립트가 replier.reply(...) 호출
  8. SessionReplier가 캐시된 세션으로 실제 전송
  9. 성공/실패 로그 기록

핵심은 “로직 실행”보다 세션 확보 + 전송 안정성이다.


1) NotificationListener: 입력 파이프의 시작점

NotificationListener는 시스템 알림 이벤트를 받아서 카톡 메시지 입력으로 변환하는 컴포넌트다.

1-1. 하는 일

  • 특정 패키지(예: 카카오톡) 알림만 필터링
  • 알림 extras에서 텍스트/발신자/방 정보 추출
  • 중복 알림 처리 방지
  • 파싱 완료된 메시지를 봇 실행 레이어로 전달

1-2. 왜 중요한가 (메신저봇R은 이걸 못했다)

여기서 파싱이 틀리면 뒤 단계는 전부 잘못된다.

  • 방 이름이 잘못 잡히면 엉뚱한 방 세션에 바인딩
  • 메시지 본문 파싱 실패면 스크립트 조건문이 동작 안 함
  • 중복 처리 누락이면 봇이 같은 답을 2번 보냄

1-3. 실무에서 자주 나오는 이슈

  1. 알림 포맷 변화
    안드로이드 버전/앱 업데이트에 따라 extras 구조가 달라진다.

  2. 중복 이벤트
    같은 알림이 update/repost 되며 다시 들어올 수 있다.

  3. 그룹채팅 파싱 혼선
    room/sender 판단이 애매한 경우가 있다.

1-4. 방어 설계 포인트

  • 여러 필드(EXTRA_TEXT, EXTRA_BIG_TEXT, EXTRA_MESSAGES)를 fallback으로 조회
  • notification key + postTime 기반 중복 차단
  • 파싱 실패 시 안전한 기본값/무시 정책
  • 디버그 로그 옵션(필요 시 상세 extras 덤프)

2) SessionManager: 답장 가능한 “통로”를 저장하는 레이어

SessionManager는 방별로 reply 가능한 세션 액션을 캐싱한다.

2-1. 하는 일

  • 알림에서 reply action(RemoteInput + PendingIntent) 추출
  • 방 이름 기준으로 세션 저장
  • 마지막 활성 시간 관리
  • 세션 목록 조회 API 제공

2-2. 왜 필요한가

카톡봇이 실제로 망가지는 가장 흔한 이유는 “답장 통로 없음”이다.

  • 메시지는 읽었는데 reply가 안 됨
  • 세션이 만료/무효화됨
  • action 추출 실패

그래서 세션 매니저는 사실상 봇의 심장에 가깝다.

2-3. 동작 포인트

  • 먼저 wearable action에서 remoteInput 탐색
  • 없으면 일반 action에서 탐색
  • 찾으면 room -> cachedSession 갱신
  • 방 lastSeen 시각 저장

2-4. 실무 이슈

  1. 세션은 영구가 아니다
    앱 상태/OS 정책/알림 업데이트로 무효화될 수 있다.

  2. 방 이름 키 충돌 가능성
    동명이방/특수케이스 고려 필요

  3. 초기 콜드스타트 공백
    세션이 아직 없는 방은 첫 답장이 실패할 수 있다.

2-5. 개선 포인트

  • room key 정규화 규칙 강화
  • 세션 유효성 진단 함수 추가
  • 세션 만료 추정 + 재획득 유도 메시지
  • 세션 캐시 히트율 모니터링

3) BotManager: 봇 로직의 런타임 카탈로그

BotManager는 JS 스크립트 파일을 관리하고 활성 봇 목록을 제공한다.

3-1. 하는 일

  • 봇 파일 저장/조회/삭제
  • 봇 활성/비활성 상태 저장
  • 코드 로드 및 목록 제공
  • 폴링 봇 구성 추출/마이그레이션

3-2. 왜 중요한가

앱 코드와 봇 로직을 분리해야 운영이 빨라진다.

  • 앱 재빌드 없이 로직 수정 가능
  • 방/기능 단위로 봇 분리 가능
  • 장애 시 특정 봇만 끄기 가능

3-3. 운영 장점

  1. 핫스왑: 로직 배포 속도 빠름
  2. A/B 스타일 운영: 봇별 실험 가능
  3. 장애 격리: 문제 봇만 비활성화

3-4. 실무 리스크

  • 스크립트 품질 편차
  • 무한루프/장시간 실행 가능성
  • 버전 관리 부재 시 롤백 어려움

3-5. 개선 포인트

  • 스크립트 사전 검증(lint/금지 패턴)
  • 실행 시간 제한(타임아웃)
  • 버전 태깅/변경 이력
  • 공통 유틸 템플릿 제공

4) SessionReplier: 실제 전송의 마지막 관문

SessionReplier는 캐시된 세션을 이용해 메시지를 실제로 전송한다.

4-1. 하는 일

  • reply(message) 또는 replyToRoom(room, message) 실행
  • SessionManager에서 room 세션 조회
  • RemoteInput에 메시지 주입
  • PendingIntent 전송
  • 성공/실패 로그 기록

4-2. 왜 중요한가

여기가 실패하면 사용자 입장에서는 “봇이 안 된다”로 보인다.

즉, 체감 품질의 마지막 책임이 replier에 있다.

4-3. 실패 분류 예시

  • no session: 세션 자체 없음
  • pendingIntent null: 액션 무효
  • no remoteInput: 답장 가능한 입력 없음
  • exception: 기타 실행 예외

실무에서 중요한 건 “실패한다”가 아니라 왜 실패했는지 구분하는 것이다.

4-4. 디버그 모드 역할

실전 세션이 없을 때도 시뮬레이션 응답을 낼 수 있으면,

  • 로직 검증
  • UI 확인
  • QA 자동화

가 가능해진다.


5) 4컴포넌트가 맞물리는 방식

이 구조의 핵심 아이디어는 역할 분리다.

  • NotificationListener: 입력 신뢰성
  • SessionManager: 회신 통로 유지
  • BotManager: 로직 유연성
  • SessionReplier: 전송 확실성

한 컴포넌트가 여러 역할을 동시에 맡으면 디버깅이 급격히 어려워진다.
반대로 분리가 잘 되어 있으면 장애 원인 분리가 빠르다.


6) 운영에서 반드시 보는 지표

  1. 알림 파싱 성공률
  2. 세션 캐시 히트율
  3. 답장 성공률
  4. 실패 사유 분포
  5. 봇별 에러율
  6. 평균 처리 지연

이 지표를 같이 보면 어디가 병목인지 보인다.


7) 결론

요청한 4개 컴포넌트는 각각 독립 기능처럼 보이지만, 실제로는 하나의 체인이다.

  • 입력을 정확히 받아야 하고
  • 답장 가능한 세션을 잡아야 하고
  • 로직을 유연하게 실행해야 하고
  • 마지막 전송이 확실해야 한다.

카톡봇 품질은 결국 이 4개를 얼마나 안정적으로 연결했느냐에서 결정된다.


출처

profile
무엇이든 필요한 것을 합니다. https://mint-middle-1e5.notion.site/2b7655e8316980ad9422d96a6f3947de

0개의 댓글