Repository navigation
Knox API Spec
이 문서는 Soc PlatformClaw와 회사 메신저 Knox를 연결하기 위한 사내 프록시 API 규격을 정의한다.
이 문서의 목표는 다음과 같다.
- Knox 원본 API를 직접 PlatformClaw에 붙이지 않고, 회사 내부 표준 API로 한 번 감싸기
- 직원 계정,
agentId,sessionKey를 일관되게 매핑하기 - 웹 employee 로그인과 메신저 DM이 같은 사람 기준으로 안정적으로 연결되게 하기
- 수신 / 발신 / 상태 조회 / 인증 / 에러 처리 규칙을 명확히 하기
이 문서는 회사 API 서버 구현팀, PlatformClaw 연동 구현자, 운영 담당자가 함께 보는 기준 문서다.
Knox Proxy API는 구현 전에 문서 버전을 먼저 고정해야 한다.
권장:
- 문서 버전:
v1 - API 경로 버전:
/api/v1/... - 하위 호환 원칙:
- 필수 필드 제거 금지
- enum 값 제거 금지
- 응답 필드 추가는 가능
권장 헤더:
X-Knox-Proxy-Version: 1X-PlatformClaw-Adapter-Version: 1
권장 구조는 아래와 같다.
- Knox 원본 시스템
- 회사 Knox Proxy API
- PlatformClaw adapter / gateway integration
- PlatformClaw agent / session runtime
즉 PlatformClaw는 Knox 원본 API와 직접 통신하지 않고, 반드시 회사 내부의 Knox Proxy API만 바라본다.
이 구조를 쓰는 이유는 다음과 같다.
- Knox 원본 포맷 변경 영향 최소화
- 사내 인증 / 감사 / 보안 규칙을 회사 쪽에서 통제 가능
- 직원 식별 규칙을 회사 기준으로 통일 가능
- 이후 다른 메신저가 추가되어도 PlatformClaw 쪽 변경을 줄일 수 있음
Knox를 Slack처럼 안정적으로 붙이려면, 단순히 수신 API와 발신 API만 있으면 끝나지 않는다. 아래 조건이 모두 만족돼야 실제 운영이 가능하다.
| 구분 | 필수 여부 | 설명 |
|---|---|---|
| 수신 이벤트 전달 | 필수 | Knox에서 DM, 그룹방, thread reply, 첨부 이벤트를 Proxy가 받아야 한다 |
| 발신 API | 필수 | PlatformClaw가 생성한 답장을 Knox로 다시 보낼 수 있어야 한다 |
| 사용자 식별 | 필수 |
knoxUserId를 회사 계정과 1:1 매핑할 수 있어야 한다 |
| 대화방 식별 | 필수 |
conversationId, threadId, roomId를 안정적으로 구분할 수 있어야 한다 |
| 서명 검증 | 필수 | 수신 webhook 위변조를 막을 인증 수단이 있어야 한다 |
| dedupe | 필수 | 같은 메시지가 재전송되어도 한 번만 처리되게 해야 한다 |
| bot loop 차단 | 필수 | PlatformClaw가 보낸 메시지를 다시 수신 처리하지 않아야 한다 |
| thread reply 지원 | 권장 | Slack류 UX에서는 thread 분리가 중요하다 |
| 첨부파일 수신/발신 | 권장 | 문서, 이미지, 링크 카드가 업무 흐름에 자주 섞인다 |
| presence / read 상태 | 선택 | 꼭 필요하진 않지만 운영 UX에는 도움 된다 |
| slash command / action button | 선택 | 나중에 확장하고 싶으면 고려한다 |
아래는 기술 구현 전에 먼저 합의해야 하는 정책이다.
| 항목 | 권장값 | 이유 |
|---|---|---|
| DM 세션 분리 여부 | 분리 | 웹 employee 세션과 메신저 DM 문맥이 섞이는 것을 막는다 |
| 그룹방 처리 | 공용 agent 분리 | 개인 agent private context 오염 방지 |
| thread 처리 | thread 유지 | 같은 room 안에서도 주제가 섞이지 않게 한다 |
| 발신 실패 retry | 제한적 재시도 | 중복 답장 방지 |
| 첨부파일 저장 정책 | Proxy에서 스캔/검증 후 전달 | 보안 및 파일 손상 방지 |
| 사용자 매핑 기준 | knoxUserId + email |
단순 display name 매핑은 위험 |
| webhook 허용 원본 | allowlist + signature | 사내망이어도 위변조 방지 필요 |
현재 PlatformClaw employee 구조는 직원 1명 = agent 1개를 전제로 한다.
예:
-
eon@samsung.com->agentId = "eon" -
minji@samsung.com->agentId = "minji"
권장:
- 웹 employee 기본 세션:
agent:<agentId>:main - Knox DM 세션:
agent:<agentId>:knox:dm:<knoxUserId>
예:
- 웹 로그인
agentId = "eon"sessionKey = "agent:eon:main"
- Knox DM 수신
agentId = "eon"sessionKey = "agent:eon:knox:dm:u_123456"
이렇게 하면 다음 장점이 있다.
- 웹 대화와 메신저 대화를 분리 가능
- 메신저 전용 문맥을 유지 가능
- heartbeat, cron, skill, workspace는 같은 agent 기준으로 공유 가능
권장 정책:
- DM: 개인 agent로 연결
- 그룹방: 별도 공용 agent 또는 별도 정책 필요
이유:
- 그룹방은 발화자와 책임 경계가 모호함
- 개인 agent의 private context와 섞일 위험이 큼
Knox Proxy API는 최소한 아래 역할을 수행해야 한다.
- Knox webhook 또는 polling 결과 수신
- Knox 원본 payload 검증
- 메시지 표준화
- 발화자 식별
- 대상 conversation / thread 식별
- 직원 계정 매핑
-
agentId,sessionKey결정 - PlatformClaw adapter로 전달
- PlatformClaw가 생성한 outbound reply를 Knox 발신 API 형식으로 변환
- 텍스트 / 첨부 / 스레드 답장 전송
- 결과 상태 반환
- Knox webhook 서명 검증
- 발신 API 인증 관리
- 중복 메시지 차단
- 감사 로그 기록
반드시 아래 중 하나 이상을 사용해야 한다.
- HMAC signature header
- mTLS
- 사내 전용 네트워크 + IP allowlist
- bearer token
권장 우선순위:
- HMAC signature
- 사내망 + allowlist
- bearer token
HMAC을 사용할 경우 아래 형식으로 canonical string을 만드는 것을 권장한다.
<timestamp>\n<http-method>\n<path>\n<sha256(body)>
예:
1712507400
POST
/api/v1/knox/webhooks/messages
8a3b8f8f0d5d...
권장 헤더:
X-Knox-TimestampX-Knox-SignatureX-Knox-Key-Id
검증 규칙:
- timestamp skew 허용 범위: 5분 이내
- body hash는 raw body 기준
- signature mismatch 시 즉시
401또는403 - 실패 사유는 내부 로그에만 남기고 응답에는 과도한 상세를 주지 않는다
PlatformClaw adapter가 회사 Proxy를 호출할 때는 아래 중 하나를 사용한다.
- static bearer token
- mTLS
- short-lived service token
최소 요구:
- 정적 bearer token
- 요청 감사 로그
수신 메시지는 반드시 idempotencyKey 또는 messageId 기준으로 dedupe 해야 한다.
최소 보관 권장:
- 최근 24시간 messageId cache
Proxy는 자기 자신이 보낸 메시지를 다시 PlatformClaw로 전달하지 않도록 막아야 한다.
필수 판정 예:
sender.type == "bot"sender.id == botServiceIdmessage.source == "platformclaw"
Knox Proxy는 최소 아래 매핑 결과를 계산할 수 있어야 한다.
employeeIdemployeeEmailknoxUserIddisplayNamedepartmentagentIdsessionKey
예:
employeeEmail = "eon@samsung.com"employeeId = "eon"agentId = "eon"- 웹 기본 세션 =
agent:eon:main - Knox DM 세션 =
agent:eon:knox:dm:u_123456
agent:<agentId>:knox:dm:<knoxUserId>
예:
agent:eon:knox:dm:u_123456
권장 1:
agent:knox-shared:knox:room:<roomId>
권장 2:
agent:<department-agent>:knox:room:<roomId>
개인 agent와 그룹방을 바로 섞는 것은 권장하지 않는다.
- Knox -> 회사 Proxy로 메시지 전달
- Proxy가 서명 검증
- Proxy가 발화자 / 대화방 / thread 식별
- Proxy가 직원 매핑
- Proxy가
agentId,sessionKey결정 - Proxy 또는 adapter가 PlatformClaw에 메시지 주입
- PlatformClaw가 agent/session 기준으로 처리
- 응답 생성
- 응답을 Proxy 발신 API를 통해 Knox로 재전송
- PlatformClaw가 outbound reply 생성
- adapter가 이를 Knox Proxy 발신 요청 형식으로 변환
- Proxy가 Knox 원본 발신 API 호출
- 발신 결과 / 실패 사유를 adapter에 반환
시나리오:
- Knox 사용자
u_123456 - 회사 계정
eon@samsung.com agentId = "eon"- DM session =
agent:eon:knox:dm:u_123456
흐름:
- Knox가 Proxy로 DM webhook 전달
- Proxy가
X-Knox-Signature검증 - Proxy가
u_123456 -> eon@samsung.com -> agentId=eon매핑 - Proxy가
sessionKey=agent:eon:knox:dm:u_123456결정 - Adapter가 PlatformClaw 세션
agent:eon:knox:dm:u_123456에 메시지 주입 - PlatformClaw가
eonagent 기준으로 응답 생성 - Adapter가 Proxy 발신 API 호출
- Proxy가 Knox DM으로 답장 발송
시나리오:
- 직원은 웹에서
agent:eon:main - Knox DM은
agent:eon:knox:dm:u_123456
기대 동작:
- 둘 다 같은
agentId = eon - 하지만 session은 다름
- 따라서 웹에서 하던 대화 문맥이 Knox DM과 자동으로 섞이지 않음
- heartbeat, cron, skills는 같은 agent 단위로 유지 가능
이 구조가 현재 PlatformClaw employee 모델과 가장 잘 맞는다.
권장 최소 API는 아래와 같다.
아래 표는 구현팀이 실제로 만들어야 하는 endpoint를 한눈에 보도록 정리한 것이다.
| 영역 | Method | Endpoint | 호출 주체 | 목적 | 필수 |
|---|---|---|---|---|---|
| Knox 원본 수신 | POST |
/api/v1/knox/webhooks/messages |
Knox | Knox 원본 이벤트 수신 | 필수 |
| 정규화 수신 | POST |
/api/v1/platformclaw/knox/inbound |
Proxy 내부 또는 Adapter | 정규화된 메시지를 PlatformClaw 연동 계층으로 전달 | 필수 |
| 발신 | POST |
/api/v1/platformclaw/knox/outbound/send |
PlatformClaw adapter | PlatformClaw 응답을 Knox로 전송 | 필수 |
| 사용자 매핑 | POST |
/api/v1/platformclaw/knox/resolve-user |
Adapter 또는 Proxy 내부 |
knoxUserId를 employeeId/agentId/sessionKey로 변환 |
필수 |
| 상태 확인 | GET |
/api/v1/platformclaw/knox/healthz |
운영/모니터링 | Proxy 상태 확인 | 필수 |
| 발신 결과 확인 | GET |
/api/v1/platformclaw/knox/outbound/:requestId |
운영/Adapter | 비동기 발신 결과 조회 | 권장 |
| 파일 다운로드 중계 | GET |
/api/v1/platformclaw/knox/files/:fileId |
Adapter | Knox 첨부파일을 표준 방식으로 중계 | 권장 |
| 서명 검증 진단 | POST |
/api/v1/platformclaw/knox/verify-signature |
운영/개발 | 수신 서명 검증 점검 | 선택 |
POST /api/v1/knox/webhooks/messages용도:
- Knox 원본 시스템이 회사 Proxy로 이벤트를 전달
권장 헤더:
| Header | 설명 | 필수 |
|---|---|---|
X-Knox-Event-Type |
메시지 이벤트 타입 | 권장 |
X-Knox-Delivery-Id |
재전송 구분용 delivery ID | 권장 |
X-Knox-Signature |
HMAC signature | 필수 |
X-Knox-Timestamp |
서명 유효시간 검증 | 필수 |
권장 응답:
| 상태 | 의미 |
|---|---|
202 Accepted |
정상 수신, 비동기 처리 예정 |
400 Bad Request |
payload 형식 오류 |
401 Unauthorized |
인증/서명 실패 |
409 Conflict |
중복 전달로 무시 |
429 Too Many Requests |
과도한 호출 |
500 Internal Server Error |
내부 처리 오류 |
POST /api/v1/platformclaw/knox/inbound용도:
- Proxy 내부에서 정규화된 이벤트를 PlatformClaw adapter 단계로 전달
실제로는 같은 서비스 내부 함수여도 무방하다.
권장 처리 규칙:
- 이미 검증된 webhook만 받아야 한다.
- 이 단계에서는 Knox 원본 포맷이 아니라 정규화된 내부 포맷만 사용한다.
- 이 단계에서 반드시
agentId,sessionKey가 결정되어 있어야 한다. - 이 단계 이후에는 Knox vendor 특화 필드를 가능한 한 제거한다.
POST /api/v1/platformclaw/knox/outbound/send용도:
- PlatformClaw 응답을 Knox로 발송
권장 헤더:
| Header | 설명 | 필수 |
|---|---|---|
Authorization: Bearer <token> |
PlatformClaw adapter 인증 | 필수 |
X-Request-Id |
추적용 request ID | 권장 |
X-PlatformClaw-Agent-Id |
발신 agent 식별 | 권장 |
POST /api/v1/platformclaw/knox/resolve-user용도:
-
knoxUserId를employeeId,agentId,sessionKey로 해석
실제 운영에서는 이 API를 외부 공개하지 않고 내부 서비스 함수로 구현해도 된다.
| API | Timeout | Retry | 비고 |
|---|---|---|---|
| Knox 원본 webhook 수신 | 3초 이내 응답 | 재시도는 Knox 정책 따름 | 수신은 빠르게 ACK하고 후처리 비동기 권장 |
| 정규화 수신 | 3~5초 | 내부 재시도 가능 | dedupe 필수 |
| Knox 발신 | 5~10초 |
retryable=true일 때만 제한적 재시도 |
중복 발신 주의 |
| 사용자 매핑 조회 | 1~3초 | 제한적 재시도 | 실패 시 fallback 정책 필요 |
| healthz | 1초 | 불필요 | 모니터링 전용 |
GET /api/v1/platformclaw/knox/healthz용도:
- Knox Proxy 상태 확인
권장 응답 예시:
{
"ok": true,
"service": "knox-proxy",
"version": "v1",
"time": "2026-04-08T02:10:00+09:00",
"checks": {
"signatureVerifier": "ok",
"userResolver": "ok",
"outboundClient": "ok",
"dedupeStore": "ok"
}
}회사 Proxy는 Knox 원본 포맷이 어떻든, 내부적으로는 아래 형식으로 정규화하는 것을 권장한다.
초기 구현에서는 이벤트 타입을 명확히 제한해야 한다.
권장 enum:
| eventType | 설명 | MVP 포함 여부 |
|---|---|---|
message.created |
새 메시지 수신 | 포함 |
message.reply |
thread 또는 reply 메시지 | 포함 |
message.attachment |
첨부 포함 메시지 | 제한적 포함 |
message.edited |
메시지 수정 | 제외 권장 |
message.deleted |
메시지 삭제 | 제외 권장 |
reaction.added |
리액션 추가 | 제외 |
reaction.removed |
리액션 제거 | 제외 |
presence.updated |
상태 변경 | 제외 |
중요:
- 초기에는
message.created,message.reply만 받아도 충분하다. - 나머지는 event storm를 만들기 쉬우므로 1차 범위에서 빼는 것이 안전하다.
{
"eventId": "evt_20260408_000001",
"messageId": "msg_001",
"occurredAt": "2026-04-08T01:30:00+09:00",
"tenantId": "samsung",
"source": "knox",
"conversation": {
"type": "dm",
"conversationId": "conv_123",
"threadId": null,
"roomId": null
},
"sender": {
"userId": "u_123456",
"email": "eon@samsung.com",
"displayName": "Eon",
"department": "SOC",
"employeeId": "eon"
},
"message": {
"text": "오늘 보고서 초안 만들어줘",
"attachments": [],
"replyToMessageId": null
},
"routing": {
"agentId": "eon",
"sessionKey": "agent:eon:knox:dm:u_123456"
},
"security": {
"signatureVerified": true,
"idempotencyKey": "knox:msg_001"
}
}eventIdmessageIdoccurredAtsourceconversation.typeconversation.conversationIdsender.userId-
message.text또는message.attachments routing.agentIdrouting.sessionKeysecurity.idempotencyKey
Proxy가 PlatformClaw adapter로 넘기는 최소 입력은 아래와 같아야 한다.
{
"source": "knox",
"messageId": "msg_001",
"idempotencyKey": "knox:msg_001",
"employeeId": "eon",
"agentId": "eon",
"sessionKey": "agent:eon:knox:dm:u_123456",
"conversationType": "dm",
"conversationId": "conv_123",
"threadId": null,
"sender": {
"userId": "u_123456",
"email": "eon@samsung.com",
"name": "Eon",
"department": "SOC"
},
"message": {
"text": "오늘 보고서 초안 만들어줘",
"attachments": []
}
}PlatformClaw는 결국 agentId와 sessionKey를 기준으로만 대화를 분리한다.
즉 Knox Proxy가 아래를 정확히 계산하지 못하면 바로 문제가 생긴다.
- 다른 직원 agent로 메시지가 들어감
- 웹 employee 세션과 Knox DM 세션이 섞임
- 그룹방 메시지가 개인 agent로 들어감
- heartbeat / cron / skill 문맥이 다른 사람과 섞임
따라서 employeeId, agentId, sessionKey는 단순 참고용이 아니라, 실제 권한 경계다.
권장:
| 필드 | 용도 |
|---|---|
providerMessageId |
원본 Knox 메시지 추적 |
platformclawRunId |
OpenClaw 응답 생성 추적 |
platformclawSessionKey |
어느 세션에 넣었는지 감사 추적 |
conversationKey |
room/thread 묶음 추적 |
deliveryAttempt |
재시도 횟수 추적 |
sourceEventHash |
dedupe 및 감사 로그 |
PlatformClaw adapter가 Proxy에 발신을 요청할 때의 권장 형식이다.
POST /api/v1/platformclaw/knox/outbound/send
Content-Type: application/json
Authorization: Bearer <SERVICE_TOKEN>{
"requestId": "req_20260408_000001",
"source": "platformclaw",
"agentId": "eon",
"sessionKey": "agent:eon:knox:dm:u_123456",
"conversation": {
"type": "dm",
"conversationId": "conv_123",
"threadId": null
},
"recipient": {
"userId": "u_123456"
},
"message": {
"text": "초안을 정리했습니다.",
"attachments": []
},
"metadata": {
"replyToMessageId": "msg_001",
"reason": "chat.reply"
}
}발신은 아래 두 모드를 구분하는 것을 권장한다.
| mode | 설명 |
|---|---|
sync |
Proxy가 Knox 발신 결과를 즉시 기다려 응답 |
async |
Proxy가 큐에 적재 후 accepted만 반환 |
권장:
- 기본은
async - 운영 초기 디버깅 구간에서만
sync허용
이유:
- Knox 발신 지연이 PlatformClaw 응답 경로를 직접 막지 않게 하기 위함이다.
권장:
{
"name": "report.pdf",
"mimeType": "application/pdf",
"contentBase64": "<base64>",
"sizeBytes": 183920
}파일이 큰 경우는 presigned URL 방식도 가능하다.
필수 또는 권장 규칙:
| 항목 | 권장 |
|---|---|
| 최대 파일 크기 | 10MB 또는 회사 정책 기준 |
| 허용 mime type | 화이트리스트 기반 |
| 악성코드 검사 | Proxy 단계에서 수행 |
| 원본 URL 직접 전달 | 지양 |
| presigned URL 만료 | 5~15분 |
| 파일명 정규화 | 필수 |
권장 mime type 예:
image/pngimage/jpegapplication/pdftext/plainapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
성공:
{
"ok": true,
"provider": "knox",
"messageId": "knox_out_001",
"conversationId": "conv_123",
"threadId": null,
"acceptedAt": "2026-04-08T01:31:02+09:00"
}실패:
{
"ok": false,
"errorCode": "KNOX_RATE_LIMIT",
"message": "Knox send rate limit exceeded",
"retryable": true,
"retryAfterSeconds": 30
}발신 실패 시 PlatformClaw adapter는 아래 규칙을 권장한다.
| 조건 | 처리 |
|---|---|
retryable = true |
제한적 재시도 |
retryAfterSeconds 존재 |
해당 시간 이후 재시도 |
| 인증 실패 | 즉시 운영 경고, 자동 무한 재시도 금지 |
| conversation not found | 매핑 점검 필요, 운영 알림 |
| rate limit | backoff 후 재시도 |
| 5xx | 최대 2~3회 재시도 |
중요:
- 같은
messageId로 중복 발송되지 않도록 outbound dedupe가 필요하다. - 재시도 로직은 Proxy 또는 adapter 중 한쪽에서만 책임져야 한다.
회사 내부에서 별도 매핑 서비스가 필요하다면 아래 형식을 권장한다.
POST /api/v1/platformclaw/knox/resolve-user요청:
{
"knoxUserId": "u_123456",
"email": "eon@samsung.com",
"displayName": "Eon"
}응답:
{
"resolved": true,
"employeeId": "eon",
"email": "eon@samsung.com",
"displayName": "Eon",
"department": "SOC",
"agentId": "eon",
"defaultWebSessionKey": "agent:eon:main",
"defaultKnoxDmSessionKey": "agent:eon:knox:dm:u_123456"
}실패:
{
"resolved": false,
"message": "employee mapping not found"
}권장 표준 에러 코드:
INVALID_SIGNATUREUNAUTHORIZEDUSER_MAPPING_NOT_FOUNDAGENT_MAPPING_NOT_FOUNDSESSION_KEY_INVALIDDUPLICATE_MESSAGEKNOX_RATE_LIMITKNOX_TEMPORARY_FAILUREKNOX_PERMANENT_FAILUREUNSUPPORTED_CONVERSATION_TYPEATTACHMENT_TOO_LARGEVALIDATION_ERROR
권장 응답 형식:
{
"ok": false,
"errorCode": "USER_MAPPING_NOT_FOUND",
"message": "employee mapping not found",
"retryable": false
}필수 지원 권장.
- 개인 agent로 라우팅
- 세션 분리 가능
- 가장 안정적
초기 도입 시 바로 개인 agent에 붙이지 않는 것을 권장.
선택지:
- 그룹방 미지원
- 공용 agent 하나로 운영
- 부서별 agent로 운영
Knox에 thread 개념이 있으면 다음 중 하나를 선택해야 한다.
- thread를 별도 session으로 분리
- thread를 같은 session의 metadata로만 관리
초기 권장:
- DM은 thread 분리 없이 session 하나 사용
- 그룹방은 별도 정책 확정 후 적용
초기 1차 목표:
- plain text
- newline 포함 텍스트
- 이미지 첨부 1~N개
- 파일 첨부 1~N개
- thread reply
초기 제외 권장:
- message edit sync
- reaction sync
- read receipt sync
- emoji event sync
- voice / call event
권장:
- 즉시
202 Accepted - 실제 처리 비동기 큐잉
이유:
- Knox 원본이 응답 timeout에 민감할 수 있음
권장 timeout:
- connect timeout: 3s
- read timeout: 10s
권장 retry:
- retryable 에러만 최대 3회
아래 문제는 Slack류 메신저 연동에서 반복적으로 발생하는 실수다.
| 실수 | 결과 | 대응 |
|---|---|---|
displayName만으로 사용자 매핑 |
동명이인 오매핑 |
knoxUserId + email 기준 사용 |
| 웹 session과 DM session을 무조건 동일하게 사용 | 문맥 오염, history 혼선 | 웹 main, DM knox:dm:* 분리 |
| webhook 응답을 늦게 반환 | Knox 재전송 증가 | 빠른 ACK 후 비동기 처리 |
| dedupe 미구현 | 같은 메시지 중복 처리 |
messageId 또는 idempotencyKey 캐시 |
| bot 자기 메시지 미차단 | 무한 루프 | sender/bot/service ID 필터링 |
| 그룹방을 개인 agent에 바로 연결 | private context 누수 | 공용 agent 분리 |
| threadId 무시 | 대화 흐름 혼선 | thread 정책 명시 |
| 첨부파일 원본 URL 바로 전달 | 보안/권한 문제 | Proxy 중계 또는 presigned URL |
| Proxy와 Adapter 둘 다 retry | 중복 발신 | retry 책임 한쪽으로 고정 |
| 발신 실패를 무조건 무시 | silent failure | 실패 로그/알림/재시도 정책 명시 |
- exponential backoff
아래 기준으로 중복 차단 권장:
messageIdidempotencyKey
Proxy는 최소 아래 항목을 남겨야 한다.
- inbound 수신 시각
- Knox sender id
- resolved employeeId
- resolved agentId
- resolved sessionKey
- outbound 요청 시각
- outbound 결과
- 실패 코드
- retry 여부
- signature verification 결과
민감정보 정책:
- 본문 전체 평문 저장은 정책 확인 필요
- 토큰 / 서명값 / 비밀번호는 저장 금지
회사가 Knox Proxy를 구현한 뒤, PlatformClaw 연동에 최소 필요한 정보는 아래와 같다.
- Proxy base URL
- inbound 인증 방식
- outbound 인증 방식
-
resolve-user사용 여부 - 세션 정책
- 웹 / DM 분리 여부
- 그룹방 지원 여부
- thread 지원 여부
권장 순서:
- 사용자 매핑 API
- Knox inbound webhook 검증 및 정규화
- DM 수신 처리
- PlatformClaw outbound send 연결
- dedupe / retry / logging
- 그룹방 / thread 확장
초기 MVP는 아래만 지원하면 충분하다.
- 직원 DM 수신
- 직원 DM 발신
- 사용자 매핑
-
agentId,sessionKey고정 연결 - 서명 검증
- dedupe
- 장애 로그
초기 MVP에서 그룹방과 고급 이벤트는 제외하는 것을 권장한다.
agentId = eonsessionKey = agent:eon:main
agentId = eonsessionKey = agent:eon:knox:dm:u_123456
- DM reply는 원 conversation으로 보냄
- heartbeat/cron은 DM으로 보내려면 명시적으로 target 설정 필요
- Knox webhook 서명 검증 방식이 있는가
- Knox userId -> 직원 계정 ->
agentId매핑이 가능한가 - DM / 그룹 / thread를 구분 가능한가
- 발신 API가 thread reply를 지원하는가
- 첨부파일 업로드 형식이 무엇인가
- messageId가 안정적으로 unique한가
- retryable / non-retryable 에러를 구분할 수 있는가
- 감사 로그를 남길 수 있는가
| 구분 | 확인 항목 | 상태 |
|---|---|---|
| 사용자 매핑 |
knoxUserId -> employeeId -> agentId 매핑 규칙 존재 |
필수 |
| 세션 정책 | 웹 main, Knox DM knox:dm:* 분리 여부 확정 |
필수 |
| 수신 검증 | HMAC 또는 동등 수준 서명 검증 | 필수 |
| dedupe |
messageId 또는 idempotencyKey 캐시 구현 |
필수 |
| bot loop 차단 | 자기 메시지 재수신 방지 | 필수 |
| 발신 API | text / attachment / thread reply 형식 확정 | 필수 |
| 에러 계약 |
retryable, retryAfterSeconds 정의 |
필수 |
| healthz | Proxy 상태 확인 endpoint 존재 | 필수 |
| 감사 로그 | inbound / outbound / retry / failure 로깅 | 권장 |
| 그룹방 정책 | 미지원 또는 공용 agent 정책 확정 | 권장 |
- DM과 웹 세션을 무조건 하나로 합치지 말 것
- 그룹방을 개인 agent에 바로 연결하지 말 것
- thread를 무시한 채 room 단위로만 세션을 묶지 말 것
- webhook 수신은 빠르게 ACK하고 후처리는 비동기로 넘길 것
- 발신 retry는 Proxy와 Adapter 둘 중 한 군데에서만 책임질 것
- 첨부파일 원본 URL을 그대로 OpenClaw에 넘기지 말고 검증/중계 정책을 둘 것
POST /api/v1/knox/webhooks/messages
X-Knox-Signature: sha256=...
X-Knox-Timestamp: 1712507400
Content-Type: application/json{
"messageId": "msg_001",
"conversationId": "conv_123",
"conversationType": "dm",
"threadId": null,
"sender": {
"userId": "u_123456",
"email": "eon@samsung.com",
"displayName": "Eon"
},
"text": "오늘 보고서 초안 만들어줘"
}정규화 결과 예:
{
"source": "knox",
"messageId": "msg_001",
"idempotencyKey": "knox:msg_001",
"employeeId": "eon",
"agentId": "eon",
"sessionKey": "agent:eon:knox:dm:u_123456",
"conversationType": "dm",
"conversationId": "conv_123",
"threadId": null,
"message": {
"text": "오늘 보고서 초안 만들어줘",
"attachments": []
}
}POST /api/v1/platformclaw/knox/outbound/send
Authorization: Bearer <SERVICE_TOKEN>
Content-Type: application/json{
"requestId": "req_20260408_000001",
"agentId": "eon",
"sessionKey": "agent:eon:knox:dm:u_123456",
"conversation": {
"type": "dm",
"conversationId": "conv_123",
"threadId": null
},
"recipient": {
"userId": "u_123456"
},
"message": {
"text": "초안을 정리했습니다.",
"attachments": []
}
}PlatformClaw와 Knox를 직접 연결하는 것보다, 회사 내부 Knox Proxy API를 먼저 정의하고 그 계약에 PlatformClaw adapter를 맞추는 것이 맞다.
이 문서의 핵심은 다음 두 가지다.
- 사람 기준 매핑:
직원 -> agentId - 대화 기준 매핑:
채널/DM -> sessionKey
이 둘이 흔들리지 않으면 웹 employee와 Knox 메신저 연동을 안정적으로 함께 운영할 수 있다.