데이터베이스 · 로깅
내 앱에 '기억'을 붙이는 방법입니다. 사용자가 쓴 글, 신청 내역, 방문 기록 — 새로고침해도 사라지지 않게 어딘가에 저장해야 합니다. 그게 데이터베이스(DB)예요. 예전엔 개발자만 다뤘지만, 지금은 Claude에게 시키면 됩니다. 대신 '이건 사람이 꼭 지켜야 한다'는 규칙 몇 개가 있어요.

이 페이지의 한 줄 요약
데이터베이스란
앱에 기억을 붙이는 상자
DB는 '표'가 쌓여 있는 곳이에요
데이터베이스는 어렵게 생각할 것 없어요. 엑셀 시트 여러 장을 모아둔 것이라고 보면 됩니다. 시트 한 장이 테이블(table)이고, 테이블은 행(row)과 열(column)로 되어 있어요.
예를 들어 '신청자' 테이블이라면 — 열은 이름 · 이메일 · 신청일시, 행은 신청자 한 명 한 명. 사용자가 폼을 제출할 때마다 이 표에 줄이 하나씩 추가되는 거예요.


'applications' 테이블 예시
| id | name | created_at | |
|---|---|---|---|
| 1 | 김하늘 | sky@… | 2026-07-21 14:03 |
| 2 | 이바다 | sea@… | 2026-07-21 14:07 |
각 열엔 '종류(타입)'가 정해져 있어요 — id는 숫자, email은 글자, created_at은 시간. 이 타입 규칙 덕분에 잘못된 값이 들어오는 걸 막아줍니다.

원래는 개발자만 다루던 영역이었어요
표를 쌓는 게 뭐가 어렵냐 싶지만, DB는 직접 하려면 까다로운 것들이 많았어요. 어떤 표를 만들지 설계하고(스키마), 연결을 안전하게 잡고, 표끼리 관계를 맺고, 느려지지 않게 손보고, 망가졌을 때 되돌릴 백업까지 — 이걸 다 신경 써야 해서 보통 백엔드 개발자의 일이었습니다.
예전 — 직접 하던 시절
SQL 문법 배우고, 서버 세팅하고, 연결 풀 관리하고, 스키마 마이그레이션 도구 익히고… 앱 하나 붙이는 데 며칠.
지금 — AI에게 시키면
“신청 폼 내용을 DB에 저장해줘” 한 줄. Claude가 테이블 설계·연결·저장 코드까지 만들어줍니다. 몇 분.
그래서 지금 이 수업이 가능한 거예요
어디에 저장하고, 얼마인가
Vercel + Supabase · Neon · Blob 연결과 과금
먼저 그림부터 — Vercel과 DB는 다른 회사예요
헷갈리기 쉬운 부분: 내 웹사이트가 도는 곳(Vercel)과 데이터가 저장되는 곳(DB)은 보통 서로 다른 서비스예요. Vercel은 '앱을 인터넷에 띄워주는 집'이고, DB는 '데이터를 보관하는 창고'입니다. 이 둘을 연결 문자열(connection string) 하나로 이어줘요.
연결은 클릭 몇 번이면 돼요
실제로 연결해본 과정 — 클릭만 따라가면 돼요
말로만 들으면 감이 안 오죠. 강사가 실제로 ‘행사 신청 폼’ 앱에 DB를 붙인 그대로예요 — 전부 무료, 카드 등록도 필요 없었어요.
Vercel 프로젝트의 Storage 탭에서 'Create Database'

DB 종류에서 Supabase 선택

무료 플랜($0) 그대로 두고 진행

DB 이름(my-eventpage-db) 확인하고 'Create' — Free Plan은 DB 500MB·대역폭 5GB까지 무료

몇십 초 뒤 — 'database is ready to use', 만들어졌어요

만들면 프로젝트에 연결되고, 환경변수가 자동으로 꽂혀요

신청을 저장할 표(applications)를 만들고

실제 신청이 이렇게 쌓입니다

‘표 만들기’랑 ‘저장 코드’는 Claude에게 시키면 돼요. 사람이 한 건 클릭 몇 번 + 무료 플랜 선택뿐이에요.
세 가지 저장소 — 뭘 쓰나요?
Supabase — 초보자 기본값
PostgreSQL DB + 로그인 인증 + 파일 저장 + 표를 눈으로 보고 고치는 화면까지 한 세트로 줍니다. 처음이라면 이걸 추천해요.
Neon — 안 쓸 땐 잠들어 요금 절약
같은 PostgreSQL인데, 트래픽이 없으면 자동으로 ‘잠들었다(scale to zero)’ 깨어나서 비용이 적게 나와요. 실험용 앱 여러 개 굴릴 때 좋아요.
Vercel Blob — 파일 전용
이미지·영상·PDF 같은 파일을 담는 창고예요. DB가 아닙니다. “사용자가 올린 사진 저장” 같은 게 필요할 때만 씁니다.
DB에 파일을 넣지 마세요
과금 구조 — 실제로 얼마 나오나요
숫자는 2026년 기준 '대략'입니다
| 무료로 되는 것 | 유료 시작 | 돈이 새는 지점 | |
|---|---|---|---|
| Vercel | Hobby 무료 — 개인·비상업 프로젝트, 대역폭 월 100GB | Pro 월 $20/명 (사용 크레딧 $20 포함) | Hobby는 한도를 넘으면 청구 대신 프로젝트가 일시정지 / Pro는 방문 폭증 시 대역폭·함수 실행이 종량제로 초과 과금 |
| Supabase | DB 500MB·스토리지 1GB, 프로젝트 2개 | Pro 약 $25/월 | 1주일 안 쓰면 무료 DB가 일시정지 / Free는 자동 백업이 없어요 / 용량이 차면 Pro로 올려야 해요 |
| Neon | 무료 플랜 있음, 안 쓰면 자동 정지 | 월 최소 요금 없는 종량제 — 컴퓨트 약 $0.106/CU-시간, 저장 약 $0.35/GB-월 | 쓴 만큼 나가요. 컴퓨트 사용 시간·저장량이 늘면 같이 늘어요 |
| Vercel Blob | Hobby 기준 저장 1GB · 전송 월 10GB | Pro에서 저장 GB·전송량당 소액 | 큰 파일 다운로드가 많으면 전송량(egress)에서 새어나감 |
과금의 핵심 원리 3가지
- 기본요금(월 정액) + 사용량(종량제)이 합쳐져요. “$25면 끝”이 아니라, 많이 쓰면 그 위로 더 붙습니다.
- 초보자 프로젝트는 거의 다 무료 티어 안에서 돌아가요. 수강생·지인 몇십 명 수준이면 돈 낼 일이 잘 없어요.
- 진짜 무서운 건 “사고성 폭탄” — 무한 반복 코드가 DB를 계속 호출하거나, 큰 파일이 대량 다운로드될 때. 그래서 Pro라면 사용량 알림·상한(spend limit)을 꼭 켜두세요. Hobby는 청구 대신 한도를 넘으면 프로젝트가 일시정지돼요.

이 프로젝트의 Vercel/Supabase 사용량이 무료 티어를 넘지 않는지 확인하는 법을 알려줘. 그리고 요금 폭탄을 막게, 내 플랜(Hobby/Pro)에 맞는 결제 상한(spend limit)과 사용량 알림 설정하는 위치를 단계별로 알려줘.
공식 가격: vercel.com/pricing · supabase.com/pricing · neon.com/pricing
AI에게 시키는 법 + 절대 규칙
편하게 시키되, 사람이 반드시 지킬 선
저장 붙이기 — 이렇게 시키면 됩니다
거창한 SQL을 몰라도 돼요. “무엇을 저장하고 싶은지”를 평소 말로 설명하면 Claude가 테이블 설계부터 저장 코드까지 만들어줍니다.
이 프로젝트에 Supabase를 연결하고 싶어. Vercel Storage 탭에서 연결하는 방법과, 연결 정보를 .env에 안전하게 넣는 것까지 단계별로 알려줘. 내가 클릭할 화면을 정확히 짚어줘.
신청 폼(이름·이메일·소속)을 제출하면 그 내용이 DB에 저장되게 해줘. - 테이블 이름은 applications - 저장 시각(created_at)도 같이 기록 - 같은 이메일이 두 번 신청하면 막아줘 표 구조를 먼저 설명하고, 내 확인을 받은 다음에 만들어.
방금 만든 신청 폼으로 테스트 데이터를 하나 넣고, DB에 제대로 들어갔는지 조회해서 보여줘. 확인 끝나면 그 테스트 데이터는 지워도 되는데, 지우기 전에 나한테 먼저 물어봐.
절대 규칙 — 지우기·고치기는 사람이 결정한다
AI는 시키면 정말로 지워버려요. “테스트 데이터 정리해줘” 한마디에 진짜 사용자 데이터까지 날아갈 수 있어요. 그래서 실제 데이터가 든 프로젝트에는 이 규칙을 CLAUDE.md에 박아두고 AI가 항상 지키게 만드는 게 핵심이에요. (아래 블록을 그대로 복사해서 내 프로젝트 최상단 CLAUDE.md에 붙여넣으세요.)
# 백엔드/DB 작업 규칙 (반드시 지킬 것) ## 이 프로젝트는 실제 사용자 데이터를 다룬다 DB에는 진짜 데이터가 들어간다. 되돌릴 수 없는 작업은 사람이 결정한다. ## 반드시 나에게 먼저 물어보고, 승인 없이는 실행하지 말 것 - 데이터·테이블 삭제: DELETE / TRUNCATE / DROP - 기존 데이터 일괄 수정: UPDATE - 스키마 변경(컬럼 삭제·타입 변경·제약조건 변경), 마이그레이션 실행 - 관리자/인증 계정 조작 승인 요청은 이 형식으로: 작업: (무엇을) / 영향: (어느 테이블·몇 건) / 되돌리기: (가능/불가) / 백업: (했는지) → "이대로 진행할까요?" ## 물어보지 않고 해도 되는 것 - 조회(SELECT), 새 기능 코드 작성·배포, 로그 확인 - 새 데이터 추가(INSERT). 단, 실서비스에 넣는 내 테스트 데이터는 반드시 '테스트'로 표시한다(아래 참고) ## 시간은 무조건 이렇게 (아래 6번 참고) - DB에는 UTC로 저장(timestamptz). 코드에서 +9시간을 더하지 않는다. - 화면·집계에서만 Asia/Seoul로 변환한다. - 내가 말하는 시각(예: "오전 10시 마감", "매일 9시 실행")은 한국 시간이다. 코드·DB·예약(cron)에 넣을 땐 UTC로 변환하고, 애매하면 먼저 되묻는다. (cron은 UTC 기준) ## 테스트 데이터 구분 / 비밀 - 초보·소규모 단계에선 실서비스 DB 하나만 써도 된다(개발/운영 DB 분리는 스케일 커질 때). - 대신 내 테스트 데이터는 반드시 구분한다: · 계정 있는 앱: 사용자 표에 is_test 칸을 두고 내 테스트 계정만 표시 + 숨은 경로에서 테스트 계정 로그인 · 계정 없는 앱: 방문자마다 랜덤 익명 ID를 쿠키/로컬스토리지에 저장하고 데이터에 함께 기록 - 연결 문자열·키는 .env에만 둔다. 코드·깃에 절대 커밋하지 않는다. ## 매 작업 끝 - 무엇을 바꿨고 되돌리는 법이 뭔지 한 줄로 보고한다.
이 규칙이 실제로 서비스를 지킨 사례
CLAUDE.md에 “삭제·수정·스키마 변경은 먼저 물어보기” 규칙을 붙여넣었다. 이제 Claude는 위험한 작업 전에 항상 나에게 확인한다.로깅 — DB냐 Mixpanel이냐
'누가 무엇을 했는지' 기록하는 두 갈래
로깅이 왜 필요한가요
앱을 띄우면 궁금해져요 — 사람들이 어디서 들어와서, 어느 버튼을 누르고, 어디서 나가는가? 이 '행동 기록'을 남기는 게 로깅이에요. 방법은 크게 둘 — ① 내 DB에 직접 기록하거나, ② Mixpanel 같은 전문 분석 도구로 보내거나.
| 내 DB에 로깅 | ||
|---|---|---|
| 시작 난이도 | 이미 DB 있으면 즉시 | 가입·SDK 심기 필요(그래도 쉬움) |
| 데이터 소유 | 100% 내 것, 외부로 안 나감 | 외부 회사 서버에 저장됨 |
| 분석 화면 | 직접 만들어야 함(쿼리·그래프) | 깔때기·리텐션·코호트 기본 제공 |
| 비용 | DB 요금에 포함(로그 쌓이면 무거워짐) | 월 이벤트 수 기준, 무료 티어 넉넉 |
| 서비스 로직과 결합 | 쉬움 — 로그로 기능도 만들 수 있음 | 분석 전용, 서비스에 되먹이긴 번거로움 |
| 개인정보/규제 | 내가 관리·책임(장점이자 부담) | 제3자 제공 → 동의·정책 명시 필요 |

내 DB에 로깅이 유리할 때
- 로그가 서비스 기능이기도 할 때 (예: “내 활동 내역” 화면, 응모 횟수 집계)
- 데이터를 밖으로 내보내면 안 되는 민감한 서비스
- 이벤트 종류가 단순하고, 정밀 분석까진 필요 없을 때
Mixpanel이 유리할 때
- “어디서 이탈하나”(깔때기), “다시 오나”(리텐션)를 보고 싶을 때
- 분석 화면 만들 시간이 아까울 때 — 클릭 몇 번이면 그래프가 나옴
- 마케팅·A/B 테스트처럼 행동 분석이 본론일 때
바이브코딩 단계라면 — 결론은 '그냥 DB에 남기세요'
위에서 말한 그대로예요. ‘행사 신청 폼’ 앱에 이벤트 로깅(방문·입력 시작·신청 완료)을 심고, Claude에게 “이 데이터로 분석 대시보드 만들어줘”라고 했더니 나온 화면이에요. 퍼널 · 전환율 · 일별 추이 · 소속 분포 — 딱 Mixpanel이 해주던 것들이죠.

방문 420 → 입력 158 → 신청 23 (전환율 5.5%). 전부 내 Supabase에 쌓인 이벤트를 직접 집계한 거예요 — 외부 분석 도구 0개, 추가 비용 0원, 데이터도 100% 내 것.
DB를 편하게 보는 법
표를 직접 뒤지지 말고, 나에게 맞는 화면으로
왜 DB를 직접 열어 보면 안 되나요
Supabase 화면에서 표를 직접 볼 수도 있지만, 그건 날것이에요 — 원하는 정렬도, 보기 좋은 요약도 없고, 잘못 눌러 데이터를 고칠 위험도 있어요. 매번 표를 뒤지는 대신, 내가 편한 방식으로 정리된 화면을 따로 두는 게 좋아요. 두 가지 방법이 있어요.

방법 A — 나만의 관리자 웹(admin 페이지)을 만든다
내 앱 안에 /admin 같은 비공개 페이지를 하나 두고, 거기서 내가 보고 싶은 대로 — 최신순 정렬, 오늘 신청자 수, 상태별 필터 — 보여주게 만드는 거예요. 데이터를 실수로 고칠 걱정 없이 '보기 전용'으로 만들 수 있어요.
/admin 페이지를 만들어줘. applications 테이블을 최신순으로 보여주고, 맨 위에 '오늘 신청 수 / 전체 신청 수'를 크게 표시해줘. - 보기 전용(여기서 데이터 수정·삭제는 안 되게) - 비밀번호로 잠가서 나만 볼 수 있게 - 시간은 한국 시간(KST)으로 표시
방법 B — 스프레드시트로 자동 복사(cron)
“나는 그냥 구글 시트에서 보고 싶다”면 — 일정 시간마다 자동으로 DB 내용을 시트에 복사하게 할 수 있어요. 이 '정해진 시간에 자동 실행'을 cron(크론) 작업이라고 해요. 시트에 쌓이면 정렬·필터·피벗·차트 다 익숙한 방식으로 볼 수 있죠.
| A | B | C | |
|---|---|---|---|
| 1 | name | created_at (KST) | |
| 2 | 이바다 | sea@… | 2026-07-21 14:07 |
| 3 | 김하늘 | sky@… | 2026-07-21 14:03 |
DB 내용이 이렇게 시트에 최신순으로 쌓여요 — 익숙한 정렬·필터로 봅니다. (스프레드시트 목업)
매일 아침 9시에 applications 테이블 전체를 구글 스프레드시트에 자동으로 복사하는 cron 작업을 만들어줘. 시트에는 이름·이메일·신청시각(KST)만, 최신순으로. 설정에 필요한 것(구글 시트 연동 방법 등)을 단계별로 안내해줘.
※ Vercel에는 Cron Jobs기능이 있어서, “매일 9시에 이 작업 실행”을 앱 안에 넣어둘 수 있어요. Claude가 설정 파일까지 만들어줍니다.
어느 쪽을 고르나요
안 하면 크게 다치는 것
RLS·시간(UTC) 문제와 그 밖의 함정
Supabase RLS — 안 켜면 내 데이터가 전부 공개돼요
RLS가 꺼진 테이블은 누구나 읽고, 고치고, 지울 수 있어요
RLS(Row Level Security)는 “누가 어느 행(row)을 볼 수 있는지” 정하는 DB의 출입 규칙이에요.
RLS가 꺼진 테이블은 브라우저에 들어 있는 공개용 키(sb_publishable_... 또는 옛 anon)만 있으면 누구든 읽고, 수정하고, 삭제할 수 있어요.이 키는 원래 누구나 볼 수 있게 설계된 키라서, 개발자 도구만 열어도 보여요. Supabase 대시보드에 ‘RLS disabled’ 경고가 뜨는 테이블은 사실상 공개 상태라는 뜻이에요.
기억할 규칙 2개
- 테이블을 만들면 RLS부터 켜요. 브라우저에서 접근하는 테이블이라면 예외 없이요.
- Claude에게 ‘RLS 정책도 같이 만들어줘’라고 말해요. 켜기만 하면 아무도 못 읽으니, “누가 무엇을 할 수 있는지” 정책이 같이 있어야 앱이 돌아가요.
Supabase 테이블을 만들 때마다 RLS(Row Level Security)를 반드시 켜줘. RLS 정책도 같이 만들어줘. - 로그인한 사용자는 자기 데이터만 읽고 쓰게 해줘. - 누구나 봐도 되는 데이터가 아니면 공개 읽기는 허용하지 마. - 지금 있는 테이블 중에 RLS가 꺼진 게 있는지도 확인해서 목록으로 알려줘. - secret(service_role) 키는 서버 코드에서만 쓰고, NEXT_PUBLIC_ 이름으로 노출하지 마.
새 키 이름: 공개용은 sb_publishable_..., 비밀용은 sb_secret_.... 옛 anon / service_role 키는 올해 말쯤 중단될 예정이에요. 비밀용 키는 RLS를 건너뛰는 강한 키라 서버에서만 써요.
시간(UTC) — 비개발자가 가장 많이 데는 곳
실화 — 사용자가 뭔가 할 때마다 시간이 8~9시간씩 밀렸다
왜 이런 일이 생기나
DB는 시간을 보통 UTC(세계 표준시)로 저장해요. 한국(KST)은 UTC보다 9시간 빠릅니다. 그래서 화면에 “9시간 늦게” 보이면, 초보자는 저장된 값에 +9를 더해 '고치고' 싶어져요.
문제는 — 저장할 때 한 번, 보여줄 때 한 번, 나중에 마이그레이션에서 또 한 번, 이렇게 여기저기서 +9를 중복으로 더하면시간이 계속 밀립니다. “볼 때마다 8시간씩 늘어난다”는 게 정확히 이 증상이에요.
이렇게 하면 안 돼요 — 밀림의 원인
// 저장하면서 시간을 강제로 +9 — 이러면 이중 변환으로 밀린다
const d = new Date(created_at);
d.setHours(d.getHours() + 9); // ✗ 손으로 오프셋을 더함
await save({ created_at: d.toISOString() }); // ✗ 게다가 다시 UTC로 되돌려 저장하나의 규칙만 지키면 끝
- 저장은 언제나 UTC로. 컬럼 타입은
timestamptz, 값은new Date()(=UTC) 그대로. 코드에서 +9를 더하지 않는다. - 보여줄 때만 한국 시간으로 변환한다. (
Asia/Seoul타임존으로 포맷) - “며칠에 몇 건” 같은 날짜 집계도 한국 시간 기준으로 묶는다. (UTC로 묶으면 자정 근처 데이터가 하루 어긋남)
- 내가 말하는 시각은 항상 한국 시간이다. “오전 10시에 마감”, “매일 9시에 실행” 같은 지시를 코드·DB·예약에 넣을 땐 AI가 UTC로 변환해서 넣는다. 헷갈리면 먼저 되묻는다.
가장 헷갈리는 곳 — 내가 시간을 ‘말할 때’
위 1~3번은 ‘이미 저장된 시간’ 이야기예요. 그런데 반대로 내가 시간을 지시할 때도 함정이 있어요. 비개발자는 당연히 한국 시간으로 말하는데(“오전 10시에 닫아줘”), AI가 그 ‘10시’를 그대로 UTC로 넣으면 또 9시간이 어긋납니다. 그래서 이렇게 되게 시켜두는 게 좋아요.
나: “응모 마감을 오전 10시로 해줘”
AI(이렇게 되묻거나 변환): “말씀하신 10시는 한국 시간 기준 맞죠? DB엔 UTC로 변환해서 01:00(UTC)로 저장할게요.”
특히 예약 실행(cron)이 위험해요 — Vercel Cron 같은 건 대부분 UTC 기준이라, “매일 아침 9시(KST)”는 cron으로는 0 0 * * *(UTC 0시)로 적어야 맞습니다. 타임존이 안 정해지면 AI가 UTC로 도는 걸 알려주고 확인받게 하세요.
// 저장: 손대지 않는다 (UTC 그대로)
await save({ created_at: new Date().toISOString() });
// 표시: 볼 때만 한국 시간으로
new Intl.DateTimeFormat("ko-KR", {
timeZone: "Asia/Seoul",
dateStyle: "medium",
timeStyle: "short",
}).format(new Date(row.created_at));
시간 처리 규칙을 아래로 통일해줘. 코드 전체를 이 기준으로 점검하고, 어긋난 곳을 고쳐줘: 1. DB 저장은 항상 UTC(timestamptz), 코드에서 +9시간 같은 오프셋을 절대 더하지 않는다. 2. 화면 표시와 날짜별 집계에서만 Asia/Seoul로 변환한다. 3. 내가 시각을 말하면(예: "오전 10시 마감", "매일 9시 실행") 그건 한국 시간이다. 그걸 코드·DB·예약(cron)에 넣을 땐 UTC로 변환해서 넣고, 애매하면 먼저 나에게 되물어. (cron은 UTC 기준이라 "KST 9시"는 "0 0 * * *"로 적어야 함) 4. 지금 이미 시간이 밀려 저장된 데이터가 있는지 먼저 조회해서 보여주고, 고치는 건(마이그레이션) 내 승인을 받은 다음에 해.
이미 밀려서 저장된 데이터가 있다면
그 밖에 미리 알면 좋은 함정
테스트 데이터, 진짜 데이터와 섞이지 않게
DB를 하나(실서비스)만 쓰기로 했다면, 내가 테스트하며 만든 데이터가 진짜 사용자 데이터에 섞여들어가요. 나중에 “테스트한 것만 지워줘”가 안 되면 곤란하죠. 그래서 처음부터 '이건 테스트다'라는 표시를 남겨두는 게 핵심이에요. 내 앱에 로그인(계정)이 있느냐 없느냐로 방법이 갈려요.
A. 계정(로그인)이 있는 앱
- 테스트 계정에 '테스트용' 표시를 남기기 — DB의 사용자 표에
is_test같은 칸을 두고 내 계정만 표시. 나중에 “is_test인 것만 지워줘”가 됩니다. - 나만 아는 숨은 테스트 로그인 — 구글 로그인을 붙였어도 매번 구글로 들어가긴 번거로우니, 남들에겐 안 보이는 경로(예:
/test-login)에서 내 테스트 계정으로만 로그인하게 만들어 두기. - 테스트로 만든 자료는 지워달라고 할 때 지우면 됩니다 (삭제는 Part 3 규칙대로 먼저 확인).
B. 계정이 없는 앱 (예: 심리테스트처럼 널리 뿌리는 것)
로그인이 없으면 ‘누가 만든 데이터인지’ 잡을 앵커가 없어요. 이럴 땐 브라우저에 랜덤한 식별값(익명 ID)을 하나 만들어 쿠키·로컬스토리지에 저장해 둡니다. 같은 사람이 다시 오면 같은 값이라 ‘같은 방문자’로 묶을 수 있고, 그 값을 데이터에 함께 기록하면 “이 익명 ID(=내 브라우저)가 만든 건 테스트”라고 구분·삭제할 수 있어요.
실서비스 DB 하나만 쓸 거야. 대신 내 테스트 데이터가 진짜 데이터와 섞이지 않게 해줘: - (계정 있는 앱) 사용자 표에 is_test 칸을 만들고 내 테스트 계정만 test로 표시. 구글 로그인은 붙이되, 남들에겐 안 보이는 숨은 경로에서 내 테스트 계정으로 로그인할 수 있게 해줘. - (계정 없는 앱) 방문자마다 랜덤 익명 ID를 만들어 쿠키/로컬스토리지에 저장하고, 저장되는 데이터에 그 ID를 같이 기록해줘. - 나중에 "테스트 데이터만 지워줘"라고 하면 지울 수 있게 (지우기 전엔 나에게 먼저 확인).