# Tokensensus 언론사 연동 가이드

모든 언론사가 동일한 API와 SDK로 연동할 수 있습니다.
개발자 페이지: https://tokensensus.vercel.app/developers
API 상세 문서: https://tokensensus.vercel.app/publisher-api.md

## 1. 언론사 등록

매체명, 정확한 HTTPS 기사 도메인, 로고 URL, 기술 담당자 정보를 플랫폼 운영자에게 전달합니다.
운영자가 도메인 소유를 확인하고 매체별 publisher ID와 비공개 API 키를 발급합니다.
현재 공개 셀프 가입은 제공하지 않습니다. 다른 언론사의 초안·본문·검토 권한은 공유되지 않습니다.
키는 CMS 서버 환경변수 TOKENSENSUS_PUBLISHER_KEY에만 보관합니다. 임베드에 넣지 않습니다.

## 2. 선택한 기사만 처리

- 제목 맨 앞에 `[POLL]` 또는 `[VOTE]`를 붙입니다. 대소문자 구분은 없습니다.
- 또는 CMS에서 `pollEnabled: true`를 전송합니다. 실제 제목을 바꿀 필요가 없습니다.
- `pollEnabled: false`이면 제목 표시가 있어도 제외합니다.
- 표시와 true 값 모두 없으면 AI를 호출하거나 기사를 저장하지 않고 skipped를 반환합니다.
- 표시 문자열은 Tokensensus에 표시되는 기사 제목에서 제거됩니다.
- 선택한 기사를 검토한 뒤 질문과 선택지 초안을 만듭니다. 게시 전 편집자 검토가 필요합니다.
- 시세·가격 방향에 대한 질문도 가능합니다. 상승/하락/횡보/모르겠음 등 균형 잡힌 선택지를 검토합니다.
- 질문 작성에 적합하지 않은 기사는 제외 상태로 반환합니다.

## 3. 기사 전송

POST /api/v1/articles
Authorization: Bearer YOUR_PRIVATE_PUBLISHER_KEY
Content-Type: application/json

```json
{
  "articleId": "your-cms-id",
  "url": "https://news.example.com/articles/your-id",
  "title": "[POLL] 기사 제목",
  "body": "CMS의 전체 기사 본문. 최소 200자, 최대 40,000자입니다.",
  "imageUrl": "https://your-image-cdn.com/article-thumbnail.jpg",
  "language": "ko"
}
```

예시 body는 길이 제한을 설명하기 위한 자리표시자입니다. 실제 기사 본문을 전송해야 합니다.
썸네일은 CMS 원본 썸네일 또는 og:image 값을 전달합니다. 서버가 임의의 URL을 크롤링하지 않습니다.
로고는 PATCH /api/v1/publisher에 `{"logoUrl":"https://…"}`를 전송해 설정합니다.
외부 이미지 도메인을 사용하는 권한과 이미지 표시 권한을 확인해 주세요.

JavaScript/TypeScript SDK는 /sdk/tokensensus.mjs와 /sdk/tokensensus.d.mts를 같은 폴더로 내려받아 사용합니다.
npm에 게시된 패키지는 아닙니다. Node.js 20 이상, 서버 전용이며 추가 의존성이 없습니다.

## 4. 검토 및 게시

제목 표시를 제거하거나 pollEnabled를 false로 바꾸어도 이미 게시된 투표를 자동 종료하지 않습니다. 참여를 끝내려면 close 작업을 호출하고, 화면에서 숨기려면 해당 기사 임베드 컨테이너를 제거합니다.

https://tokensensus.vercel.app/publishers 에서 매체 API 키로 로그인합니다.
질문·선택지·원문 인용을 확인하고 검토 체크 후 게시합니다. 자동 게시하지 않습니다.
한번 게시한 선택지는 수정할 수 없습니다. 투표 종료 후에도 결과는 남습니다.

## 5. 영어·한국어 임베드

```html
<div data-tokensensus data-publisher="YOUR_PUBLISHER_ID"
     data-article-id="your-cms-id" data-lang="ko"></div>
<script src="https://tokensensus.vercel.app/embed.js" defer></script>
```

영어는 data-lang="en"입니다. 이 값은 버튼과 안내 문구의 언어입니다.
질문·선택지 언어는 기사 전송 시 language로 지정합니다. 게시된 질문을 임베드에서 자동 번역하지 않습니다.
한글 질문에는 language="ko"와 data-lang="ko"를 함께 사용합니다.
공개 질문이 없는 기사에서는 위젯이 표시되지 않습니다. 페이지 조회·투표에는 AI를 호출하지 않습니다.

### 같은 질문을 여러 기사에서 함께 사용하기

기존 게시 질문의 임베드를 복사하고 **원래 질문의** `data-publisher`와 `data-article-id`를 그대로 사용합니다. 설치하는 기사나 매체가 달라도 이 두 값은 바꾸지 않습니다. 동일한 `ARTICLE_POLL_ID`를 사용하는 직접 iframe도 가능합니다. 공개 ID만 필요하며 다른 매체의 API 키를 받을 필요는 없습니다.

```html
<div data-tokensensus data-publisher="ORIGINAL_PUBLISHER_ID"
     data-article-id="ORIGINAL_CMS_ARTICLE_ID" data-lang="ko"></div>
<script src="https://tokensensus.vercel.app/embed.js" defer></script>
```

영어 버튼과 안내는 `data-lang="en"`으로 지정합니다. 같은 투표 ID를 불러오면 두 언어의 위젯 모두 같은 결과를 사용합니다. 질문·선택지는 자동 번역되지 않습니다.

편집자가 질문·선택지·기간·맥락이 각 기사에 맞는지 먼저 확인합니다. 기존 질문을 표시하기 위해 새 기사 생성 API를 호출하지 않아도 되며, 임베드 재사용에는 AI 호출이 없습니다. 원래 질문의 매체·썸네일·기사 출처가 유지됩니다. 추가 설치 기사가 별도 출처로 등록되거나 설치 위치별 결과가 제공되지는 않습니다.

유사 질문 검색·자동 병합·질문의 한영 번역 연결 기능은 아직 없습니다. 별도로 생성한 질문은 제목이 같아도 ID와 결과가 분리됩니다. 한글·영문 질문을 각각 발행하면 별개 투표가 되며, 위젯 표시 언어만 바꾸는 경우에는 같은 투표를 유지합니다.

## 6. 메인 집계

한국어 화면은 한국어 질문만, 영어 화면은 영어 질문만 보여줍니다. 홈·피드·랭킹·언론사 목록 모두 같은 기준이며, 해당 언어의 질문이 없으면 빈 상태를 표시합니다. 화면 언어 전환으로 질문을 번역하거나 새로운 투표를 만들지는 않습니다.

공개 목록 API는 `/api/public/polls?language=ko`와 `/api/public/polls?language=en`으로 구분합니다. 생략하면 영어이며 다른 값은 HTTP 400을 반환합니다. `&publisher=매체ID`로 매체도 지정할 수 있습니다. 언어 필터를 먼저 적용한 뒤 최신 질문 최대 60개를 반환하며 URL별 캐시는 최대 30초입니다. 응답은 `{ polls, language }`입니다.

기존 질문의 직접 링크와 명시적인 임베드는 유지합니다. 목록의 언어 구분은 접근 제한이 아니며, 질문 원문·선택지·기존 투표 ID와 합계를 변경하지 않습니다.

게시된 질문은 Tokensensus 메인의 언론사 투표 영역과 /newsrooms에 모입니다.
로고·매체명·원문 기사 제목·썸네일·실제 참여 수를 표시하며 매체별로 볼 수 있습니다.
임베드와 Tokensensus에서 같은 질문에 참여하면 같은 결과로 집계합니다.
실제 매체 사이트에 설치됐는지 확인하기 전에는 설치됐다고 표시하지 않습니다.

## 사용 한도와 보안

매체별 사용 한도는 운영자에게 확인하세요. HTTP 429를 받으면 반복 요청을 멈추고 다음 사용 가능 시점을 확인합니다.
HTTP 202는 처리 중입니다. 시간 초과나 HTTP 502가 발생하면 기사 상태를 먼저 조회한 뒤 같은 내용으로 재시도합니다.
중복 요청은 기존 결과를 사용합니다. 제목·본문을 변경한 기사는 별도 리비전 ID와 URL이 필요합니다.
발급받은 연동 키는 CMS 서버에만 보관하고 HTTPS로 전송합니다. 임베드, 공개 저장소, 브라우저 코드에 넣지 않습니다.
키가 노출되면 운영자에게 폐기와 재발급을 요청하세요. 매체 간 키를 공유하지 않습니다.
처리 권한이 있는 기사 본문만 전송합니다. 게시 전에는 초안과 본문이 공개되지 않습니다.
투표는 브라우저 기준 중복 참여를 제한합니다. 1인 1표나 여론의 대표성을 보장하지 않으며, 블록체인 기록은 아직 제공하지 않습니다.
