[feature] Mixpanel 로컬 환경 비활성화 및 세션 ID 연동#1004
Conversation
- localhost에서 Mixpanel 비활성화 - session_id 파라미터로 사용자 식별 - 프로덕션 호스트네임 체크 로직 제거
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | 변경 내용 |
|---|---|
Mixpanel 초기화 frontend/src/utils/initSDK.ts |
PRODUCTION_HOSTNAMES 기반 체크를 제거하고 LOCALHOST_HOSTNAME으로 로컬 감지 변경. 로컬이 아닐 때 URL 쿼리에서 session_id 파싱 후 mixpanel.identify(sessionId) 호출 및 쿼리 제거(세션 ID 유효성 검사 TODO). VITE_MIXPANEL_TOKEN 경로는 유지. |
페이지 트래킹 훅 frontend/src/hooks/useTrackPageView.ts |
익명 visibilitychange 리스너를 명명된 handleVisibilityChange로 분리해 등록/해제 정리. pageName을 useEffect 의존성에 추가하고, 문서 숨김 시 페이지 지속시간 트래킹 호출 위치 명확화(클린업 개선). |
앱 초기화/엔트리 frontend/src/index.tsx |
initializeChannelService의 import 및 호출 제거로 ChannelService 초기화 단계 삭제. initializeKakaoSDK, initializeMixpanel, initializeSentry 호출은 유지. |
Sequence Diagram(s)
sequenceDiagram
%%{init: {"themeVariables":{"actorBorder":"#6b7280","actorBg":"#f8fafc","noteBorder":"#c7d2fe","noteBg":"#eef2ff"}}}%%
participant Browser
participant Router as "React Router\n(useSearchParams)"
participant Hook as "useTrackPageView"
participant SDK as "initSDK / Mixpanel"
Browser->>Router: 요청 (URL, ?session_id=...)
Router->>Hook: searchParams 전달
Hook->>SDK: isLocalhost? 검사
alt not localhost
Hook->>SDK: session_id 파싱 요청
alt session_id 존재
Hook->>SDK: mixpanel.identify(session_id)
SDK->>Browser: history.replaceState (쿼리 제거)
end
Hook->>SDK: mixpanel.track('Page View', { pageName })
else localhost
note right of SDK: Mixpanel 로컬 초기화 비활성화
end
Browser->>Hook: visibilitychange 이벤트
Hook->>SDK: handleVisibilityChange -> document.hidden? -> mixpanel.track('Duration')
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related issues
- MOA-481: Mixpanel 로컬 환경 비활성화 및 크로스 플랫폼 사용자 추적 구현 — 로컬호스트 비활성화 및 session_id 기반 식별 목표와 일치합니다.
- [feature] MOA-481 Mixpanel 로컬 환경 비활성화 및 크로스 플랫폼 사용자 추적 구현 #1003 — localhost 비활성화 및 session_id 기반 식별 요구사항과 중복되는 목표를 가집니다.
Possibly related PRs
- [feature] Mixpanel IP 추적하도록 변경 및 ignore_dnt 적용 #850 —
frontend/src/utils/initSDK.ts의 Mixpanel 초기화 옵션/설정 변경과 코드 레벨 연관성이 높습니다. - [fix] Mixpanel 활성 호스트에 www 도메인 추가 #876 — PRODUCTION_HOSTNAMES/호스트 체크 관련 초기화 로직 수정과 관련됩니다.
- [feature] 프로덕션 외 Mixpanel 비활성화 #869 — 호스트 기반 활성화 로직 변경과 직접적인 유사성이 있습니다.
Suggested reviewers
- oesnuj
- lepitaaar
- suhyun113
Pre-merge checks and finishing touches
❌ Failed checks (1 warning, 1 inconclusive)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
|
| Out of Scope Changes check | ❓ Inconclusive | initializeChannelService 제거는 linked issue의 명시적 요구사항에 없지만, 로컬 환경 비활성화 목표와 무관한 변경으로 보여 범위 밖 변경일 가능성이 있습니다. | initializeChannelService 제거가 MOA-481 이슈의 명시적 요구사항인지, 아니면 별도 이슈에서 파생된 변경인지 확인하고 이를 관련 이슈에 연결하거나 설명을 추가해주시기 바랍니다. |
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | 제목 '[feature] Mixpanel 로컬 환경 비활성화 및 세션 ID 연동'은 PR의 주요 변경사항을 명확하게 요약하고 있습니다. 로컬 환경 비활성화와 세션 ID 연동이라는 핵심 내용을 정확히 반영하고 있습니다. |
| Linked Issues check | ✅ Passed | PR의 코드 변경사항들(localhost 체크 추가, session_id 파싱 및 제거, initializeChannelService 제거, 의존성 배열 수정)은 linked issue MOA-481의 목표(로컬 환경 비활성화, 세션 ID 연동)를 충족하고 있습니다. |
✨ Finishing touches
- 📝 Generate docstrings
📜 Recent review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
frontend/src/utils/initSDK.ts
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx,js,jsx}: Replace magic numbers with named constants for clarity
Replace complex/nested ternaries withif/elseor IIFEs for readability
Assign complex boolean conditions to named variables for explicit meaning
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)
Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Define constants near related logic or ensure names link them clearly to avoid silent failures
Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Files:
frontend/src/utils/initSDK.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/utils/initSDK.ts
🧠 Learnings (1)
📚 Learning: 2025-08-24T17:33:23.092Z
Learnt from: suhyun113
Repo: Moadong/moadong PR: 698
File: frontend/src/hooks/queries/applicants/useDeleteApplicants.ts:10-16
Timestamp: 2025-08-24T17:33:23.092Z
Learning: The codebase has inconsistent console logging patterns across files - mixing console.log/console.error for errors, using both Korean and English messages, and various formatting styles (template literals vs separate arguments, with/without emojis). A unified logging format like `console.error('[ModuleName] Operation failed:', error)` should be established for better debugging consistency.
Applied to files:
frontend/src/utils/initSDK.ts
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.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
frontend/src/utils/initSDK.ts
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx,js,jsx}: Replace magic numbers with named constants for clarity
Replace complex/nested ternaries withif/elseor IIFEs for readability
Assign complex boolean conditions to named variables for explicit meaning
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)
Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Define constants near related logic or ensure names link them clearly to avoid silent failures
Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Files:
frontend/src/utils/initSDK.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/utils/initSDK.ts
- 페이지 방문 및 체류 시간 이벤트에 session_id 파라미터 연동
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
frontend/src/hooks/useTrackPageView.ts (1)
35-35:sessionId || undefined표현 단순화 고려.
sessionId가null또는 문자열인 경우,sessionId || undefined는 작동하지만 약간 불필요한 표현입니다. 다음 중 하나를 고려하세요:
sessionId ?? undefined(nullish coalescing 사용)- 또는 그냥
sessionId(Mixpanel이 null 처리 가능한 경우)기능에는 영향이 없으므로 선택적 개선 사항입니다.
🔎 선택적 수정
session_id: sessionId || undefined, + // 또는 + session_id: sessionId ?? undefined,Also applies to: 48-48
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
frontend/src/hooks/useTrackPageView.ts
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx,js,jsx}: Replace magic numbers with named constants for clarity
Replace complex/nested ternaries withif/elseor IIFEs for readability
Assign complex boolean conditions to named variables for explicit meaning
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)
Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Define constants near related logic or ensure names link them clearly to avoid silent failures
Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Files:
frontend/src/hooks/useTrackPageView.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/hooks/useTrackPageView.ts
🧠 Learnings (2)
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Applied to files:
frontend/src/hooks/useTrackPageView.ts
📚 Learning: 2025-03-19T05:18:07.818Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Applied to files:
frontend/src/hooks/useTrackPageView.ts
🔇 Additional comments (2)
frontend/src/hooks/useTrackPageView.ts (2)
54-59: 좋은 리팩토링입니다!
handleVisibilityChange함수를 명시적으로 추출하여 동일한 함수 참조로 이벤트 리스너를 추가/제거할 수 있게 되었습니다. 이는 클린업 로직의 정확성을 보장하며 코드 가독성도 향상시킵니다.Also applies to: 64-64
66-66: 의존성 배열의searchParams추가를 재검토하세요.
searchParams를 의존성 배열에 추가하면 URL 쿼리 파라미터가 변경될 때마다 전체 effect가 재실행되어 페이지 방문 이벤트(Visited)가 다시 추적됩니다.이것이 의도된 동작인지 확인이 필요합니다:
- 동일 페이지에서 쿼리 파라미터만 변경될 때 새로운 "Visited" 이벤트를 발생시키는 것이 맞는지?
- 일반적으로 페이지 방문은 pathname 변경 시에만 추적하는 것이 일반적입니다.
session_id만 감지하려면 별도의 effect로 분리하는 것을 권장합니다 (이전 코멘트 참조).
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/utils/initSDK.ts (1)
7-14: 초기화되지 않은 Mixpanel 인스턴스에 메서드를 호출할 수 있습니다.
VITE_MIXPANEL_TOKEN이 없으면mixpanel.init()이 실행되지 않지만, 이후 15-24줄에서mixpanel.disable()또는mixpanel.identify()가 여전히 호출됩니다. 초기화되지 않은 상태에서 메서드 호출은 예상치 못한 동작을 유발할 수 있습니다.🔎 제안하는 수정
export function initializeMixpanel() { if (import.meta.env.VITE_MIXPANEL_TOKEN) { mixpanel.init(import.meta.env.VITE_MIXPANEL_TOKEN, { ignore_dnt: true, debug: false, }); + } else { + return; } if (window.location.hostname === LOCALHOST_HOSTNAME) { mixpanel.disable(); + return; } else { const urlParams = new URLSearchParams(window.location.search); const sessionId = urlParams.get('session_id'); if (sessionId) { // TODO: sessoin_id 검증 추가 mixpanel.identify(sessionId); } } }
♻️ Duplicate comments (2)
frontend/src/utils/initSDK.ts (2)
19-23: 세션 ID 검증이 누락되었습니다.URL 파라미터에서 추출한
session_id를 검증 없이mixpanel.identify()에 전달하고 있습니다. 빈 문자열(?session_id=)이나 예상치 못한 형식의 값이 전송될 수 있습니다. TODO 코멘트로만 남겨두지 말고 구현해야 합니다.🔎 제안하는 수정
} else { const urlParams = new URLSearchParams(window.location.search); const sessionId = urlParams.get('session_id'); - if (sessionId) { - // TODO: sessoin_id 검증 추가 + if (sessionId && sessionId.trim().length > 0 && /^[a-zA-Z0-9_-]+$/.test(sessionId)) { mixpanel.identify(sessionId); + } else if (sessionId) { + console.warn('Invalid session_id format:', sessionId); } }
5-5: 로컬호스트 체크가 불완전합니다.현재 상수는
'localhost'만 포함하고 있어127.0.0.1이나[::1](IPv6 loopback)로 접근 시 Mixpanel이 비활성화되지 않습니다.🔎 제안하는 수정
-const LOCALHOST_HOSTNAME = 'localhost'; +const LOCAL_HOSTNAMES = ['localhost', '127.0.0.1', '[::1]'] as const;그리고 line 15에서:
-if (window.location.hostname === LOCALHOST_HOSTNAME) { +if (LOCAL_HOSTNAMES.includes(window.location.hostname)) {
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
frontend/src/hooks/useTrackPageView.tsfrontend/src/utils/initSDK.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/hooks/useTrackPageView.ts
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx,js,jsx}: Replace magic numbers with named constants for clarity
Replace complex/nested ternaries withif/elseor IIFEs for readability
Assign complex boolean conditions to named variables for explicit meaning
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)
Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Define constants near related logic or ensure names link them clearly to avoid silent failures
Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Files:
frontend/src/utils/initSDK.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/utils/initSDK.ts
oesnuj
left a comment
There was a problem hiding this comment.
로깅 분리 작업 수고하셨습니다 👍
앱에서 사용하는 session_id가 충분히 유니크하다면 이 구조도 문제 없을 것 같습니다.
React Native 쪽 코드도 한 번 같이 확인해보겠습니다.
- 세션 탈취 및 데이터 오염 방지를 위해 Mixpanel 식별 후 URL 세탁 로직 추가
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/utils/initSDK.ts (1)
7-13: 초기화 상태 검증이 누락되었습니다.
VITE_MIXPANEL_TOKEN이 없으면mixpanel.init()이 실행되지 않지만, 이후 Line 15-29의 로직은 여전히 실행되어 Line 21에서 초기화되지 않은mixpanel.identify()를 호출할 수 있습니다.초기화 여부를 확인하는 플래그를 추가하거나, 토큰이 없을 경우 early return하세요.
🔎 제안하는 수정
export function initializeMixpanel() { + if (!import.meta.env.VITE_MIXPANEL_TOKEN) { + return; + } + - if (import.meta.env.VITE_MIXPANEL_TOKEN) { - mixpanel.init(import.meta.env.VITE_MIXPANEL_TOKEN, { - ignore_dnt: true, - debug: false, - }); - } + mixpanel.init(import.meta.env.VITE_MIXPANEL_TOKEN, { + ignore_dnt: true, + debug: false, + }); if (window.location.hostname === LOCALHOST_HOSTNAME) { mixpanel.disable(); + return; } else { // ... 나머지 로직 } }
♻️ Duplicate comments (2)
frontend/src/utils/initSDK.ts (2)
17-28: 세션 ID 검증 및 에러 처리를 추가하세요.주요 개선 사항:
세션 ID 검증 누락: URL 파라미터에서 추출한
session_id를 검증 없이identify()에 전달합니다. 빈 문자열(?session_id=)이나 예상 외 형식의 값이 Mixpanel로 전송될 수 있습니다.보안: 과거 리뷰에서 언급된 대로 쿼리스트링 노출 위험이 있습니다. 세션 ID 형식을 검증하여(예: UUID, 영숫자+하이픈) 잘못된 값 주입을 방지하세요.
에러 처리:
history.replaceState호출이 실패할 수 있는 엣지 케이스(예: 일부 구형 브라우저)에 대한 처리가 없습니다.🔎 제안하는 수정
} else { const urlParams = new URLSearchParams(window.location.search); const sessionId = urlParams.get('session_id'); - if (sessionId) { + + // UUID 또는 영숫자+하이픈+언더스코어 형식 검증 (8-64자) + const isValidSessionId = sessionId && + /^[a-zA-Z0-9_-]{8,64}$/.test(sessionId); + + if (isValidSessionId) { mixpanel.identify(sessionId); urlParams.delete('session_id'); const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : ''); - window.history.replaceState({}, document.title, newUrl); + + try { + window.history.replaceState({}, document.title, newUrl); + } catch (error) { + console.error('[Mixpanel] URL 업데이트 실패:', error); + } + } else if (sessionId) { + console.warn('[Mixpanel] 유효하지 않은 session_id 형식:', sessionId); } }Based on learnings, 일관된 로깅 형식을 사용하세요(예:
[ModuleName] 작업 설명).
5-5: 로컬호스트 감지가 불완전합니다.
127.0.0.1또는[::1](IPv6 localhost)로 접근하는 경우 Mixpanel이 비활성화되지 않습니다. 배열 또는 Set으로 확장하여 모든 로컬호스트 주소를 포함하세요.🔎 제안하는 수정
-const LOCALHOST_HOSTNAME = 'localhost'; +const LOCALHOST_HOSTNAMES = ['localhost', '127.0.0.1', '[::1]'];그리고 Line 15의 체크도 함께 수정:
- if (window.location.hostname === LOCALHOST_HOSTNAME) { + if (LOCALHOST_HOSTNAMES.includes(window.location.hostname)) {
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
frontend/src/utils/initSDK.ts
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx,js,jsx}: Replace magic numbers with named constants for clarity
Replace complex/nested ternaries withif/elseor IIFEs for readability
Assign complex boolean conditions to named variables for explicit meaning
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)
Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Define constants near related logic or ensure names link them clearly to avoid silent failures
Break down broad state management into smaller, focused hooks/contexts to reduce coupling
Files:
frontend/src/utils/initSDK.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/utils/initSDK.ts
🧠 Learnings (1)
📚 Learning: 2025-08-24T17:33:23.092Z
Learnt from: suhyun113
Repo: Moadong/moadong PR: 698
File: frontend/src/hooks/queries/applicants/useDeleteApplicants.ts:10-16
Timestamp: 2025-08-24T17:33:23.092Z
Learning: The codebase has inconsistent console logging patterns across files - mixing console.log/console.error for errors, using both Korean and English messages, and various formatting styles (template literals vs separate arguments, with/without emojis). A unified logging format like `console.error('[ModuleName] Operation failed:', error)` should be established for better debugging consistency.
Applied to files:
frontend/src/utils/initSDK.ts
#️⃣연관된 이슈
📝작업 내용
1. 프로덕션 Url 식별 코드 제거
vercel에서 프로덕션일 때의 믹스패널 key와 개발모드일 때의 믹스패널 key를 분리했기에 클라이언트에서 직접 분리하지 않아도 됩니다.
2. 로컬호스트 추적방지
로컬에서의 로깅은 방지했습니다.
3. 세션id 인식 코드 추가
모바일 앱에서 메인페이지 진입 시 추가되는 세션id를 가져오는 코드를 추가했습니다. 추후 앱 로그 통일을 위해 사용될 예정입니다.
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
개선사항
✏️ Tip: You can customize this high-level summary in your review settings.