분석 이벤트 API 맥락
스펙 원본은 frontmatter
spec:. 필드 계약은 as-built §10 analytics schema v2. 이 문서는 v2로 바꾼 이유, enum 의미, 중복 제거 규칙만.
한눈에
| 엔드포인트 | 역할 한 줄 |
|---|---|
POST /v1/analytics/events | 방문·행동 이벤트 수집. 항상 202 + 빈 body (fire-and-forget) |
왜 v2인가
- v1은 공개 요청이 내부
businessCardId를 들고 다녔다. v2는 공개 식별자(cardSlug)만 받고 서버가 내부 ID를 역해석 — 내부 ID가 브라우저에 노출되지 않는다. - 재시도·중복 문제를 클라이언트
clientEventId+ DB unique index(event_key)로 해소. 이미 처리된 ID도 202 — 클라이언트는 성공·중복을 구분할 필요 없다. SHAREsourceType 신설 이유: 공유받은 방문을SOCIAL/LINK로 뭉개면 NFC 유입과 공유 유입을 분리한다는 기능 목표 자체가 무의미해짐.
이벤트 · 소스 의미
eventType:PAGE_VIEW·NFC_TAP·LINK_CLICK·CARD_DOWNLOAD·SHARE_CLICKsourceType:DIRECT(기본) ·NFC·QR·LINK·SEARCH·SOCIAL·SHARE·UNKNOWNSHARE_CLICK은 공유 버튼을 누른 시점의 이벤트 — 공유 시트에서 사용자가 취소했는지는 플랫폼별로 알 수 없어 정의에서 제외.?source=nfc로 들어온 방문자가 공유하면 그 공유 URL은source=share— 공유받은 방문이 NFC로 집계되지 않는다.NFC_TAP은 서버 전용 기록(키nfc:{visitId}) — 상세는 nfc-card.md.
불변조건
- 공개 요청에서
businessCardId,nfcCardId, 원문 referrer, city를 받지 않는다. cardSlug는 현재 공개 명함이어야 함 — 아니면 404.cardLinkId는 그 명함 소유 링크인지까지 검증.- 전송 실패가 화면 동작을 막지 않는다(fire-and-forget).
엣지케이스 · gotcha
crypto.randomUUID없는 구형 브라우저의 FE fallback 값은 BE의 UUID/ULID 검증에 걸릴 수 있다(알려진 제한) — 특정 브라우저군 이벤트 유실이 보이면 이것부터.- 서로 다른 인스턴스가 같은 event key를 완전 동시 저장하면 한쪽은 unique constraint 오류(알려진 경쟁, 저장 전 존재 확인 + index가 최종 방어).
- visitor ID는
localStorage, session ID는sessionStorage— 탭·기기 단위 집계 차이는 여기서 나온다.
관련 문서
- 구현 심화(스포크): as-built §10
- 유입 흐름: nfc-card.md · public-card.md