데이터 계약 위험

대상 제품: NewbieFinder v1.0.0
최종 갱신일: 2026년 8월 11일
계약 실측일: 2026년 8월 11일

NewbieFinder는 치지직 개발자 센터에 등록하지 않았고 공식 Open API(/open/v1/*)를 호출하지 않습니다. 대신 치지직 웹 클라이언트가 사용하는 읽기 전용 응답(https://api.chzzk.naver.com/service/v1/*)을 읽습니다.

이 경로와 응답 필드는 공개된 공식 계약이 아닙니다. 사전 공지 없이 경로, 응답 필드, 페이지네이션, CORS, 접근 정책이 변경되거나 차단될 수 있습니다.

이 문서는 그 전제 아래 "무엇이 깨질 수 있고, 깨지면 어떤 증상이 보이며, 어떻게 감지하고, 무엇을 하는지"를 기록합니다.

1. 우회하지 않는다 (First Principle)

이 원칙은 다른 모든 항목보다 우선합니다. 대응 방안을 고를 때 이 원칙과 충돌하는 선택지는 검토 대상이 아닙니다.

상황 우리가 하는 것 우리가 하지 않는 것
429 Too Many Requests 남은 큐를 흘려보내고 즉시 중단합니다. Retry-After 를 존중하되 30초를 넘으면 재시도 없이 RATE_LIMITED 로 멈춥니다. 확보한 결과만 부분 결과로 표시합니다. 429 를 무시한 재시도, 지연 없는 반복 호출, 동시성 상향
403 Forbidden / 401 ACCESS_DENIED 로 중단합니다. "우회하지 않고 탐색을 중단했습니다" 라고 사용자에게 그대로 알립니다. 재시도 버튼을 제공하지 않습니다. 헤더 위장, 프록시 경유, 다른 경로 무차별 시도
봇 방어 / CAPTCHA 기능을 중단하고 제품 범위를 다시 검토합니다. CAPTCHA 자동 해결, 자동화 탐지 회피, 브라우저 지문 조작
인증이 필요해짐 제품 범위를 재검토합니다. 필요하면 기능을 제거합니다. 로그인 쿠키 추출 안내, 사용자 토큰 요구, 비공식 인증 우회
응답 형식 변경 어댑터를 수정해 정식 업데이트로 배포합니다. DOM 크롤링으로 즉시 대체, 임의 추론으로 필드 채우기

추가로 다음을 구현하지 않습니다.

  • User-Agent, Origin, Referer 위장
  • 브라우저 지문 생성
  • 사용자 모르게 주기적으로 도는 백그라운드 수집
  • 결과를 중앙 서버로 업로드
  • 확인되지 않은 API 버전 경로를 자동으로 순회 시도
  • 공식 CHZZK 로고를 확장 아이콘으로 사용하거나 "공식", "파트너", "인증" 으로 오인시키는 문구 사용

모든 요청은 credentials: "omit", redirect: "error", referrerPolicy: "no-referrer" 로 보내며, URL은 origin === https://api.chzzk.naver.com 허용 목록을 통과한 경우에만 사용합니다.

2. 2026-08-11 실측으로 확인한 계약

아래 값이 현재 구현의 전제입니다. 하나라도 어긋나면 3장의 해당 항목을 확인해 주세요.

# 계약 항목 실측 결과 코드 위치
C-1 라이브 목록 경로 GET /service/v1/lives200 JSON chzzk-web/endpoints.ts
C-2 페이지 크기 상한 size 최대 50. 초과 요청 시 데이터가 늘지 않고 빈 배열 반환 LIVE_PAGE_SIZE = 50
C-3 기본 정렬 sortType 미지정 시 시청자 수 내림차순 buildLiveListUrl()
C-4 페이지네이션 content.page.next = { concurrentUserCount, liveId } keyset 커서, 기본 정렬에서 이 쌍의 내림차순 live-adapter.ts
C-5 시드 커서 { concurrentUserCount: viewerMax + 1, liveId: 0 } 으로 시드하면 조건 구간 첫 항목부터 수신 seedCursorForViewerCeiling()
C-6 LATEST 정렬 sortType=LATEST 는 시작 시각 내림차순 buildLiveListUrl()
C-7 v2 경로 GET /service/v2/lives404. v2는 존재하지 않습니다. (구현하지 않음)
C-8 채널 정보 GET /service/v1/channels/{id}200 JSON, content.followerCount 포함 channel-adapter.ts
C-9 존재하지 않는 채널 404 가 아니라 200 + followerCount: 0 자리표시자. content.channelIdnull 이거나 요청 ID와 다릅니다. adaptChannelInfo()
C-10 날짜 형식 openDate = 오프셋 없는 YYYY-MM-DD HH:mm:ss, 한국 표준시(UTC+09:00) 벽시계 CHZZK_OPEN_DATE_UTC_OFFSET
C-11 인증 로그인 쿠키 없이(credentials: "omit") 공개 데이터 반환 fetch-json.ts
C-12 CORS 확장 오리진에서 요청 허용 client.ts
C-13 채널 ID 형식 32자리 소문자 16진수 CHANNEL_ID_PATTERN
C-14 썸네일 호스트 *.pstatic.net, *.akamaized.net ALLOWED_IMAGE_HOST_SUFFIXES

3. 위험 등록부

3.1. 발생 가능성·영향 요약

ID 위험 가능성 영향 대응 요약
R-01 비공식 엔드포인트 경로·필드 변경 높음 높음 어댑터 격리, 계약 오류, 긴급 Patch
R-02 CORS·접근 정책 변경 중간 높음 우회하지 않고 기능 중단·재설계
R-03 팔로워 요청량 증가 높음 중간 캐시, 동시성 4, 예산 300, 부분 결과
R-04 라이브 수 증가 중간 중간 점진 렌더링, 탐색 예산, 계속 탐색
R-05 썸네일 호스트 변경 중간 낮음 CSP·허용 목록 갱신, 대체 이미지
R-06 날짜 포맷·시간대 변경 중간 중간 원본 보존, 파서 계약 테스트
R-07 치지직 상표 오인 낮음 중간 독립 로고, 비제휴 고지
R-08 Chrome 정책 변경 중간 중간 MV3 공식 문서 추적, 권한 재검토

3.2. 계약 항목별 상세

R-01a. 페이지 크기 상한 변경 (C-2)

현재 계약 size 최대 50. 초과 시 빈 배열
깨졌을 때 증상 상한이 내려가면 첫 페이지부터 빈 배열이 돌아와 결과가 0건이 됩니다. 커서도 전진하지 않아 탐색이 즉시 끝난 것처럼 보입니다.
감지 방법 npm run contract:live 의 페이지 크기 검증. 런타임에서는 scannedLives === 0 인데 오류 코드가 없는 상태로 관찰됩니다. 무한 루프 방지 가드(page.rawCount === 0 이면 중단)가 함께 걸립니다.
대응 LIVE_PAGE_SIZE 를 낮춰 Patch 배포합니다. 예산 계산(resolveBudgetLimits)이 이 값을 참조하므로 함께 재검증합니다. 상한을 올려 보는 시도는 하지 않습니다.

R-01b. 기본 정렬·커서 의미 변경 (C-3, C-4, C-5)

현재 계약 기본 정렬 = 시청자 수 내림차순, 커서 = (concurrentUserCount, liveId) 내림차순 keyset. 시드 커서로 조건 구간 진입 가능
깨졌을 때 증상 viewer-tail 전략의 전제가 무너집니다. 시드 커서가 엉뚱한 구간을 가리켜 결과가 비거나, 시청자 상한을 넘는 방송이 응답에 섞입니다. 가장 위험한 시나리오는 "결과는 나오는데 조건 구간을 다 훑지 못한 상태에서 완전 탐색이라고 표시하는 것"입니다.
감지 방법 계약 테스트에서 시드 커서 응답의 첫 항목 시청자 수가 상한 이하인지 확인합니다. 런타임에서는 응답 항목의 concurrentUserCount 가 커서 값보다 큰 경우를 진단 신호로 삼습니다. 도메인 필터가 최종 방어선이므로 조건 초과 항목이 화면에 나오지는 않습니다.
대응 시드 커서 사용을 중단하고 viewer-taillatest 로 강등해, 완전 탐색 주장을 먼저 내립니다. 그다음 새 커서 의미를 재확인해 Patch 배포합니다. 잘못된 완전성 주장을 유지한 채 결과만 보여주지 않습니다.

R-01c. 응답 스키마 변경 (필드 삭제·이름 변경)

현재 계약 content.data[]liveId, liveTitle, concurrentUserCount, openDate, adult, channel.channelId, channel.channelName
깨졌을 때 증상 런타임 스키마 검증이 실패하고 LIVE_SCHEMA_CHANGED 로 결과 그리드가 숨겨집니다. 화면에는 "치지직 데이터 형식이 변경된 것으로 보입니다" 가 표시됩니다.
감지 방법 Zod 스키마 검증 실패. 계약 테스트와 사용자 신고. 픽스처 기반 유닛 테스트(live-page.changed.json)가 이 경로를 상시 검증합니다.
대응 필드가 사라져도 기본값으로 채워 숨기지 않습니다. 어댑터와 스키마만 수정해 긴급 Patch로 배포합니다. 수정 범위가 infrastructure/chzzk-web/ 를 벗어나면 계층 격리가 깨진 것이므로 함께 점검합니다.

R-01d. 경로 버전 변경 (C-7)

현재 계약 /service/v1/* 만 존재. /service/v2/lives404
깨졌을 때 증상 v1 이 사라지면 모든 요청이 404 가 되어 INVALID_RESPONSE 로 중단됩니다.
감지 방법 계약 테스트의 상태 코드 검증. 런타임에서는 첫 페이지 요청부터 실패합니다.
대응 endpoints.ts 한 파일만 수정해 Patch 배포합니다. v2, v3 를 자동으로 순회 시도하는 폴백을 넣지 않습니다. 새 경로는 사람이 확인하고 명시적으로 반영합니다.

R-01e. 존재하지 않는 채널의 자리표시자 응답 (C-9)

현재 계약 존재하지 않는 채널도 200 + followerCount: 0, content.channelIdnull 이거나 요청 ID와 다름
깨졌을 때 증상 대조 로직이 없거나 무력화되면 존재하지 않는 채널이 "팔로워 0명" 으로 해석되어 모든 팔로워 조건을 통과합니다. 결과에 유령 카드가 섞이고, 클릭하면 없는 채널 페이지로 이동합니다. 반대로 서버가 대조 기준(channelId 반환 방식)을 바꾸면 정상 채널이 전부 unknown-channel 로 분류되어 팔로워 결과가 0건이 됩니다.
감지 방법 픽스처 기반 유닛 테스트(존재하지 않는 ID 요청 → unknown-channel 기대). 런타임에서는 unresolvedChannels 비율이 비정상적으로 높은 상태로 관찰됩니다.
대응 대조 조건을 응답 구조에 맞게 수정해 Patch 배포합니다. 어떤 경우에도 followerCount: 0 을 검증 없이 신뢰하지 않습니다. 미확인 상태는 failed 로 분리하고 조건 충족으로 추정하지 않습니다.

R-01f. followerCount 필드 삭제

현재 계약 content.followerCount 는 유한한 0 이상의 수
깨졌을 때 증상 CHANNEL_SCHEMA_CHANGED 가 발생합니다. 결과 그리드는 유지되고 시청자 조건 결과만 표시됩니다.
감지 방법 어댑터의 타입·범위 검증. 픽스처(channel.changed.json) 테스트.
대응 팔로워 조건 기능을 일시적으로 비활성화하는 것까지 검토합니다. 팔로워 수를 다른 필드에서 추론하거나 0으로 대체하지 않습니다.

R-02. CORS·접근 정책 변경

현재 계약 확장 오리진에서 CORS 허용, 로그인 쿠키 없이 공개 데이터 반환 (C-11, C-12)
깨졌을 때 증상 fetch가 CORS 오류로 실패하거나 401/403 이 돌아옵니다. 사용자에게는 "현재 데이터에 접근할 수 없습니다" 가 표시됩니다.
감지 방법 계약 테스트의 CORS 항목. 런타임에서는 ACCESS_DENIED 또는 TypeError 계열 실패.
대응 우회하지 않습니다. 기능을 중단하고 제품 범위를 다시 검토합니다. 헤더 위장, 프록시 서버 도입, 쿠키 요구는 검토 대상이 아닙니다. 접근이 영구적으로 막히면 확장 배포를 중단하는 것까지 포함해 판단합니다.

R-03. 팔로워 요청량 증가

현재 계약 채널 1건당 요청 1건, 동시성 4, 실행당 최대 300건
깨졌을 때 증상 라이브 수가 늘거나 캐시 적중률이 떨어지면 429 빈도가 올라갑니다. 부분 결과가 잦아지고 판정 대기 카운트가 커집니다.
감지 방법 partialReasonrate-limit 또는 channel-budget 인 비율. 개발 모드 디버그 이벤트의 followers.resolved 소요 시간.
대응 캐시 TTL과 예산을 조정합니다. 동시성을 4보다 올리는 방향으로는 대응하지 않습니다. 필요하면 예산을 더 낮추고 계속 탐색 을 통해 사용자가 명시적으로 이어가도록 합니다.

R-04. 라이브 수 증가

현재 계약 페이지 50건, 실행당 최대 20페이지
깨졌을 때 증상 조건 구간이 넓어져 커서 소진 전에 예산이 먼저 끝납니다. 완전 탐색 판정이 나오는 빈도가 줄어듭니다.
감지 방법 coverage.exhausted === false 비율, partialReason === "page-budget" 비율.
대응 점진 렌더링과 계속 탐색 으로 흡수합니다. 예산 상향은 요청량 영향을 함께 계산한 뒤에만 검토합니다.

R-05. 썸네일 호스트 변경 (C-14)

현재 계약 *.pstatic.net, *.akamaized.net
깨졌을 때 증상 새 호스트의 이미지가 CSP에 막혀 모든 카드가 대체 이미지로 표시됩니다. 콘솔에 CSP 위반이 기록됩니다.
감지 방법 콘솔 CSP 위반 경고. 대체 이미지 비율 급증.
대응 manifest의 img-srcALLOWED_IMAGE_HOST_SUFFIXES같은 범위로 갱신해 Patch 배포합니다. 둘 중 하나만 고치면 안 됩니다. 그 전까지는 대체 이미지로 안전하게 동작합니다.

R-06. 날짜 포맷·시간대 변경 (C-10)

현재 계약 오프셋 없는 YYYY-MM-DD HH:mm:ss, KST(UTC+09:00) 벽시계
깨졌을 때 증상 시간대 해석이 9시간 어긋나 "9시간 전 시작" 같은 값이 나오거나, 형식이 바뀌면 파싱에 실패해 시작 시간 확인 불가 로 표시됩니다. 최근 시작 순 정렬이 뒤섞입니다.
감지 방법 파서 계약 테스트(고정 문자열 → 기대 epoch). 런타임에서는 unparsedDates 카운트 증가.
대응 원본 openDate 문자열을 항상 보존하고 있으므로 어댑터의 오프셋 처리만 수정합니다. 파싱 실패는 라이브 제외 사유가 아닙니다. 정렬에서 뒤로 보내고 진단 카운트에만 반영합니다.

R-07. 치지직 상표 오인

현재 계약 독립 로고, Footer 비제휴 고지 상시 노출
깨졌을 때 증상 사용자가 공식 서비스로 오인하거나, 상표권 문제 제기를 받을 수 있습니다.
감지 방법 QA 체크리스트의 브랜드 항목, 사용자 문의.
대응 공식 로고를 사용하지 않고, "공식 / 파트너 / 인증" 으로 오인시키는 문구를 쓰지 않습니다. 비제휴 고지는 접을 수 없는 상시 노출로 유지합니다.

R-08. Chrome 정책 변경

현재 계약 MV3, Chrome 120 이상, declarativeContent + storage + 단일 호스트 권한
깨졌을 때 증상 declarativeContent 지원 변경 시 아이콘 활성화 규칙이 동작하지 않거나, 호스트 권한 정책 변경으로 요청이 차단될 수 있습니다.
감지 방법 Chrome 릴리스 노트와 MV3 공식 문서 추적. 브라우저 업데이트 후 E2E 회귀.
대응 권한 구성을 다시 검토합니다. 권한을 넓혀 해결하는 방향은 마지막 선택지이며, 늘어나는 권한은 반드시 CHANGELOG.mdPERMISSIONS.md 에 명시합니다.

4. 감지 체계 요약

계층 무엇을 잡나 실행 시점
Zod 런타임 스키마 봉투·필드 구조 변경 매 응답
어댑터 검증 채널 ID 대조, 음수·비유한 값, URL 허용 목록 매 응답
도메인 필터 조건 초과 항목의 최종 차단 (마지막 방어선) 매 렌더
픽스처 유닛 테스트 정상·변경 응답 양쪽 경로 npm run test
통합 테스트 부분 결과·캐시 폴백·429 처리 npm run test
계약 테스트 실제 응답과의 계약 일치 npm run contract:live (수동)
E2E 권한·아이콘·링크·쿨다운 npm run test:e2e
manifest 검증 권한·CSP·경로 npm run validate:manifest

계약 테스트는 수동 실행 전용입니다. CI 스케줄에 넣어 고빈도로 호출하지 않습니다. 실패가 접근 제한을 의미하는 경우 재시도하지 않고 출시를 보류합니다.

5. 계약 파손 대응 절차

① 증상 확인
     사용자 신고 / 계약 테스트 실패 / 오류 코드 급증
        │
        ▼
② 분류
     ├─ 스키마 변경   → LIVE_SCHEMA_CHANGED · CHANNEL_SCHEMA_CHANGED
     ├─ 접근 제한     → ACCESS_DENIED · RATE_LIMITED
     └─ 경로 소멸     → INVALID_RESPONSE
        │
        ▼
③ 접근 제한인가?
     ├─ 예  → 우회하지 않습니다. 기능 중단 후 제품 범위 재검토.
     └─ 아니오
            │
            ▼
④ 픽스처 갱신 (익명화 필수)
        │
        ▼
⑤ endpoints / schema / adapter 만 수정
     수정 범위가 이 세 곳을 벗어나면 계층 격리를 함께 점검합니다.
        │
        ▼
⑥ 유닛 · 통합 테스트 → 수동 계약 테스트 1회
        │
        ▼
⑦ 긴급 Patch 배포 + CHANGELOG "확인된 데이터 계약" 갱신

계약이 깨진 동안에도 확장은 잘못된 데이터를 보여주지 않고 진단 가능한 상태로 멈춰 있어야 합니다. 이것이 이 등록부가 지키려는 단 하나의 성질입니다.

6. 참고

비공식 인터페이스에 관한 공개 참고 구현은 현재 웹 응답의 동작을 파악하기 위한 자료일 뿐이며, NAVER 또는 CHZZK가 호환성을 보증하는 공식 문서가 아닙니다.

NewbieFinder는 NAVER 또는 CHZZK의 공식 서비스가 아닌 독립적인 브라우저 확장 프로그램입니다.