Voice of Customer 모니터링 대시보드입니다. Zendesk로 들어온 고객 문의를 카테고리·감정별로 분석해서 급증 카테고리·부정 감정 변화·신규 키워드를 실시간으로 탐색하고, AI 채팅으로 질의할 수 있습니다.
- 운영 URL: https://prj-frontend-a2qqw2.lab.wntd.co/product (사내망)
- 배포: Backyard(사내 Kubernetes 샌드박스)
proj-a2qqw2 - 리포:
wanteddev/voc-analyst
Slack 주간 알림 봇은 별도 리포로 분리되었습니다. 과거 코드는 이 리포의 git history에 있습니다.
처음 합류하셨다면 이 문서 순서대로 따라오시면 됩니다.
시스템 흐름
Zendesk 문의
→ wanted-data.wanted_ml.zendesk_voc_classified (ML팀이 분류·감정 라벨링, 전일자까지 적재)
→ BigQuery views (bq_views/ 폴더의 SQL로 정의)
→ 웹 대시보드 (webapp/, Next.js)
└─ Redis 캐시 (25h TTL) — 같은 조회는 하루 1번만 BQ 실행
핵심 개념
- surge_level: 카테고리별 상태.
SURGE(급증) /WATCH(주의) /STABLE(안정) /IMPROVED(개선). 최근 7일 티켓 수를 직전 4주 평시와 비교해 분류. - as-of (기준일): 대시보드의 모든 숫자는 특정 기준일의 스냅샷. 데이터가 전일자까지만 적재되므로 default는 어제.
- 부정률:
overall_emotion = '부정'인 티켓 비율.
git clone git@github.com:wanteddev/voc-analyst.git
cd voc-analystvoc-analyst/
├── webapp/ ★ 대시보드 (Next.js 14 App Router)
│ ├── src/app/product/ # Product Insights 페이지 + error boundary
│ ├── src/app/api/ # /api/drilldown, /api/chat(SSE), /api/jira/create
│ ├── src/components/ # StatusOverview, WatchGrid, DrilldownPanel, ChatSidebar ...
│ └── src/lib/ # queries.ts(BQ), bq.ts(client+캐시), cache.ts(Redis) ...
├── bq_views/ # BigQuery view/TVF 정의 SQL (수정 시 bq CLI로 직접 반영)
├── dashboards/ # 대시보드 PRD (product-insights 구현됨 · cs-live, executive 미구현)
├── docs/ # 계획·마이그레이션 문서
└── justfile # dev / check / deploy 레시피
| 필요한 것 | 용도 | 받는 곳 |
|---|---|---|
GCP wanted-data 프로젝트 조회 권한 |
BigQuery 쿼리 | 데이터팀 |
BQ 서비스 계정 JSON (voc-bq-sa.json) |
로컬 개발·배포 | 데이터팀 (또는 Backyard secret에서 확인) |
| Backyard 계정 | 배포·로그 확인 | 인프라팀 |
| OpenAI API 키 | 채팅 에이전트 | 팀 공용 키 사용 |
⚠️ BigQuery에 사용자별 일일 쿼리 한도(QueryUsagePerUserPerDay)가 걸려 있습니다. 리셋은 매일 태평양 시간 자정 = KST 오후 4~5시경. Redis 캐시(25h TTL)가 있어 일반 사용으로는 초과되지 않습니다.
cd webapp
npm install
export GCP_SA_KEY="$(cat ~/voc-bq-sa.json)"
export BQ_PROJECT=wanted-data
export OPENAI_API_KEY=sk-... # 채팅 에이전트 안 쓰면 생략 가능
# REDIS_URL 없으면 캐시 자동 no-op (로컬은 굳이 필요 없음)
npm run dev
# → http://localhost:3000/product확인할 것: 페이지가 뜨고 "주간 시그널" 4개 블럭에 숫자가 보이면 성공. BQ 인증 에러가 나면 GCP_SA_KEY JSON이 유효한지 확인하세요.
대시보드 사용법 요약
- 상단 sticky 필터 바: 유저/기업 · 상태(급증/주의/안정/개선, 다중 선택) · 기준일
- 주간 시그널 블럭 클릭 → 상태 필터 토글
- 카테고리 카드 클릭 → 드릴다운(12주 트렌드·키워드·원문 티켓) + 상단에 중/소분류 chip 추가
- 트렌드 차트 포인트 클릭 → 해당 주 티켓만 필터
- 우측 💬 버튼 → AI 채팅 (BQ 조회 도구 포함, 답변 근거 CSV 다운로드 가능)
just check # typecheck + build 통과 확인
just deploy # arm64 빌드 + Backyard push푸시 후 Backyard에서 frontend 컴포넌트 restart (Claude Code에서 Backyard MCP restart_component 또는 Backyard 콘솔). :latest 태그 webhook이 항상 재배포를 보장하지 않으므로 restart는 필수입니다.
체크리스트:
-
just check통과 - push 후 restart → 새 이미지 sha 확인 (
list_images/ 콘솔) - https://prj-frontend-a2qqw2.lab.wntd.co/product 접속 확인
주의: arm64 필수. amd64 이미지는 Backyard에서 exec format error로 즉사합니다.
bq_views/*.sql 수정 후 직접 반영:
bq query --use_legacy_sql=false < bq_views/02_voc_surge_score.sql02_voc_surge_score.sql(오늘 기준 view)과 05_voc_surge_score_at.sql(TVF)은 정의를 항상 동기화하세요.
| 증상 | 원인 | 해결 |
|---|---|---|
| 대시보드에 "데이터 조회 한도 초과" 안내 | BQ 일일 quota 소진 | KST 오후 4~5시(태평양 자정) 리셋 대기, 또는 관리자에게 상향 요청 |
| 배포했는데 예전 화면 | Backyard rolling update 중 stale pod | restart_component 한 번 더, 30초 대기 |
| Docker 빌드가 옛 코드 사용 | 빌드 캐시 | --no-cache 플래그 (justfile deploy에 이미 포함) |
| 월요일 아침 급증 카테고리 0개 | 주말 저볼륨이 7일 창에 유입 (정상) | 기준일을 금요일로 바꿔 비교 |
| 캐시가 안 갱신되는 느낌 | Redis TTL 25h + asOf 기반 키 | 키는 날짜 전환 시 자동 교체. 강제 초기화는 Backyard MCP redis_delete_key |
- dashboards/product-insights.md — 대시보드 PRD·설계 결정
- docs/PLAN_PRODUCT_INSIGHTS.md — 기능 상세 계획
- docs/MIGRATION.md — Metabase → 커스텀 웹앱 전환 배경
- docs/ROADMAP.md — 로드맵
MIT