AI 사용량 추적 SaaS
사내 SaaS · 운영 중
브라우저 확장 · CLI 콜렉터 · 어드민 콘솔을 단일 모노레포로 통합한 사내 SaaS
직원별 Claude · Codex 등 AI 도구의 사용량을 자동 수집하고 7일 사이클 기준 플랜 추천까지 제공하는 사내 SaaS입니다. 웹 포털 · Chrome MV3 확장 · 크로스플랫폼 Node CLI 콜렉터를 단일 모노레포로 묶었습니다.
- apps/web · packages/extension · packages/cli-collector · packages/shared 4-패키지 npm 모노레포 설계
- Chrome MV3 확장이 background SW에서 claude.ai 사용량 API를 폴링해 Supabase로 송신하는 파이프라인 구축
- Codex · Claude Code의 로컬 캐시를 파싱하는 크로스플랫폼 Node CLI (Windows Startup · macOS LaunchAgent 자동 등록) 구현
- 관리자 대시보드에서 Upgrade / Downgrade / Adequate / Insufficient 플랜 추천 시그널과 임계값을 실시간 조정 가능하도록 구현
- Vercel Cron 기반 Slack DM 자동 알림(미동작 사용자 감지)과 DB 쿼터 모니터링 운영 중
- 디바이스 등록 코드(30분 만료) · 90일 토큰 만료 · SHA-256 해시 저장으로 콜렉터 보안 모델 구현
- Next.js 16
- React 19
- Supabase Postgres
- Chrome MV3 Extension
- Node CLI
- Tailwind CSS
- Zod
- Vercel Cron
- 01
Problem
초기 설계에서는 모든 AI 사용량을 단일 테이블에 모아 집계하려고 했습니다. 그러나 Codex·Claude Code가 제공하는 '오늘의 토큰·세션' 같은 KST 일자 기준 누적치(차원 A)와, Claude 웹이 제공하는 '현재 7일 사이클의 사용률'(차원 B)이 의미적으로 결합 불가능한 차원이라는 사실을 운영 중에 발견했습니다. 두 값을 같은 행에 채워 넣으니 일별 그래프에서 '어제 사용률은 90% 였는데 일자 토큰 카운트는 0' 같은 모순이 반복됐고, 플랜 추천 로직도 사용자별로 들쑥날쑥한 결과를 냈습니다.
- 02
Solution
차원을 명시적으로 분리했습니다. cli_usage_rollups 테이블은 (user, KST date) 키로 토큰·세션·시간을 버킷팅하고, quota_utilization_snapshots는 (provider, product, surface, external_account_id, cycle_start) 키로 7일 사이클의 최대 사용률을 별도 보존하도록 마이그레이션했습니다. 두 테이블은 절대 JOIN하지 않으며, 화면도 '오늘 회사 전체 활동' 카드와 '내 현재 사이클 사용률' 카드로 완전히 분리해 의미 혼선을 차단했습니다.
- 03
Result
차원 분리 이후 일자 그래프와 사이클 게이지가 각각 일관된 의미를 보존하게 되었고, 플랜 추천(Upgrade / Downgrade / Adequate / Insufficient data)이 cycle_max_utilization 단일 지표로 결정되도록 단순화됐습니다. 이 과정을 정리한 30+ 데이터 정확성 함정·해결책 노트는 이후 신규 마이그레이션을 검토할 때마다 회귀 방지 체크리스트로 활용 중입니다.