콘텐츠로 이동

Lark, Feishu, DingTalk, WeCom, QQ, Mochat

아시아권 기업용 및 소비자용 메시징 플랫폼 — 지역별 라우팅 및 기능 플래그 안내 포함.

이 페이지는 Revka의 아시아권 기업용·소비자용 메시징 채널에 대한 레퍼런스입니다. 다루는 채널은 Lark(해외) 및 Feishu(중국), DingTalk, WeCom(기업용 WeChat), QQ 공식 봇, 그리고 Mochat입니다. 정확한 설정 키, 지역 라우팅, 수신 모드 동작 방식, Lark/Feishu를 활성화하는 빌드 플래그(channel-lark)가 필요할 때 이 페이지를 참고하세요. 각 플랫폼 개발자 콘솔에서 봇을 생성하는 단계별 절차는 해당 플랫폼의 공식 온보딩 문서를 따른 다음, 여기서 자격 증명을 설정하세요.

이 모든 채널은 ~/.revka/config.toml[channels_config] 아래에서 설정합니다. 파일을 직접 편집하거나 revka onboard --channels-only를 실행한 뒤 데몬을 재시작하여 변경 사항을 적용하세요. 공통 채널 트레이트, 전달 모드, 허용 목록 모델에 대해서는 채널 개요를 참고하세요.

채널지역수신 모드공개 인바운드 포트 필요 여부빌드 기능 플래그
Lark / Feishu해외 / 중국WebSocket(기본) 또는 웹훅웹훅 모드만 필요channel-lark
DingTalk중국Stream Mode WebSocket불필요
WeCom중국발신 전용(Bot Webhook)불필요
QQ 공식 봇중국봇 게이트웨이 WebSocket불필요
Mochat자체 호스팅HTTP 폴링불필요

Lark/Feishu만 빌드 시 기능 플래그로 제어됩니다. 나머지 네 채널은 항상 컴파일에 포함됩니다. WebSocket 모드의 Lark/Feishu, DingTalk, QQ, Mochat은 모두 플랫폼으로 외부 연결을 맺으므로 인바운드 포트가 필요 없습니다. 웹훅 모드의 Lark/Feishu만 로컬 HTTP 리스너를 엽니다.

Lark와 Feishu는 두 개의 지역 엔드포인트를 사용하는 동일한 제품입니다. Revka는 이를 플랫폼 스위치가 있는 단일 채널 구현으로 모델링합니다.

  • **Lark(해외)**는 open.larksuite.com으로 라우팅됩니다.
  • **Feishu(중국)**는 open.feishu.cn으로 라우팅됩니다.

이 채널은 두 가지 수신 모드(WebSocket vs 웹훅 수신 모드 참고), 로케일 인식 수신 확인 반응, 타이핑 표시기, 오디오 전사(25 MB 제한), 이미지 및 파일 수신, 자동 tenant_access_token 갱신을 지원합니다.

[channels_config.lark]
app_id = "cli_xxx"
app_secret = "xxx"
encrypt_key = "" # optional: AES key for webhook event decryption
verification_token = "" # optional: webhook authenticity check
allowed_users = ["*"]
mention_only = false
receive_mode = "websocket" # websocket | webhook
port = 8081 # required for webhook mode only
use_feishu = false # legacy: routes this section to Feishu endpoints
[channels_config.feishu]
app_id = "cli_xxx"
app_secret = "xxx"
encrypt_key = "" # optional
verification_token = "" # optional
allowed_users = ["*"]
receive_mode = "websocket"
필드타입기본값설명
app_idstringLark/Feishu 개발자 콘솔의 앱 ID. 필수.
app_secretstring개발자 콘솔의 앱 시크릿. 필수.
encrypt_keystring암호화된 웹훅 이벤트 페이로드를 복호화하는 데 사용하는 AES 키. 선택 사항; 웹훅 모드 전용.
verification_tokenstring웹훅 URL 인증 챌린지의 token 필드와 대조하는 토큰. 선택 사항; 웹훅 모드 전용.
allowed_usersarray[]상호작용이 허용된 Open ID(또는 Union ID). []는 전체 차단; ["*"]는 전체 허용.
mention_onlyboolfalse그룹 채팅에서 봇이 @ 멘션될 때만 응답. 다이렉트 메시지는 항상 처리됨.
receive_modestring"websocket""websocket"(장기 연결, 인바운드 포트 불필요) 또는 "webhook"(HTTP 콜백, 공개 URL 필요).
portnumber로컬 HTTP 리스너 포트. receive_mode = "webhook"일 때 필수; WebSocket 모드에서는 무시됨.
use_feishuboolfalseLark 섹션 전용. 레거시 스위치: true로 설정하면 [channels_config.lark]를 Feishu 엔드포인트로 라우팅. 전용 [channels_config.feishu] 섹션 사용을 권장.
proxy_urlstring채널별 선택적 HTTP/SOCKS5 프록시.
transcription.*table오디오 메시지 음성-텍스트 변환(25 MB 제한). Voice, TTS & 전사 참고.

Lark vs Feishu: 어떤 섹션을 사용할까

섹션 제목: “Lark vs Feishu: 어떤 섹션을 사용할까”

Feishu(중국) 엔드포인트에 접근하는 방법은 두 가지이며, Revka는 정해진 우선순위에 따라 처리합니다.

  • 권장 방법: 전용 [channels_config.feishu] 섹션을 추가합니다. 이 섹션은 항상 Feishu 엔드포인트를 대상으로 하며 Feishu로 등록됩니다.
  • 레거시 방법: [channels_config.lark] 아래에 use_feishu = true를 설정합니다. 아직 지원되지만 권장하지 않습니다. 시작 시 Revka는 Using legacy [channels_config.lark].use_feishu=true compatibility path; prefer [channels_config.feishu]를 로그에 기록합니다.

[channels_config.feishu] 섹션과 Lark 섹션의 use_feishu = true를 동시에 설정하면, 레거시 Lark 측 Feishu 폴백은 무시되고(Revka가 경고를 기록), 전용 Feishu 섹션이 우선합니다. use_feishu = false인 일반 [channels_config.lark] 섹션은 Lark로 등록되어 해외 엔드포인트를 대상으로 합니다.

인바운드 텍스트, 리치 텍스트(post), 이미지, 파일, 오디오 메시지가 디코딩됩니다. 이미지는 base64 데이터 마커로 인라인 처리됩니다(5 MiB 상한, PNG/JPEG/GIF/WebP/BMP 지원). 텍스트형 파일은 인라인 처리(512 KiB 상한)되고, 그보다 크거나 바이너리 파일은 첨부 파일 요약으로 변환됩니다. [transcription] 섹션이 설정된 경우 오디오는 전사됩니다. 수락된 각 메시지마다 봇은 로케일 인식 수신 확인 반응을 추가합니다(zh-CN, zh-TW, en, ja에 대해 각각 다른 이모지 세트 사용).

응답은 인터랙티브 카드 JSON 2.0 마크다운 형식으로 전송되므로 제목, 표, 인용문, 인라인 코드가 렌더링됩니다. 긴 응답은 카드 크기 제한에 맞도록 줄 경계에서 분할됩니다. 봇은 tenant_access_token을 캐시하고 자동으로 갱신합니다. 만료된 토큰 응답(비즈니스 코드 99991663) 또는 401이 반환되면 토큰을 무효화하고 한 번 재시도합니다.

DingTalk는 Stream Mode로 동작합니다. Revka는 client_idclient_secret을 사용해 DingTalk 게이트웨이에 연결을 등록하고, WebSocket 엔드포인트와 티켓을 수신한 뒤 해당 장기 연결을 통해 챗봇 콜백을 수신합니다. 인바운드 포트가 필요 없습니다.

DingTalk에서의 응답 처리 방식은 특수합니다. 전역 전송 API가 없으며, 각 수신 이벤트에는 메시지별 세션 웹훅 URL이 포함됩니다. Revka는 이를 채팅(및 발신자) 단위로 캐시하여 마크다운 메시지 형태로 응답을 전송할 때 재사용합니다. 따라서 봇은 사용자가 먼저 메시지를 보낸 이후에만 해당 대화에 응답할 수 있습니다. 세션 웹훅이 존재하기 전에 전송을 시도하면 No session webhook found for chat <id>. The user must send a message first to establish a session. 오류가 발생합니다.

[channels_config.dingtalk]
client_id = "ding-app-key"
client_secret = "ding-app-secret"
allowed_users = ["*"]
proxy_url = ""
필드타입기본값설명
client_idstringDingTalk 개발자 콘솔의 앱 키. 필수.
client_secretstring개발자 콘솔의 앱 시크릿. 필수.
allowed_usersarray[]상호작용이 허용된 DingTalk 직원 ID(senderStaffId). []는 전체 차단; ["*"]는 전체 허용.
proxy_urlstring채널별 선택적 HTTP/SOCKS5 프록시.

1:1 프라이빗 대화와 그룹 대화를 모두 지원합니다. 프라이빗 채팅은 발신자의 직원 ID로 식별되고, 그룹 채팅은 conversationId로 식별됩니다. 채널은 연결을 유지하기 위해 게이트웨이 SYSTEM 핑에 응답하며, 각 이벤트를 에이전트에 디스패치하기 전에 수신 확인합니다.

WeCom은 여기서 Bot Webhook으로 설정되며, 발신 전용입니다. Revka는 https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=<webhook_key>로 텍스트 메시지를 전송하고 errcode: 0을 성공으로 처리합니다. listen() 측은 연결 유지용 no-op으로, 이 채널을 통해 메시지를 수신하지 않습니다.

[channels_config.wecom]
webhook_key = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
allowed_users = ["*"]
필드타입기본값설명
webhook_keystringWeCom 그룹 봇 웹훅 URL의 key 값. 필수.
allowed_usersarray[]향후 인바운드 지원을 위해 예약됨. 발신 전용인 현재는 사용되지 않음.

헬스 체크는 웹훅에 소규모 health_check 텍스트 메시지를 전송합니다. 따라서 헬스 체크 통과 시 봇의 채팅에 실제(최소) 메시지가 전송됩니다.

QQ 공식 봇은 Discord와 유사한 WebSocket 프로토콜인 텐센트의 봇 게이트웨이를 사용합니다. Revka는 app_idapp_secret으로 getAppAccessToken에 인증하고, 게이트웨이 URL을 가져와 C2C(다이렉트) 및 그룹 @-메시지 인텐트로 식별합니다. 마지막 세션 ID와 시퀀스 번호를 사용한 게이트웨이 재개(opcode 6)를 지원하며, 게이트웨이 Hello(opcode 10) 하트비트를 수신 확인합니다. 인바운드 포트가 필요 없습니다.

[channels_config.qq]
app_id = "qq-app-id"
app_secret = "qq-app-secret"
allowed_users = ["*"]
proxy_url = ""
필드타입기본값설명
app_idstringQQ 봇 개발자 콘솔의 앱 ID. 필수.
app_secretstring개발자 콘솔의 앱 시크릿. 필수.
allowed_usersarray[]상호작용이 허용된 QQ 사용자 ID(C2C user_openid). []는 전체 차단; ["*"]는 전체 허용.
proxy_urlstring채널별 선택적 HTTP/SOCKS5 프록시.

발신 미디어는 [IMAGE:...], [VIDEO:...], [VOICE:...], [FILE:...] 마커를 사용하며, TTL 내에 동일한 파일의 재업로드를 방지하는 업로드 캐시(최대 500개 항목)를 포함합니다. 미디어 업로드 최대 크기는 10 MB입니다.

QQ 보이스는 기본적으로 .wav, .mp3, .silk만 지원합니다. 다른 형식을 가리키는 [AUDIO:...]/[VOICE:...] 마커는 재생 가능한 음성 메시지 대신 일반 파일 업로드로 처리됩니다.

Mochat은 오픈소스 Mochat 고객 서비스 플랫폼과 HTTP API를 통해 연동합니다. 폴링 방식이며 푸시 방식은 없습니다. Revka는 고정 간격으로 GET <api_url>/api/message/receive를 폴링하고, 메시지를 중복 제거(10,000개 항목 세트)한 뒤 Bearer 토큰을 사용해 POST <api_url>/api/message/send로 응답합니다.

[channels_config.mochat]
api_url = "https://mochat.example.com"
api_token = "mochat-api-token"
allowed_users = ["*"]
poll_interval_secs = 5
필드타입기본값설명
api_urlstringMochat API 기본 URL. 필수. 후행 슬래시는 자동으로 제거됨.
api_tokenstringAuthorization: Bearer <token>으로 전송되는 API 토큰. 필수.
allowed_usersarray[]상호작용이 허용된 Mochat 사용자 ID(fromUserId). []는 전체 차단; ["*"]는 전체 허용.
poll_interval_secsnumber5수신 폴링 간격(초).

폴러는 마지막으로 확인한 메시지 ID를 추적하여 다음 요청 시 since_id로 전달합니다. 응답 code0 또는 200이면 전송 성공으로 인식합니다. 헬스 체크는 GET <api_url>/api/health를 호출합니다.

설정 가능한 수신 모드를 제공하는 채널은 Lark/Feishu뿐입니다. receive_mode로 설정하며, 인바운드 이벤트가 Revka에 전달되는 방식이 달라집니다.

모드동작 방식인바운드 포트사용 시기
websocket(기본)Revka가 Lark/Feishu 오픈 플랫폼에 지속적인 WSS 장기 연결을 열고 이벤트를 프로토콜 프레임으로 수신합니다.없음기본값. 가장 간편하게 운영 가능 — NAT 환경에서 공개 URL이나 리버스 프록시 없이도 동작.
webhookRevka가 port에서 로컬 HTTP 콜백 서버를 실행하고, 플랫폼이 URL 인증 챌린지와 im.message.receive_v1 이벤트를 POST합니다.있음(port)장기 연결을 유지할 수 없거나 조직 정책상 HTTP 콜백이 필요한 경우에만 사용. 공개 HTTPS 엔드포인트 필요.

각 모드에 대한 참고 사항:

  • WebSocket 모드는 서버의 ping_interval 보정을 위해 즉시 핑을 전송하고, 플랫폼의 3초 윈도우 내에 각 이벤트 프레임을 수신 확인하며, 다중 프래그먼트 페이로드를 재조립하고, 최근 약 30분간 확인된 메시지 ID를 중복 제거하며, 하트비트 타임아웃(300초) 시 재연결합니다.
  • 웹훅 모드는 port가 설정되어야 합니다. 설정하지 않으면 Lark webhook mode requires port to be set in [channels_config.lark] 오류와 함께 시작이 실패합니다. 엔드포인트는 라이브 이벤트를 수신하기 전에 플랫폼의 URL 인증 챌린지에 응답해야 합니다(verification_token이 설정된 경우 유효성 검사 포함). 플랫폼이 게이트웨이에 접근해야 하므로 HTTPS로 노출해야 합니다. 터널로 게이트웨이 노출하기를 참고하세요.

DingTalk와 QQ는 항상 WebSocket(설정 불가)이고, WeCom은 항상 발신 전용이며, Mochat은 항상 폴링 방식입니다. 이 채널들은 receive_mode를 사용하지 않습니다.

Lark/Feishu 지원은 Cargo 기능 channel-lark로 컴파일됩니다. 이 방식으로 게이팅되는 채널은 Lark/Feishu뿐이며, DingTalk, WeCom, QQ, Mochat은 기능 플래그 없이 항상 사용 가능합니다.

Lark/Feishu를 명시적으로 포함하여 빌드하려면:

Terminal window
cargo build --release --features channel-lark

--no-default-features와 직접 지정한 기능 목록으로 빌드하는 경우, Lark 또는 Feishu를 원한다면 channel-lark를 다시 추가하세요. 플래그 없이 빌드했는데 설정에 Lark/Feishu 섹션이 있으면, Revka는 해당 채널을 시작하지 않고 이 빌드에서 지원이 비활성화되어 있다는 메시지를 로그에 기록합니다. Matrix, Lark, Nostr, WhatsApp Web, Voice Wake를 포함한 전체 채널 기능 플래그 목록은 Cargo 기능 플래그 및 ADR을 참고하세요.

이 페이지의 모든 채널은 allowed_users로 인바운드 발신자를 제어합니다.

  • 빈 목록([])은 모든 발신자를 차단합니다.
  • "*" 단일 항목은 모든 발신자를 허용합니다.
  • 그 외의 경우, 나열된 ID만 허용됩니다 — 각각 Lark/Feishu Open ID, DingTalk 직원 ID, QQ 사용자 ID, Mochat 사용자 ID.

WeCom은 발신 전용이므로 allowed_users는 예약 필드이며 현재 사용되지 않습니다. 새 채널을 설정할 때는 allowed_users = ["*"]로 시작하여 전달을 확인한 뒤, 명시적인 ID로 좁히세요.