Conversation
- 패치노트 배너 제거
- APP_STORE_LINKS 상수 추가 (iOS, Android, default) - getAppStoreLink 함수로 user-agent 기반 OS 판별 - iOS: itms-apps 스키마로 App Store 연결 - Android/기타: Google Play Store 연결
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
외부 URL 탐지 및 네비게이션 훅 frontend/src/hooks/useNavigator.ts |
위험한 프로토콜(javascript:, data:, vbscript:) 차단; 외부 링크 판별을 http/https/itms-apps 등으로 확장; 외부 링크는 내부 라우터 대신 window.location.href로 이동하도록 변경. |
훅 단위테스트 추가 frontend/src/hooks/__tests__/useNavigator.test.ts |
빈/공백 링크, 위험 스킴(대소문자 포함), 외부 링크(itms-apps 포함), 내부 절대/상대 경로 시나리오를 검증하는 테스트 추가. useNavigate 및 window.location 모킹/복원 포함. |
배너 클릭 처리 및 앱스토어 토큰 해석 frontend/src/pages/MainPage/components/Banner/Banner.tsx |
APP_STORE_LINKS 맵과 getAppStoreLink() 추가. handleBannerClick이 APP_STORE_LINK일 때 플랫폼별 스토어 URL을 해석해 트래킹(APP_DOWNLOAD_BANNER_CLICKED) 후 이동; 일반 링크는 BANNER_CLICKED 트래킹 후 이동. |
배너 데이터 업데이트(콘텐츠 전환) frontend/src/pages/MainPage/components/Banner/bannerData.ts |
PatchNote 배너 항목 제거, 앱 출시 배너(app-release-december-2025)로 교체(데스크톱/모바일 이미지 및 linkTo: APP_STORE_LINK). |
이벤트 상수 추가 frontend/src/constants/eventName.ts |
USER_EVENT에 BANNER_CLICKED 및 APP_DOWNLOAD_BANNER_CLICKED 키 추가. |
Sequence Diagram(s)
sequenceDiagram
participant User
participant Banner
participant useNavigator
participant Router as React-Router
participant Window as window.location
User->>Banner: 배너 클릭 (bannerId, bannerName, linkTo)
Banner->>useNavigator: handleBannerClick(linkTo, bannerId, bannerName)
alt linkTo == APP_STORE_LINK
useNavigator->>useNavigator: getAppStoreLink(userAgent)
useNavigator->>Window: window.location.href = appStoreUrl
useNavigator->>Banner: track(APP_DOWNLOAD_BANNER_CLICKED, ...)
else linkTo matches external (http/https/itms-apps)
useNavigator->>Window: window.location.href = url
useNavigator->>Banner: track(BANNER_CLICKED, ...)
else internal path
useNavigator->>Router: navigate(path)
useNavigator->>Banner: (no window.location change)
end
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 분
- 주의할 파일/영역:
useNavigator.ts의 스킴 차단 정규식(대소문자 및 인코딩 엣지케이스)getAppStoreLink()의 userAgent 기반 플랫폼 판별 정확성- Banner의 트래킹 호출 인자와 이벤트 이름(
USER_EVENT) 사용 일관성 - 테스트에서
window.location모킹/복원으로 인한 사이드 이펙트
Possibly related issues
- MOA-427: 패치노트 배너를 앱 출시 배너로 변경한다 — 패치노트 제거 및 앱 출시 배너 추가 구현과 직접 연관.
- [feature] MOA-427 패치노트 배너를 앱 출시 배너로 변경한다 #937 — MainPage 배너 교체(패치노트→앱 출시)와 기능적으로 일치.
Possibly related PRs
- [feature] 11월 패치노트 배너 추가 및 Banner 컴포넌트 구조 개선 #858 — Banner 컴포넌트 및 bannerData 관련 변경 이력과 직접적 코드 레벨 연관.
- [refactor] 믹스패널 이벤트 이름을 통일한다 #856 —
USER_EVENT상수 변경/확장과 이벤트 네이밍 정합성 관련 연관. - [feature] 메인 배너 클릭, 페이지네이션 추가 및 Swiper 마이그레이션 #788 —
useNavigator외부 링크 처리/네비게이션 흐름 관련 변경 이력과 연관.
Suggested reviewers
- oesnuj
- lepitaaar
- seongje973
Pre-merge checks and finishing touches
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | The PR title '[feature] 앱 출시 배너를 추가한다' clearly summarizes the main objective: adding an app release banner feature. |
| Linked Issues check | ✅ Passed | All coding requirements from MOA-427 are met: patch note banner removed, app release banner added with platform-specific store links, security enhancements to useNavigator implemented, and comprehensive tests added. |
| Out of Scope Changes check | ✅ Passed | All changes directly support the linked issue objectives: banner replacement, app store navigation, security improvements, and test coverage are all within scope. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
✨ Finishing touches
- 📝 Generate docstrings
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
feature/#937-add-app-banner-MOA-427
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: 3
📜 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 ignored due to path filters (2)
frontend/src/assets/images/banners/banner_desktop4.pngis excluded by!**/*.pngfrontend/src/assets/images/banners/banner_mobile4.pngis excluded by!**/*.png
📒 Files selected for processing (3)
frontend/src/hooks/useNavigator.ts(1 hunks)frontend/src/pages/MainPage/components/Banner/Banner.tsx(2 hunks)frontend/src/pages/MainPage/components/Banner/bannerData.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
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/pages/MainPage/components/Banner/Banner.tsxfrontend/src/pages/MainPage/components/Banner/bannerData.tsfrontend/src/hooks/useNavigator.ts
frontend/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{tsx,jsx}: Abstract complex logic/interactions into dedicated components/HOCs
Separate significantly different conditional UI/logic into distinct components
Colocate simple, localized logic or use inline definitions to reduce context switching
Choose field-level or form-level cohesion based on form requirements when using form libraries like react-hook-form
Use Component Composition instead of Props Drilling to reduce coupling
Files:
frontend/src/pages/MainPage/components/Banner/Banner.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/pages/MainPage/components/Banner/Banner.tsxfrontend/src/pages/MainPage/components/Banner/bannerData.tsfrontend/src/hooks/useNavigator.ts
🔇 Additional comments (2)
frontend/src/pages/MainPage/components/Banner/bannerData.ts (1)
5-6: LGTM!앱 출시 배너로의 전환이 올바르게 구현되었습니다. 이미지 임포트와 배너 데이터 구조가 기존 패턴을 잘 따르고 있으며,
APP_STORE_LINK토큰은 Banner 컴포넌트에서 플랫폼별 스토어 링크로 적절히 해석됩니다.Also applies to: 32-36
frontend/src/pages/MainPage/components/Banner/Banner.tsx (1)
48-57: LGTM!
handleBannerClick함수는 undefined URL에 대한 적절한 가드를 포함하고 있으며,APP_STORE_LINK토큰을 플랫폼별 스토어 링크로 올바르게 해석한 후 네비게이션을 수행합니다. 로직이 명확하고 안전합니다.
- javascript, data, vbscript 프로토콜 차단으로 XSS 방지 - 허용 프로토콜 화이트리스트 방식으로 변경
- 빈 URL 처리 테스트 - 악성 프로토콜 차단 테스트 (javascript, data, vbscript) - 외부 URL 이동 테스트 (https, http, itms-apps) - 내부 페이지 이동 테스트
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
frontend/src/hooks/useNavigator.ts (1)
12-13: 위험 프로토콜 목록에 추가 프로토콜을 포함하는 것을 권장합니다.현재
javascript:,data:,vbscript:프로토콜만 차단하고 있습니다.file:및blob:프로토콜도 보안 위험이 될 수 있으므로 차단 목록에 추가하는 것이 좋습니다.다음 diff를 적용하여 차단 목록을 확장하세요:
-const isDangerousProtocol = /^(javascript|data|vbscript):/i.test(trimmedUrl); +const isDangerousProtocol = /^(javascript|data|vbscript|file|blob):/i.test(trimmedUrl);
📜 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/__tests__/useNavigator.test.ts(1 hunks)frontend/src/hooks/useNavigator.ts(1 hunks)
🧰 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/useNavigator.tsfrontend/src/hooks/__tests__/useNavigator.test.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/hooks/useNavigator.tsfrontend/src/hooks/__tests__/useNavigator.test.ts
🧠 Learnings (1)
📚 Learning: 2025-07-20T11:48:50.207Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 541
File: frontend/src/pages/ClubDetailPage/components/ClubDetailHeader/ClubDetailHeader.tsx:41-43
Timestamp: 2025-07-20T11:48:50.207Z
Learning: moadong 프로젝트는 Next.js가 아닌 순수 React + react-router-dom 기반의 CSR(Client-Side Rendering) SPA이므로, window 객체 사용에 대한 SSR 호환성 문제를 제기하지 않아야 합니다.
Applied to files:
frontend/src/hooks/__tests__/useNavigator.test.ts
🔇 Additional comments (3)
frontend/src/hooks/useNavigator.ts (2)
15-15: LGTM! 이전 리뷰의 보안 우려사항이 해결되었습니다.외부 URL 탐지 로직이 올바르게 구현되었으며, 위험한 프로토콜 차단(12-13줄)이 추가되어 이전 리뷰에서 제기된 보안 문제가 해결되었습니다.
18-18: 외부 링크 탐색 방식 변경을 확인해주세요.외부 URL 탐색 방식이
window.open(trimmedUrl, '_blank', 'noopener,noreferrer')에서window.location.href = trimmedUrl로 변경되었습니다. 이는 외부 링크가 새 탭이 아닌 현재 탭에서 열리도록 변경하는 것으로, 사용자 경험에 큰 영향을 미칩니다.
- 이전: 외부 링크를 새 탭에서 열어 현재 페이지 유지
- 현재: 외부 링크로 현재 탭에서 이동하여 현재 페이지 이탈
앱 스토어 링크의 경우 의도적인 변경일 수 있으나, 다른 외부 링크의 경우 사용자가 새 탭에서 열리기를 기대할 수 있습니다. 이 변경이 의도된 것인지 확인해주세요.
필요한 경우 다음과 같이 URL 유형에 따라 다르게 처리할 수 있습니다:
if (isExternalUrl) { // 앱 스토어 링크는 현재 탭에서, 다른 외부 링크는 새 탭에서 if (/^itms-apps:/.test(trimmedUrl)) { window.location.href = trimmedUrl; } else { window.open(trimmedUrl, '_blank', 'noopener,noreferrer'); } } else { navigate(trimmedUrl); }frontend/src/hooks/__tests__/useNavigator.test.ts (1)
1-126: LGTM! 포괄적이고 잘 구성된 테스트 스uite입니다.테스트가 다음을 철저하게 검증합니다:
- 빈 링크 및 공백 처리
- 위험한 프로토콜 차단 (대소문자 변형 포함)
- 외부 URL 탐색 (https, http, itms-apps)
- 내부 경로 탐색 (절대/상대 경로)
테스트 구조가 명확하고, mock 관리가 적절하며, 구현과 완벽하게 일치합니다.
Based on learnings, moadong 프로젝트는 CSR SPA이므로
window객체 사용에 대한 SSR 호환성 문제가 없습니다.
- Given-When-Then 패턴 주석 추가 - renderHook을 beforeEach로 공통화하여 중복 제거
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
frontend/src/hooks/__tests__/useNavigator.test.ts (1)
54-90: 악성 링크 차단 테스트가 잘 구현되어 있습니다.
javascript:,data:,vbscript:스킴에 대한 차단과 대소문자 구분 없는 검증이 포함되어 있어 일반적인 XSS 공격 벡터를 효과적으로 커버하고 있습니다.선택적 개선 사항: 추가 보안 테스트 케이스를 고려해볼 수 있습니다:
- URL 인코딩된 스킴 (
javascript%3Aalert)- 공백이 포함된 스킴 우회 시도
- 다른 잠재적 위험 스킴 (
file:,blob:)현재 구현으로도 주요 공격 벡터는 충분히 방어됩니다.
📜 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/__tests__/useNavigator.test.ts(1 hunks)
🧰 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/__tests__/useNavigator.test.ts
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/hooks/__tests__/useNavigator.test.ts
🧠 Learnings (1)
📚 Learning: 2025-07-20T11:48:50.207Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 541
File: frontend/src/pages/ClubDetailPage/components/ClubDetailHeader/ClubDetailHeader.tsx:41-43
Timestamp: 2025-07-20T11:48:50.207Z
Learning: moadong 프로젝트는 Next.js가 아닌 순수 React + react-router-dom 기반의 CSR(Client-Side Rendering) SPA이므로, window 객체 사용에 대한 SSR 호환성 문제를 제기하지 않아야 합니다.
Applied to files:
frontend/src/hooks/__tests__/useNavigator.test.ts
🔇 Additional comments (4)
frontend/src/hooks/__tests__/useNavigator.test.ts (4)
1-32: 테스트 설정이 올바르게 구성되어 있습니다.Mock 설정,
window.location백업/복원, 그리고 각 테스트 간 초기화 로직이 적절하게 구현되었습니다.Object.defineProperty를 사용한window.location모킹은 Jest에서 표준적인 패턴입니다.
34-52: 빈 링크 처리 테스트가 올바릅니다.빈 문자열과 공백만 있는 경우 모두 내비게이션이 발생하지 않음을 검증하고 있습니다. 적절한 경계값 테스트입니다.
92-119: 외부 링크 처리 테스트가 정확합니다.
https,http,itms-apps프로토콜에 대해window.location.href를 통한 이동과useNavigate가 호출되지 않음을 모두 검증하고 있습니다. 앱 스토어 딥링크 지원이라는 PR 목표와도 일치합니다.
121-139: 내부 페이지 내비게이션 테스트가 올바릅니다.절대 경로와 상대 경로 모두
useNavigate를 통해 처리되고window.location.href가 변경되지 않음을 검증하여 SPA 내비게이션 동작이 올바르게 유지됨을 보장합니다.
- eventName에 BANNER_CLICKED, APP_DOWNLOAD_BANNER_CLICKED 이벤트 추가 - 배너 클릭 시 bannerId, bannerName, linkTo/platform 로깅 - user-agent 기반 iOS/Android 스토어 링크 분기 - 앱 다운로드 배너 데이터 추가
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
frontend/src/pages/MainPage/components/Banner/Banner.tsx (1)
21-31: iPadOS 감지 로직에 잠재적 문제가 있습니다.이전 리뷰에서 언급된 것처럼, 최신 iPadOS는 데스크탑 모드에서 macOS와 동일한 user-agent를 전송합니다.
macintosh매칭만으로는 Mac과 iPad를 구분할 수 없어 Mac 사용자가 iOS 앱스토어로 리다이렉트될 수 있습니다.
navigator.maxTouchPoints를 활용하여 개선할 수 있습니다:const getAppStoreLink = (): string => { const userAgent = navigator.userAgent.toLowerCase(); - if (/iphone|ipad|ipod|macintosh/.test(userAgent)) { + // iPad/iPhone/iPod 명시적 감지 + if (/iphone|ipad|ipod/.test(userAgent)) { + return APP_STORE_LINKS.ios; + } + // macOS Safari에서 iPadOS 감지 (maxTouchPoints > 1) + if (/macintosh/.test(userAgent) && navigator.maxTouchPoints > 1) { return APP_STORE_LINKS.ios; } if (/android/.test(userAgent)) { return APP_STORE_LINKS.android; } return APP_STORE_LINKS.default; };
🧹 Nitpick comments (2)
frontend/src/pages/MainPage/components/Banner/bannerData.ts (1)
17-23: 매직 스트링'APP_STORE_LINK'를 상수로 추출하는 것을 권장합니다.
linkTo: 'APP_STORE_LINK'가 Banner.tsx에서 특별히 처리되는 매직 스트링입니다. 명시적인 상수로 추출하면 유지보수성이 향상됩니다.+// 상수 파일 또는 이 파일 상단에 추가 +export const APP_STORE_LINK_TOKEN = 'APP_STORE_LINK'; // bannerData.ts에서 - linkTo: 'APP_STORE_LINK', + linkTo: APP_STORE_LINK_TOKEN,frontend/src/pages/MainPage/components/Banner/Banner.tsx (1)
51-59: 플랫폼 감지 로직이 중복되어 있습니다.라인 24와 56에서 동일한 iOS 감지 로직이 반복됩니다. 또한
getAppStoreLink()와 플랫폼 추적의 로직이 분리되어 있어 향후 불일치가 발생할 수 있습니다.플랫폼 감지를 통합하는 것을 권장합니다:
+const getPlatform = (): 'ios' | 'android' => { + const userAgent = navigator.userAgent.toLowerCase(); + if (/iphone|ipad|ipod/.test(userAgent)) return 'ios'; + if (/macintosh/.test(userAgent) && navigator.maxTouchPoints > 1) return 'ios'; + return 'android'; +}; + const getAppStoreLink = (): string => { - const userAgent = navigator.userAgent.toLowerCase(); - - if (/iphone|ipad|ipod|macintosh/.test(userAgent)) { - return APP_STORE_LINKS.ios; - } - if (/android/.test(userAgent)) { - return APP_STORE_LINKS.android; - } - return APP_STORE_LINKS.default; + return APP_STORE_LINKS[getPlatform()]; }; // handleBannerClick 내부 - platform: /iphone|ipad|ipod|macintosh/.test(navigator.userAgent.toLowerCase()) ? 'ios' : 'android', + platform: getPlatform(),
📜 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 (3)
frontend/src/constants/eventName.ts(1 hunks)frontend/src/pages/MainPage/components/Banner/Banner.tsx(3 hunks)frontend/src/pages/MainPage/components/Banner/bannerData.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
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/constants/eventName.tsfrontend/src/pages/MainPage/components/Banner/bannerData.tsfrontend/src/pages/MainPage/components/Banner/Banner.tsx
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
Use consistent return types for similar functions/hooks
Files:
frontend/src/constants/eventName.tsfrontend/src/pages/MainPage/components/Banner/bannerData.tsfrontend/src/pages/MainPage/components/Banner/Banner.tsx
frontend/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{tsx,jsx}: Abstract complex logic/interactions into dedicated components/HOCs
Separate significantly different conditional UI/logic into distinct components
Colocate simple, localized logic or use inline definitions to reduce context switching
Choose field-level or form-level cohesion based on form requirements when using form libraries like react-hook-form
Use Component Composition instead of Props Drilling to reduce coupling
Files:
frontend/src/pages/MainPage/components/Banner/Banner.tsx
🧬 Code graph analysis (1)
frontend/src/pages/MainPage/components/Banner/Banner.tsx (1)
frontend/src/constants/eventName.ts (1)
USER_EVENT(1-36)
🔇 Additional comments (2)
frontend/src/pages/MainPage/components/Banner/Banner.tsx (1)
89-101: 배너 클릭 핸들러 통합이 잘 되어 있습니다.
handleBannerClick에 배너 메타데이터(bannerId,bannerName,linkTo)를 전달하는 방식이 깔끔하고, 이벤트 추적과 내비게이션 로직이 적절히 분리되어 있습니다.frontend/src/constants/eventName.ts (1)
5-9: 새 배너 이벤트 상수가 적절하게 추가되었습니다.새 이벤트 상수들(
BANNER_CLICKED,APP_DOWNLOAD_BANNER_CLICKED)이 기존 네이밍 컨벤션을 잘 따르고 있습니다.참고: 라인 8-9의 불필요한 공백을 정리할 수 있습니다.
- 악성 링크 테스트 4개 → 1개 (parameterized) - 외부 링크 테스트 3개 → 1개 (parameterized)
#️⃣연관된 이슈
📝작업 내용
앱 릴리즈 배너 클릭 시 사용자의 OS에 따라 적절한 스토어로 이동하도록 구현했습니다.
1. 앱 릴리즈 배너 추가
2. OS별 스토어 분기 처리
user-agent기반으로 iOS/Android 판별하는 유틸함수 추가Banner.tsx내부에 두었습니다.3. useNavigator 보안 강화
javascript://, data://등 위험한 프로토콜 차단http://, https://, itms-apps://4. 테스트 추가
5. 로깅 추가
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
새로운 기능
개선사항
업데이트
테스트
✏️ Tip: You can customize this high-level summary in your review settings.