[feature] 메인페이지 카드 히트맵 트래킹 추가#1542
Conversation
- CLUB_CARD_VIEWED, SCROLL_DEPTH_REACHED 이벤트 상수 추가 - PAGE_NAME 상수 추가 (main, webview-main, introduce) - BREAKPOINT 기준 device_type 판별 유틸 추가 (mini_mobile/mobile/tablet/laptop/desktop)
- useScrollTracking 훅 구현 (25/50/75/100% 마일스톤) - passive scroll 이벤트 리스너로 성능 최적화 - page 의존성 배열 추가 및 reached ref 리셋으로 stale closure 방지 - MainPage에 useScrollTracking 적용
- IntersectionObserver + 3초 dwell timer로 CLUB_CARD_VIEWED 이벤트 수집 - ([entry]) 구조 분해로 단일 엔트리 처리 (forEach 배치 버그 수정) - 클릭 시 scroll_y, card_top_in_viewport, device_type 수집 - page prop으로 main/webview-main/introduce 페이지 구분 - MainPage, WebviewMainPage, IntroSection에 index·page prop 적용
- ClubCard Viewed/Clicked, Scroll Depth Reached 이벤트 설명 - 뷰포트 히트맵, CTR, 스크롤 퍼널 등 5가지 분석 시나리오 정리
- docs/features/main/ → docs/features/event/ 로 이동 - 세 이벤트 테이블에 device_type, page 속성 추가 - getDeviceType.ts 관련 코드 섹션에 추가
- mixpanel.md 업데이트 (카드 히트맵 트래킹 시나리오 반영) - mixpanel-ab.md 추가 (A/B 테스트 유의성 검정 가이드)
- 모아동 자체 실험 프레임워크(Super Property 방식) 설명 추가 - $experiment_started 기반 쿼리 → experiment.key 프로퍼티 breakdown으로 수정 - DAU 500명 기준 현실적 샘플 크기 계산 추가 - Bonferroni 보정 외부 계산기 활용 방법 추가 - 카드 트래킹 데이터 기반 Primary Metric 예시 및 쿼리 추가 - Sequential Testing 문구 제거 (자체 프레임워크에서 미지원)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
Warning
|
| 계층 / 파일(들) | 요약 |
|---|---|
이벤트 및 페이지 식별자 상수 정의 frontend/src/constants/eventName.ts |
USER_EVENT에 CLUB_CARD_VIEWED, SCROLL_DEPTH_REACHED 이벤트 추가 및 PAGE_NAME 상수(MAIN, WEBVIEW_MAIN, INTRODUCE) 추가 |
기기 유형 분류 유틸리티 frontend/src/utils/getDeviceType.ts |
뷰포트 너비 기반 기기 유형 분류 함수(mini_mobile, mobile, tablet, laptop, desktop) 구현 |
스크롤 깊이 추적 훅 frontend/src/hooks/Mixpanel/useScrollTracking.ts |
문서 높이 대비 스크롤 진행률 계산 및 25/50/75/100% 마일스톤 도달 시 SCROLL_DEPTH_REACHED 이벤트 발송 |
ClubCard 카드 보기 및 클릭 추적 frontend/src/pages/MainPage/components/ClubCard/ClubCard.tsx |
IntersectionObserver로 카드 50% 이상 3초 체류 시 CLUB_CARD_VIEWED 발송, 클릭 시 위치/페이지/기기 메타데이터 포함 |
메인 페이지 및 웹뷰 스크롤 추적 통합 frontend/src/pages/MainPage/MainPage.tsx, frontend/src/pages/WebviewMainPage/WebviewMainPage.tsx |
각 페이지에서 스크롤 추적 훅 호출 및 ClubCard에 index, page props 전달 |
소개 페이지 ClubCard 페이지 식별자 적용 frontend/src/pages/IntroducePage/components/sections/1.IntroSection/IntroSection.tsx |
ClubCard에 page={PAGE_NAME.INTRODUCE} prop 명시 |
Mixpanel 추적 인프라 정제 frontend/src/hooks/Mixpanel/useMixpanelTrack.ts |
이벤트 페이로드에서 distinct_id 필드 제거 |
카드 히트맵 추적 분석 문서 frontend/docs/features/event/card-heatmap-tracking.md |
이벤트 정의, 분석 방법(히트맵 버킷, CTR 계산, 스크롤 이탈 퍼널 등), 해석 주의사항, 관련 코드 파일 정리 |
A/B 테스트 통계 유의성 검정 가이드
| 계층 / 파일(들) | 요약 |
|---|---|
A/B 테스트 통계 검정 종합 가이드 frontend/.claude/commands/mixpanel-ab.md |
실험 설계 체크리스트(표본 크기, Primary Metric, SRM 검증), 진행 중 규칙(피킹 금지, 최소 기간), 결과 해석(Bonferroni 보정, 신뢰도 구간), Mixpanel 쿼리 패턴, 금지 행동 목록 문서화 |
Mixpanel 커맨드 문서 업데이트 frontend/.claude/commands/mixpanel.md |
/mixpanel-ab 커맨드 참조 및 실험 설계 체크리스트 사용 지침 추가 |
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related issues
- [feature] MOA-847 메인 카드 히트맵 트래킹 구현 #1541 — 동일한 카드 히트맵 추적 기능을 구현하며 ClubCard, 스크롤 추적 훅, 이벤트/페이지 상수 등 동일한 코드 영역을 수정합니다.
Possibly related PRs
- Moadong/moadong#856 —
frontend/src/constants/eventName.ts수정하여 Mixpanel 이벤트 상수를 통합/확장하고PAGE_VIEW/PAGE_NAME같은 페이지 식별자 추가 - Moadong/moadong#1383 —
frontend/.claude/commands/mixpanel.md업데이트 및mixpanel-ab문서 도입, 본 PR의 A/B 테스트 가이드와 동일한 Mixpanel Claude 커맨드 기반 구축 - Moadong/moadong#773 —
frontend/src/pages/MainPage/components/ClubCard/ClubCard.tsx수정 (본 PR은 Mixpanel 체류/보기/클릭 추적 및 새로운page/indexprops 추가, 검색된 PR은 카드 UI 구조 리팩토링)
Suggested reviewers
- oesnuj
- suhyun113
- lepitaaar
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | PR 제목 '[feature] 메인페이지 카드 히트맵 트래킹 추가'는 변경 사항의 주요 내용인 메인페이지 카드 히트맵 트래킹 기능 추가를 명확하고 간결하게 요약합니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
feature/#1541-card-heatmap-tracking-MOA-847
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
✅ UI 변경사항 없음
전체 57개 스토리 · 22개 컴포넌트 |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
frontend/.claude/commands/mixpanel-ab.md (1)
43-43: ⚡ Quick win코드 블록에 언어 식별자를 추가하세요.
정보성 텍스트 블록들이 언어 식별자 없이 펜스 코드 블록으로 작성되어 있습니다. 마크다운 렌더러와 접근성 도구가 올바르게 처리할 수 있도록
text식별자를 추가하는 것을 권장합니다.♻️ 제안하는 수정 사항
예시 (Line 43):
-``` +```text ⚠️ Mixpanel은 신뢰구간 90% / 99% 두 가지만 제공 (95%는 없음)나머지 블록들도 동일하게 적용하세요.
As per coding guidelines, static analysis tool markdownlint-cli2 flags fenced code blocks without language identifiers for improved rendering consistency.
Also applies to: 62-62, 74-74, 131-131, 140-140, 155-155, 169-169, 179-179, 190-190
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/.claude/commands/mixpanel-ab.md` at line 43, Add a language identifier (use `text`) to each fenced code block in the document so markdownlint and renderers can treat them as plain text; for example update the block containing "⚠️ Mixpanel은 신뢰구간 90% / 99% 두 가지만 제공 (95%는 없음)" to start with ```text and apply the same change to the other similar fenced blocks in the file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/docs/features/event/card-heatmap-tracking.md`:
- Around line 50-54: The markdown shows multiple fenced code blocks without a
language tag (e.g., the blocks containing "0~200px: 상단", "CTR = ClubCard Clicked
수 / ClubCard Viewed 수 (club_id 기준)", and the reach percentages like "25% 도달:
X명"), which triggers MD040; fix by adding a language identifier such as "text"
to each of these triple-backtick fences so they become ```text ... ```; update
every similar block in this file (including the other occurrences noted around
the CTR and percentage blocks) to remove the lint warnings.
- Around line 27-29: Update the "ClubCard Viewed" property descriptions to
reflect that values are recorded at the 3-second dwell event (when dwell_ms
threshold is met) rather than at entry; specifically change the phrasing for
`scroll_y` and `card_top_in_viewport` from "진입 시점" to something like "체류 충족 시점
(3초)" and clarify `dwell_ms` denotes the fixed threshold (3000 ms); ensure the
property table and any nearby text mention the 3s dwell event so `ClubCard
Viewed` documentation matches the implementation that logs values when the
dwell_ms condition is satisfied.
In `@frontend/src/hooks/Mixpanel/useScrollTracking.ts`:
- Around line 35-37: The effect that registers the scroll listener in
useScrollTracking currently only records milestones when a scroll event fires,
so restored/initial scroll positions can be missed; after calling
window.addEventListener('scroll', handleScroll, { passive: true }) inside the
useEffect, immediately invoke handleScroll() once to evaluate and record the
initial scroll state (ensure you reference the same handleScroll function used
for the listener); keep the existing cleanup that calls
window.removeEventListener('scroll', handleScroll) unchanged.
---
Nitpick comments:
In `@frontend/.claude/commands/mixpanel-ab.md`:
- Line 43: Add a language identifier (use `text`) to each fenced code block in
the document so markdownlint and renderers can treat them as plain text; for
example update the block containing "⚠️ Mixpanel은 신뢰구간 90% / 99% 두 가지만 제공 (95%는
없음)" to start with ```text and apply the same change to the other similar fenced
blocks in the file.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 36cf00cf-f862-4f5a-9b32-8f177712a797
📒 Files selected for processing (11)
frontend/.claude/commands/mixpanel-ab.mdfrontend/.claude/commands/mixpanel.mdfrontend/.gitignorefrontend/docs/features/event/card-heatmap-tracking.mdfrontend/src/constants/eventName.tsfrontend/src/hooks/Mixpanel/useScrollTracking.tsfrontend/src/pages/IntroducePage/components/sections/1.IntroSection/IntroSection.tsxfrontend/src/pages/MainPage/MainPage.tsxfrontend/src/pages/MainPage/components/ClubCard/ClubCard.tsxfrontend/src/pages/WebviewMainPage/WebviewMainPage.tsxfrontend/src/utils/getDeviceType.ts
card_top_in_viewport 계산 시 조건 체크와 값 읽기에서 getBoundingClientRect()를 두 번 호출하던 코드를 IIFE로 묶어 단일 호출로 정리
- dwell_ms를 고정값 3000에서 실제 체류 시간(Date.now() - intersectTime)으로 변경 - card_top_in_viewport를 타이머 만료 시점이 아닌 카드 진입 시점의 위치로 캡처 - useMixpanelTrack에서 SDK가 자동 포함하는 distinct_id 중복 전송 제거
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/docs/features/event/card-heatmap-tracking.md`:
- Line 29: Update the documentation for the field `dwell_ms` to reflect the
implemented behavior: instead of saying it is a fixed 3000ms, describe it as the
actual dwell time computed as Date.now() - intersectTime and recorded at the
moment the threshold is met (i.e., the first time the dwell exceeds the minimum
3000ms), so phrase it as “actual dwell time at threshold (minimum 3000ms)”.
Ensure the text references `dwell_ms` and `intersectTime` to match the
implementation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 35899143-5f2a-4d13-be5a-877c07ec6acb
📒 Files selected for processing (7)
frontend/docs/features/event/card-heatmap-tracking.mdfrontend/src/constants/eventName.tsfrontend/src/hooks/Mixpanel/useMixpanelTrack.tsfrontend/src/hooks/Mixpanel/useScrollTracking.tsfrontend/src/pages/MainPage/MainPage.tsxfrontend/src/pages/MainPage/components/ClubCard/ClubCard.tsxfrontend/src/pages/WebviewMainPage/WebviewMainPage.tsx
💤 Files with no reviewable changes (1)
- frontend/src/hooks/Mixpanel/useMixpanelTrack.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- frontend/src/constants/eventName.ts
- frontend/src/pages/MainPage/MainPage.tsx
- frontend/src/pages/WebviewMainPage/WebviewMainPage.tsx
- frontend/src/hooks/Mixpanel/useScrollTracking.ts
- frontend/src/pages/MainPage/components/ClubCard/ClubCard.tsx
- card_top_in_viewport 설명을 진입 시점으로 수정 - dwell_ms를 실제 체류 시간으로 설명 수정 - 코드펜스 언어 태그 추가 (MD040)
suhyun113
left a comment
There was a problem hiding this comment.
메인페이지는 카테고리가 전체일 경우 동아리가 많으니 스크롤 피로도가 생길 수도 있을 것 같네요.
모바일 데스크탑 모두 사용자가 어떤 부분에서 체류하냐에 따라 많은 정보를 얻을 수 있을 것 같습니다! 테스트 후 결과 공유해주세요~ 수고하셨습니당
3초 너무 길지 않나?! 그전에 꼭 시간이 지나야만 하는건가 ?! 스크롤 하다가 관심있으면 읽을텐데 라는 생각! |
모바일이 훨씬 사용자가 많고, 제가 쓴다고 했을 때 3초도 긴 시간 같긴 하네요 ㅋㅋ CoolTime은 찾아보니까 재진입 여부 체크하는 것 같은데 되게 유의미해보이고용 인사이트 감사합니다 🚀🚀 |
#️⃣연관된 이슈
📝작업 내용
배경
메인페이지에서 어떤 카드가 많이 클릭되는지 알고 싶은데, 기존 ClubCard Clicked만으로는 부족했습니다.
변경 사항
1. 카드 노출 트래킹 추가 (ClubCard Viewed)
카드가 화면에 50% 이상 들어온 뒤 3초가 지나면 이벤트를 기록합니다. 단순히 스크롤하며 지나친 카드는 제외하고, 실제로 읽은
카드만 잡기 위해 3초 기준을 사용했습니다.
2. 클릭 위치 데이터 추가 (ClubCard Clicked 확장)
클릭 시점의 scroll_y와 뷰포트 기준 카드 위치(card_top_in_viewport)를 함께 기록합니다. 이 두 값 조합으로 화면 어느
영역에서 클릭이 발생했는지 히트맵처럼 분석할 수 있습니다.
3. 스크롤 깊이 트래킹 추가 (Scroll Depth Reached)
25 / 50 / 75 / 100%지점 도달 시 이벤트를 기록합니다. 유저가 어디까지 탐색하다 이탈하는지 파악하기 위함입니다.4. 디바이스 타입 구분 (device_type)
card_top_in_viewport 값이 모바일(1열)과 데스크탑에서 의미가 달라서, 기존 BREAKPOINT 상수 기준으로 디바이스를 구분해 함께
기록합니다.
5. 트래킹 데이터 품질 개선
dwell_ms: 고정값 3000 → 실제 체류 시간(Date.now() - intersectTime)으로 변경. 탭 전환 등 브라우저 타이머 지연이 있을 경우 실제 값을 반영card_top_in_viewport: 3초 타이머 만료 시점이 아닌, 카드가 뷰포트에 진입한 시점(entry.boundingClientRect.top)으로 캡처useMixpanelTrack에서 SDK가 자동 포함하는distinct_id중복 전송 제거이걸로 뭘 볼 건가
AI관련 문서 추가
AB 테스트를 위한 md파일을 추가했습니다.
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선사항