# 계산→복사 전환 집계

계산한 페이지 세션 중 실제 복사에 성공한 비율을 Cloudflare Pages Function `POST /api/events`와 D1 `cheongirok-conversion`으로 집계한다. 개인 서버나 유료 플랜이 필요하지 않다. Cloudflare Web Analytics의 방문 통계와 별개이며, Web Analytics는 사용자 정의 이벤트를 지원하지 않는다.

## 어디서 확인하나

Cloudflare 계정에서 **Storage & databases → D1 SQL Database → cheongirok-conversion → Console**을 열어 다음 SQL을 실행한다. 계정 UI에서 메뉴 이름이 다르면 D1 데이터베이스 목록에서 같은 이름을 선택한다.

```sql
SELECT * FROM daily_funnel ORDER BY cohort_date_kst DESC;
SELECT * FROM funnel_totals;
```

첫 쿼리는 계산한 한국 날짜(KST)별 집계, 두 번째는 최근 30일 전체 집계다. 날짜별 세션 수를 더한 값과 기간 전체 고유 세션 수는 자정을 넘긴 세션 때문에 다를 수 있다. D1의 Metrics는 요청·읽기·쓰기 사용량이며 전환율 표가 아니다.

계산 세션은 계산 완료 이벤트가 접수된 서로 다른 임시 세션 수다. 복사 전환 세션은 그 세션에서 접수된 계산 결과와 같은 결과 ID로 복사 성공이 접수된 세션 수다. **복사 전환율 = copy_sessions / calculation_sessions**이며, 계산 세션이 0이면 뷰의 `conversion_percent`는 0이지만 해석할 비율은 없다. `success_sessions`와 `copy_sessions`는 복사 성공 세션 수로 같다. `conversion_percent`는 `copy_sessions / calculation_sessions × 100`이다. `calculation_count`와 `success_count`는 세션 수가 아닌 계산 결과 수와 복사 성공 결과 수다. 다운로드는 수집하거나 성공으로 집계하지 않는다.

## 수집 범위

본문에는 `event`(이벤트 종류), `session_id`(페이지 세션용 임시 UUID), `result_id`(계산 결과용 임시 UUID), `locale`(화면 언어: `ko`, `zh-CN`, `ja`)만 허용한다. 시각은 서버에서 기록한다.

| 이벤트 | 기록 시점 |
| --- | --- |
| `calculation_completed` | 새 계산 결과가 정상적으로 채택된 뒤 |
| `copy_success` | 해당 결과의 클립보드 쓰기가 성공한 뒤 |

페이지를 새로 열거나 새로고침하면 세션 ID가 바뀌고, 새 계산 결과마다 결과 ID가 바뀐다. 영구 분석 ID나 분석 쿠키를 만들지 않는다. 같은 결과의 복사 성공은 한 번만 집계한다. 계산 기록과 연결되지 않은 복사는 전환으로 세지 않는다. 브라우저 GPC 또는 DNT 추적 거부 신호가 켜지면 전송하지 않는다.

이름·생년월일·출생 시각·성별·출생지·입력값·명식·프롬프트·복사 본문은 보내지 않는다. 앱은 IP·User-Agent·referrer를 DB에 저장하거나 로그로 출력하지 않는다. 네트워크 요청을 처리하는 Cloudflare 플랫폼 자체에는 IP 등 연결 정보가 보일 수 있으므로 “네트워크에서 개인정보를 전혀 처리하지 않는다”는 의미는 아니다.

조회는 최근 30일만 포함한다. 다음 이벤트 수집 때 오래된 원자료를 요청당 최대 100건 정리한다. 트래픽이 없거나 삭제 대기 자료가 많으면 실제 보관이 30일보다 길어질 수 있다. 예약 삭제 작업은 두지 않았다.

## 해석 한계와 무료 한도

이는 익명 행동 집계이며 실제 사람 수나 외부 AI 사용률이 아니다. 새로고침·다중 탭은 새 세션이며, 차단기·추적 거부·네트워크 실패는 누락을 만든다. 복사 실패·권한 거부는 성공으로 세지 않고, 복사 성공도 붙여넣기나 읽기를 보장하지 않는다. 봇·위조 요청을 완전히 구분하지 않는다. 출생 정보를 수집해 이를 보정하지 않는다.

2026-10-18 공식 문서 기준 Workers Free는 Pages Functions와 다른 Workers를 합쳐 하루 100,000 요청, D1은 하루 500만 행 읽기·10만 행 쓰기·계정 합계 5GB를 제공한다. 이벤트 하나가 반드시 한 행 쓰기만 쓰는 것은 아니다. 인덱스·정리·콘솔 조회도 사용량에 반영되며 UTC 자정에 일일 한도가 초기화된다. 무료 한도 초과 시 집계가 실패할 수 있다. 계산·복사 기능은 집계 응답을 기다리지 않으며, 이 수치가 서비스 트래픽 보장량은 아니다.

## 설정과 배포

2026-10-18 D1 `cheongirok-conversion`(ID `84d47781-c181-411f-ad7a-c17df0d3dda3`)을 생성하고 `analytics/schema.sql`을 적용했다. `wrangler.toml`의 production 바인딩 `CONVERSION_DB`가 이 데이터베이스를 참조한다. 바인딩 변경은 이 파일에서 관리하며 Dashboard만 수정하면 다음 CLI 배포에서 덮어써질 수 있다. `public/_routes.json`은 Function 실행 경로를 `/api/events`로 한정한다. 기존 DB에 스키마를 재적용해야 할 때는 프로젝트 루트에서 다음을 실행한다.

```powershell
npx.cmd wrangler@4.151.1 d1 execute cheongirok-conversion --remote --file analytics/schema.sql
npm.cmd run build
npx.cmd wrangler@4.151.1 pages deploy dist --project-name cheongirok --branch cheongirok
```

DB를 매 배포마다 다시 만들지 않는다. Production과 Preview의 바인딩을 구분하고, 공개 통계에 테스트 데이터를 섞지 않는다. 배포는 프로젝트 루트에서 Wrangler를 사용해야 `functions/`도 함께 배포된다. Vite preview만으로는 Function/D1을 실행하지 않는다.

배포 후 실제 계산→복사 성공을 한 번 수행하고 Console에서 집계를 확인한다. 브라우저 Network의 `/api/events` 본문에 허용된 네 필드만 있는지 확인한다. 출생 입력이나 복사 내용이 있으면 배포를 중단하고 수정한다.

공식 근거: [Web Analytics FAQ](https://developers.cloudflare.com/web-analytics/faq/), [Pages Functions 요금](https://developers.cloudflare.com/pages/functions/pricing/), [D1 요금과 초과 동작](https://developers.cloudflare.com/d1/platform/pricing/), [D1 Console 안내](https://developers.cloudflare.com/d1/get-started/), [Pages D1 바인딩](https://developers.cloudflare.com/pages/functions/bindings/#d1-databases). 무료 한도와 메뉴는 변경될 수 있다.
