임베드형 AI 에이전트 SDK
포트폴리오
개발

임베드형 AI 에이전트 SDK

서드파티 임베드 AI 챗봇 SDK: 호스트 사이트 충돌 해소와 CDN 자동 배포

2026 · voidx프론트엔드 엔지니어링주식회사 업폴 (Upfall)8
  • React (standalone)
  • GitHub Actions
  • pnpm
  • CDN
  • vitest
  • ReadableStream
CDN 단일 채널로 라이브 (semver 1.1.4)
번들 gzip 196KB
스프라이트 245KB → 8.4KB
초기 네트워크 요청 2회 → 1회
위젯 소실 장애 이후 실서비스 발행을 수동 전용으로 되돌림

배경

이 SDK는 고객사 자사몰(Cafe24·React 기반)에 standalone 스크립트로 삽입돼 텍스트 채팅과 캐릭터 동작을 제공합니다. 임베드 코드라 세 가지가 전제입니다. 호스트의 React·라이브러리와 충돌하면 안 되고, 외부에서 불러오므로 가벼워야 하며, 여러 고객사에 동시 배포되므로 배포가 안전하고 자동이어야 합니다. 챗봇 서버(LLM·대화 엔진) 구현은 별도 담당자 소관입니다.

한 일

  1. 내 선택을 뒤집어 충돌의 원인을 제거: 처음엔 NPM 패키지로 배포했는데 호스트 React 버전과 충돌했습니다. 충돌을 개별 대응하는 대신 CDN standalone 스크립트로 갈아엎어 버전 의존 자체를 끊었습니다. 내 판단이 전제부터 틀렸다는 걸 인정하는 게 먼저였습니다.
  2. 배포 파이프라인을 직접 설계하고 자동화: 처음 맡는 배포 구조라 빌드 산출물을 다룰 도구를 직접 선정하고, 배포 경로와 버전 관리 방식을 팀원과 논의해 정했습니다. GitHub Actions 워크플로우를 직접 작성해 Jenkins에서 옮기고 패키지 매니저를 pnpm으로 통일했습니다. 발행 시 latest/v{semver}/, build-N/ 스냅샷을 동시에 기록하도록 경로를 나누고 동시 실행 충돌을 막았습니다.
  3. 번들과 에셋 축소: 최적화 지점은 도구로 진단하되 무엇을 적용할지는 직접 판단했습니다. standalone 번들 gzip 196KB, 도트아트 스프라이트 245KB에서 8.4KB, 매니페스트 의존 제거로 초기 요청 2회에서 1회입니다.
  4. Shadow DOM 격리와 그 대가를 절차로 흡수: 위젯을 Shadow DOM closed + 0×0 호스트로 격리해 호스트 페이지 스타일과 섞이지 않게 했습니다. 그 대신 DOM 조회로는 렌더 여부를 확인할 수 없게 돼서, 렌더 검증은 스크린샷으로만 판정한다는 절차를 런북에 명시했습니다.
  5. 실서비스 몰에서 위젯이 사라진 장애: 실제 운영 중인 몰에서 위젯이 뜨지 않는 상태가 29시간 30분 이어졌습니다. 인지한 날 원인을 특정해 복구했지만, 그때까지 아무도 몰랐다는 게 더 문제였습니다. 원인을 짚을 때 짐작으로 판정하지 않고 몰이 실제로 불러가는 주소, 토큰 발급 응답, 배포된 번들 내용물 세 가지를 실측해 서로 맞을 때만 결론을 내렸습니다.
  6. 재발을 막으려고 자동 발행을 끊음: 푸시하면 바로 나가던 경로를 수동 전용으로 바꾸고, 되돌릴 때는 다시 빌드하는 대신 검증이 끝난 CDN 스냅샷을 복사하는 방식으로 정리했습니다. 편의를 줄이고 안전을 택한 판단입니다. 계약 계층이 v1·목업·v2 세 갈래로 갈려 있던 것도 이때 v2 단일로 정리했고, 정리 전후 배포 산출물이 바이트 단위로 같은지 대조해 잘못 나간 게 없음을 확인했습니다. 라이브 번들에 개발 호스트 주소가 기본값으로 남아 있던 것도 찾아 상수를 제거하고 apiUrl을 필수 인자로 바꿨습니다.

결과

  • CDN 단일 채널: semver 1.1.4로 라이브 운영 중
  • 196KB: standalone 번들 (gzip)
  • 245KB → 8.4KB: 스프라이트, 초기 네트워크 요청은 2회 → 1회
  • vitest 전 영역 커버: 배포 전 전건 통과를 유지
  • 수동 전용 발행: 위젯 소실 장애 이후 실서비스 채널을 되돌림

정리

처음 다루는 배포 구조라 도구 선정부터 직접 결정했고, 그 결정이 틀렸을 때 개별 대응으로 버티는 대신 전제를 뒤집었습니다. 장애를 겪은 뒤에는 편의를 줄이더라도 안전한 경로로 되돌리는 쪽을 택했습니다.