본문으로 건너뛰기
NFC 성경키링 메이커노트 · 3/7시리즈 보기 →

NFC에 적힌 URL은 못 바꾼다: 말씀 카드 웹앱을 Cloudflare Pages로 옮기고 카카오 로그인·공유를 붙인 기록

· 약 5분
Datapopcorn CEO / AI automation educator

키링 안 NFC 스티커에 URL을 써서 봉인하는 순간, 그 URL은 판매된 키링 수만큼 영구적으로 남습니다. 이 글은 폰을 대면 1초 안에 열려야 하는 말씀 카드 웹앱을 정적 HTML로 만들고, 그 URL의 목적지를 Vercel에서 Cloudflare Pages로 옮기고, 카카오 로그인·공유와 측정을 붙인 3편입니다.

오늘의 말씀 웹앱 화면. 베드로후서 3:9 말씀 카드와 복사·이미지·카톡·저장 버튼, 다음 말씀 받기 버튼

배경: 서버가 없어야 빠르고, 빠르지 않으면 폰을 뗀다​

NFC 태깅은 사용자가 폰을 키링에 대고 있는 1~2초 동안 일어납니다. 그 사이에 페이지가 안 뜨면 "안 되네" 하고 폰을 떼고, 그 키링은 다시 안 씁니다. 그래서 웹앱은 처음부터 서버 없는 정적 HTML·JavaScript를 바탕으로 만들었습니다. 첫 버전의 말씀 데이터는 페이지 안에 들어 있었고, 셔플과 북마크는 브라우저의 localStorage에서 처리했습니다. 이후 버전에는 선택형 로그인과 서버 동기화가 추가됐습니다. 2026년 2월에 Claude Code로 만든 첫 버전이 이 구조였고, 랜덤 말씀, 복사, 카카오톡 공유, 닉네임 기반 북마크까지 하루 안에 나왔습니다.

목표: 8월에 다시 만들면서 정한 것​

4월에 실험용으로 등록했던 상품을 8월에 제대로 팔기로 하면서, 웹앱도 다시 봤습니다. 정한 목표는 세 가지였습니다.

  1. 로그인 없이 그대로 읽을 수 있어야 한다. 로그인은 "원하면" 하는 선택 기능
  2. 호스팅은 상업 이용에 문제가 없고, 도메인이 바뀔 일이 없는 곳
  3. 어떤 키링에서 유입됐는지, 태깅 후 실제로 말씀을 읽었는지 측정할 수 있어야 한다

구현 1: Vercel에서 Cloudflare Pages로​

첫 버전은 Vercel을 사용했습니다. 그런데 Hobby 플랜은 상업적 사용을 제한합니다. 판매하는 제품의 URL이 약관상 애매한 곳을 가리키고 있으면, 나중에 서비스가 막혔을 때 이미 팔린 키링을 회수할 방법이 없습니다. 그래서 8월 19일에 Cloudflare Pages로 옮겼습니다. GitHub 저장소의 main 브랜치를 연결하고, 빌드 명령 없이 webapp-neo 폴더를 그대로 배포하도록 설정했습니다. 정적 HTML이라 빌드가 필요 없고, 푸시하면 몇 분 안에 반영됩니다.

Cloudflare Pages
- 저장소: team-datapopcorn/vibecoding-nfc-bible (main)
- 빌드 명령: 없음
- 출력 디렉터리: webapp-neo
- 배포 URL: https://nfc-bible.pages.dev/

구현 2: 카카오 로그인은 선택, 저장은 기본이 로컬​

말씀을 저장하는 기능은 두 층으로 만들었습니다. 기본은 브라우저 로컬 저장이라 로그인 없이도 동작합니다. 카카오로 로그인하고 동의하면 저장한 말씀 ID를 서버(Supabase)에 동기화해서 폰을 바꿔도 유지됩니다. 로그인은 Supabase의 카카오 OAuth를 썼고, 카카오 개발자 콘솔에서 닉네임·프로필·이메일을 모두 "선택 동의"로 두었습니다. 필수 동의 항목을 만들면 카카오 비즈니스 앱 전환이 필요해지는데, 이 서비스에는 그럴 이유가 없었습니다.

여기서 상세페이지 카피를 한 번 고쳤습니다. 처음에는 "회원가입·서버 저장 없음"이라고 썼는데, 로그인 기능이 생긴 뒤에는 틀린 말이 됩니다. "로그인 없이 바로 읽을 수 있고, 원하면 카카오 로그인으로 저장 목록을 동기화"로 바꿨습니다. 실물 제품의 안내 문구는 서비스가 바뀌면 같이 바꿔야 합니다.

구현 3: 카카오톡 공유가 갑자기 안 된 이유​

Cloudflare로 옮긴 다음 날, 카카오톡 공유 버튼이 동작하지 않았습니다. 카카오 개발자 콘솔의 "JavaScript SDK 도메인"에는 새 도메인을 등록해 두었는데도 그랬습니다. 원인은 다른 설정이었습니다. 카카오톡 공유는 "앱 설정 > 제품 링크 관리 > 웹 도메인"에도 도메인이 등록되어 있어야 합니다. JS SDK 도메인과 별개입니다. 여기에 https://nfc-bible.pages.dev를 추가하니 바로 해결됐습니다. 도메인을 옮길 때 카카오 콘솔에서 확인할 곳은 최소 세 군데입니다.

  • 플랫폼 > Web > 사이트 도메인 (JS SDK 초기화)
  • 제품 링크 관리 > 웹 도메인 (카카오톡 공유)
  • 카카오 로그인 > Redirect URI (OAuth 콜백)

구현 4: 어떤 키링에서 왔는지 측정하기​

NFC 유입을 구분하기 위해 URL 파라미터를 설계했습니다. 다만 판매된 실물 스티커에 어떤 URL과 파라미터가 기록됐는지는 확인하지 못했습니다. 캠페인 bible_keyring과 색상 코드별 콘텐츠 파라미터를 사용할 수 있게 구성했지만, 현재 색상 매핑은 8개 중 4개만 갖춰졌습니다. 웹앱에서는 유입 파라미터의 is_nfc_entry 값으로 NFC 후보 유입을 다른 방문과 나누도록 설계했습니다. 이 값만으로 실물 태깅을 증명할 수는 없습니다.

측정 도구는 두 개를 씁니다. GA4에는 NFC 태그 성과(캠페인·콘텐츠별)와 NFC 여부(is_nfc_entry별) 탐색 보고서를 저장해 두었습니다. PostHog에는 Web Vitals 자동 수집을 켜고, 이벤트를 정리했습니다. 처음에는 "다음 말씀 받기"를 누른 Verse Shuffle을 핵심 지표로 봤는데, 실제로는 태깅 후 첫 말씀이 렌더링된 Verse Initial이 "태깅이 성공했다"는 신호라서 이걸 활성화 이벤트로 삼았습니다. 공유, 복사, 이미지 저장, 북마크, 로그인, 스토어 링크 클릭은 그 뒤에 오는 전환 이벤트입니다.

결과​

지금 서비스는 태깅하면 말씀 카드, 복사·이미지 저장·카카오톡 공유·저장 버튼, "다음 말씀 받기", 테마 변경, 그리고 함께한 날 수와 읽은 횟수를 보여주는 "내 기록"까지 제공합니다. 성경 본문은 개역한글판(1961, 대한성서공회)을 쓰고 출처를 화면 하단에 표기했습니다. PostHog 주간 리포트는 매주 월요일 아침 Slack으로 보내도록 설정했습니다. 실제 수신 여부는 따로 확인해야 합니다.

아직 안 된 것도 있습니다. 색상 코드 매핑은 8개 중 4개만 정리되어 있고, 프로덕션과 스테이징이 PostHog 프로젝트 하나를 같이 쓰고 있어 환경 분리가 필요합니다. Supabase 보안 어드바이저는 대시보드 요약에서 "문제 없음"이라고 보여주지만 상세 항목에는 RLS 정책과 익명 실행 함수 관련 검토 항목이 남아 있습니다.

배운 점​

가장 큰 교훈은 "NFC에 적은 URL은 못 바꾼다"는 제약을 기획 단계에서 인정한 것이었습니다. 덕분에 호스팅 약관을 먼저 봤고, 상업 이용이 애매한 곳에서 미리 옮겼습니다. 두 번째는 서비스가 바뀌면 실물 제품의 안내 문구도 같이 바뀐다는 점입니다. 소프트웨어는 배포하면 끝이지만, 상세페이지와 인서트 카드는 따로 고쳐야 합니다. 세 번째는 활성화 이벤트를 "사용자가 뭘 눌렀나"가 아니라 "태깅이 성공했나"로 잡아야 한다는 것입니다. 실물 트리거 제품에서는 첫 화면이 뜬 것 자체가 전환입니다.

다음 액션​

다음 편은 물류입니다. 알리익스프레스에서 NFC 스티커 100개를 사면서 걸린 가격 함정, 80×80mm 개별 포장과 합포장 계산, 그리고 네이버 풀필먼트(N배송)를 신청했다가 560개 입고를 취소한 이유를 다룹니다.