목록으로
DEV

우리 팀이 사내 이슈 리포팅 도구를 직접 만든 이유

QA/테스터가 버튼 하나로 이슈를 리포트하고, 개발자가 즉시 분석할 수 있는 사내 도구를 만든 경험을 공유합니다.

우리 팀이 사내 이슈 리포팅 도구를 직접 만든 이유

우리 팀이 사내 이슈 리포팅 도구를 직접 만든 이유

30분짜리 디버깅 세션을 1분짜리 버튼 클릭으로 바꾸기까지


목차


1. 문제: 컨텍스트 없는 버그 리포트

우리 팀이 운영하는 서비스는 QA/서비스 기획팀이 상시 테스트를 진행한다. 그런데 이슈를 리포트하는 방식이 늘 문제였다.

사내 메신저에 이런 메시지가 날아와도 개발자는 뭘 어떻게 해야 할지 막막하다.

"방금 ○○ 화면에서 버튼이 안 눌려요. 스크린샷 첨부했어요."

기존 이슈 리포팅 흐름은 이랬다.

기존 이슈 리포팅 흐름 — QA와 개발자 간 비효율적인 커뮤니케이션

이슈 하나당 낭비되는 시간이 최소 30분1시간. 하루에 이슈가 5건이면 25시간이 그냥 공중으로 사라졌다.

기존 방식의 페인 포인트 5가지

# 문제 실제 상황
1 🔁 재현 불가 "버튼이 안 눌려요" → 개발자 환경에선 정상 동작
2 📭 정보 누락 스크린샷만으로는 콘솔 에러, 네트워크 실패 원인 불명
3 🌍 환경 차이 브라우저 버전, 화면 크기, OS 정보 전달 안 됨
4 💬 커뮤니케이션 비용 QA/테스터 ↔ 개발자 반복 질문·답변으로 30분~1시간 소모
5 ✍️ 수동 관리 ClickUp 직접 등록 + 팀 공유 모두 수동

우리에게 필요한 건 단순했다.

이슈가 발생한 그 순간의 브라우저 상태를 통째로 캡처해서,
개발자가 마치 옆에서 같이 보는 것처럼 디버깅할 수 있는 도구.


2. 외부 도구를 쓰지 않은 이유

LogRocket, Sentry 세션 리플레이, Mouseflow 같은 도구를 먼저 검토했다. 하지만 도입하지 않은 이유가 있었다.

검토 항목 외부 SaaS 우리가 필요한 것
데이터 보안 외부 서버로 전송 사내 데이터 외부 유출 불가
트리거 방식 자동 (모든 사용자) 수동 (QA 판단 기반)
이슈 유형 throw된 에러 위주 UI 깨짐, UX 이상, 데이터 표시 오류 등 시각적 문제 포함
워크플로우 별도 툴 학습 필요 기존 ClickUp + Teams 흐름에 자연스럽게 통합
비용 과금 발생 내부 인프라 활용

결론은 직접 만들기였다. 팀의 워크플로우에 딱 맞는 도구는 팀이 직접 만드는 수밖에 없다.


3. 무엇을 만들었는가

remote-debugger — "이슈 현장의 블랙박스"라고 부르는 사내 패키지다.

QA/테스터가 🐛 버튼 하나로 이슈 리포트를 생성하면, 콘솔 로그 + 네트워크 요청 + 사용자 행동 + 브라우저 환경 정보가 자동 수집되어 ClickUp 태스크로 생성되고 Teams 알림이 전송된다.

핵심 가치 3가지

① 데이터 기반       주관적 설명 → 객관적인 로그와 세션 기록
② 원클릭 자동화     리포트 생성 → S3 → ClickUp 태스크 → Teams 알림
③ 개발자 친화적     Chrome DevTools 스타일 HTML 뷰어로 즉시 분석

4. 어떻게 동작하는가

전체 흐름

전체 흐름 — 테스터, 자동 처리, 개발자 3단계 파이프라인

3초. QA가 폼을 채우고 버튼을 누르면 그 다음은 전부 자동이다.


5. 무엇을 수집하는가

5-1. 콘솔 로그

console.log / warn / error / info / debug 전체를 monkey-patching으로 수집한다. 원본 메서드는 그대로 호출하면서 동시에 내부 버퍼에 쌓는 방식이다.

순환 참조 처리가 핵심이었다. React DevTools나 라이브러리들이 콘솔에 뱉는 복잡한 객체 그래프가 순환 참조를 갖는 경우가 있어서, 직렬화 전에 반드시 처리해야 한다.

// WeakSet으로 순환 참조를 안전하게 감지
function safeSerialize(value: unknown): string {
  const seen = new WeakSet();
  return JSON.stringify(value, (_, v) => {
    if (typeof v === 'object' && v !== null) {
      if (seen.has(v)) return '[Circular]';
      seen.add(v);
    }
    return v;
  });
}

5-2. 네트워크 요청

fetchXMLHttpRequest 두 군데를 모두 패치한다. 일부 외부 라이브러리가 XHR을 사용하기 때문이다.

수집 항목

항목 내용
URL / Method / Status 기본 요청 정보
Request/Response Body 텍스트/JSON 본문
Timing (Performance API) DNS·TCP·TLS·TTFB·수신 단계별
Initiator Stack Trace 요청 발생 파일·라인·컬럼
Resource Type fetch / xhr

Next.js 내부 요청 자동 제외: ?_rsc=, _next/data/, _next/static/ 등 프레임워크 내부 요청은 노이즈가 많아 필터링한다.

5-3. 사용자 세션

이벤트 수집 내용
click CSS selector, 좌표, 텍스트
input 입력값 (민감 정보 자동 마스킹)
scroll / resize 위치·크기 (200ms throttle)
navigation 페이지 이동 (popstate)
error 런타임 에러, unhandled rejection

5-4. 민감 데이터 보호

입력값     password / email / tel 타입  →  ****
요청 헤더  authorization / cookie      →  [REDACTED]
내부 트래픽  GA 요청 등                →  수집 제외

6. 아키텍처: 4-레이어 구조

4-레이어 아키텍처 — React, Core, Viewer, API 계층 구조

HTML 뷰어 탭 구성

제공 정보
🔴 Console 레벨별 필터 (error/warn/info/log/debug), Error stack trace
🔵 Network 요청·응답 헤더/본문, 소요시간 단계별, Initiator stack trace
🟢 Session 사용자 행동 타임라인, rrweb 화면 재생
🟡 Info 브라우저/OS/화면 크기/메모리, Report ID, 이슈 발생 URL

완전히 독립적인 self-contained HTML이라 외부 서버 없이 파일만 열어도 된다.

제출 파이프라인

제출 파이프라인 — S3 업로드 후 ClickUp과 Teams로 병렬 전송


7. 기술적으로 흥미로웠던 부분들

bubble vs. capture

세션 이벤트를 캡처 단계에서 잡을지, 버블 단계에서 잡을지를 고민했다. 최종적으로 버블 단계를 선택했다.

Next.js App Router의 startTransition 내부에서 이벤트를 처리하는 방식과 캡처 단계가 충돌하는 케이스가 있었기 때문이다. 프레임워크 내부 동작을 방해하지 않으면서 이벤트를 관찰하는 게 핵심 원칙이었다.

외부 의존성 없는 UI

플로팅 버튼과 모달은 디자인 시스템 컴포넌트를 쓰지 않고 인라인 React.CSSProperties로만 구현했다. 이 도구는 어느 앱에서도 독립적으로 동작해야 하기 때문에, 외부 스타일 의존성을 최대한 없앴다.


8. 도입 후: Before / After

이슈 처리 사이클 비교

단계 Before After
리포트 작성 10~20분 (수동) ~1분 (버튼 클릭 + 폼 입력)
팀 공유 3~5분 추가 0초 (자동 Teams 알림)
개발자 추가 질문 15~30분+ 0회 (리포트에 모든 정보 포함)
재현 시도 불확실 콘솔+네트워크+세션 탭으로 분석 가능
ClickUp 등록 10~15분 수동 자동 생성
총 소요 시간 30분 ~ 1시간+ 1-2분

핵심 수치

이슈 리포트 작성 시간    ~95% 단축
팀 공유 자동화           100% (0초)
개발자 재질문 왕복       0회

역할별 달라진 점

🧪 QA / 테스터

  • DevTools 열지 않아도 stack trace·실패 API·타이밍 정보 자동 포함
  • 이슈 설명 템플릿 자동 제공 → 작성 누락 최소화
  • rrweb 활성화 시 별도 화면 녹화·첨부 불필요

👩‍💻 개발자

  • Network + Session 탭으로 독립 재현, 추가 질문 불필요
  • Initiator stack trace로 실패 요청 코드 위치 즉시 확인
  • Performance API 기반 DNS/TCP/TLS/TTFB 단계별 병목 진단

🏢 비개발팀

  • 개발 지식 없이 🐛 버튼 하나로 완전한 리포트 전송
  • Teams + ClickUp 자동 알림으로 개발팀에 즉시 전달

🏆 팀 전체

  • 이슈 브라우저 상태 영구 보존 → 스프린트 회고·재발 방지 활용
  • 리포팅 품질 균일화 → 개발자·QA 간 신뢰·협업 효율 향상

9. 한계와 다음 단계

현재 한계 (MVP 단계)

솔직히 말하면 아직 완성형은 아니다.

가장 큰 문제는 API 자격증명이 클라이언트 사이드에 있다는 것이다. MVP 단계에서는 빠르게 만들고 검증하는 게 목표였지만, 장기 운영에는 서버 사이드로 이관이 필요하다.

항목 기타 모니터링 툴 (Sentry 등) remote-debugger
트리거 자동 수동 (QA 판단)
대상 전체 사용자 테스트 중 QA
이슈 유형 throw된 에러 위주 에러 + 시각적 이슈 (UI 깨짐, UX 이상 등)

remote-debugger는 Sentry 같은 도구의 대체가 아니라 보완재다. 두 도구가 협력 관계로 동작하는 게 맞다.

로드맵

Phase 1 — 보안
  클라이언트 → 백엔드 → ClickUp/S3/Teams
  API 토큰·Webhook을 서버 사이드로 이관

Phase 2 — 기능 강화
  Sentry 등 기존 에러 모니터링 도구와 통합 가능성 검토

Phase 3 — 독립 패키지화 & 분석
  리포트 통계·이슈 트렌드 분석
  다른 프로젝트에도 적용 가능한 독립 패키지화

마치며

직접 만드는 건 시간이 든다. 하지만 팀에게 딱 맞는 도구는 팀만 만들 수 있다.

이 패키지를 만들면서 브라우저 내부 동작—이벤트 버블링, fetch 인터셉션, monkey-patching의 함정—을 훨씬 깊이 이해하게 됐다. QA 도구로 만들었는데 개발자들이 디버깅 중에도 쓰기 시작했다는 게 나름 뿌듯한 부분이다.

리포트 하나에 콘솔 에러, 실패한 API 요청, 그 직전 사용자 행동이 모두 담겨오는 순간, "아, 왜 이 버그를 재현하지 못했는지 이제 알겠다"는 말이 자연스럽게 나왔다. 그걸로 충분하다.


이 글에서 소개한 도구는 사내 패키지로 운영 중이며, 일부 설정(API 엔드포인트, 버킷 정보, 웹훅 URL 등)은 외부에 공개되지 않습니다.

이런 글은 어때요?