Skip to content

Comments

Feat: GA 세팅 및 연결#193

Merged
jllee000 merged 4 commits intodevelopfrom
feat/#192/GA4-task
Oct 20, 2025
Merged

Feat: GA 세팅 및 연결#193
jllee000 merged 4 commits intodevelopfrom
feat/#192/GA4-task

Conversation

@jllee000
Copy link
Collaborator

@jllee000 jllee000 commented Oct 20, 2025

📌 Related Issues

관련된 Issue를 태그해주세요. (e.g. - close #25)

📄 Tasks

  1. GA 세팅: 각 앱(client, landing, extension)의 index.html에 GA4 스니펫 추가
  2. packages/utils/gtag.ts 파일 추가하여 공용 이벤트 로깅 함수로 관리
  3. 리마인드 푸시 알람 기능 추가

⭐ PR Point (To Reviewer)

1. FCM 푸시 알림 클릭 트래킹 및 기능 추가

(1) 푸시 알림 클릭 시 GA4 이벤트 전송
(2) 특정 URL 이동 기능 추가: 푸시 알림 클릭 시 바로 dashboard 페이지로 랜딩

self.addEventListener('notificationclick', (event) => {
  const targetUrl = event.notification.data?.url || 'https://www.pinback.today';
  fetch(`https://www.google-analytics.com/mp/collect?~~ // GA4 Measurement Protocol로 직접 전송

2. GA 이벤트는 공용 이벤트 로깅 함수로 관리

공통 유틸 함수는 packages/utils 로 이동
gtag.ts (GA 이벤트 전송)
=> 앱 단의 index.html은 GA 초기화만 수행하고 utils 함수에서 직접 호출 가능

📷 Screenshot

Summary by CodeRabbit

  • New Features

    • 전반적인 사용자 행동 분석(GA) 유틸리티가 추가되어 페이지뷰 및 이벤트를 앱에서 전송할 수 있습니다.
  • Chores

    • 클라이언트, 확장 프로그램, 랜딩 페이지에 Google Analytics 태그가 삽입되었습니다.
    • 온보딩·대시보드 방문 기록이 수집됩니다.
    • 버튼 클릭(랜딩, 설치, 익스텐션 내 대시보드 이동 등)과 푸시 알림 클릭이 이벤트로 전송됩니다.

@vercel
Copy link

vercel bot commented Oct 20, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
pinback-client-client Canceled Canceled Oct 20, 2025 7:39am
pinback-client-landing Ready Ready Preview Comment Oct 20, 2025 7:39am

💡 Enable Vercel Agent with $100 free credit for automated AI reviews

@jllee000 jllee000 self-assigned this Oct 20, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 20, 2025

Walkthrough

프로젝트 전반에 Google Analytics(g tag) 계측을 추가했습니다. HTML에 gtag 스크립트 삽입, 디자인 시스템에 sendGAEvent/trackPageView 유틸 추가, 컴포넌트 마운트·클릭에 트래킹 호출 및 서비스워커의 notificationclick에서 GA 수집 호출을 추가했습니다.

Changes

Cohort / File(s) 요약
GA 초기화 스크립트
apps/client/index.html, apps/extension/popup.html, apps/landing/index.html
gtag.js 비동기 로드와 dataLayer/gtag() 초기화, ID G-847ZNSCC3J로 config 호출 추가 (순수 삽입)
디자인시스템 GA 유틸
packages/design-system/src/components/gtag/utils/gtag.ts, packages/design-system/src/components/index.ts
전역 Window 타입 확장 및 sendGAEvent() / trackPageView() 안전 호출 유틸 추가하고 공개 export에 포함
페이지 뷰 트래킹
apps/client/src/pages/onBoarding/OnBoarding.tsx, apps/client/src/pages/remind/Remind.tsx
컴포넌트 마운트 시 trackPageView(...) 호출 추가
클릭 이벤트 트래킹 (랜딩)
apps/landing/src/components/FinalCTASection.tsx, apps/landing/src/components/Header.tsx
설치/다운로드 버튼 클릭 핸들러에 sendGAEvent(...) 호출 추가 후 웹스토어 이동 처리로 변경
클릭 이벤트 트래킹 (익스텐션)
apps/extension/src/App.tsx
handleDuplicateRightClick 내부에 sendGAEvent(...) 호출 추가
서비스 워커 알림 클릭 처리
apps/client/public/firebase-messaging-sw.js
notificationclick 리스너 추가: 클릭 시 GA MP collect fetch 전송(에러 핸들링 포함) 후 클라이언트 포커스 또는 새 창 열기 및 알림 닫기
사소한 포맷팅
apps/landing/src/App.tsx
import 사이 불필요 빈 줄 제거 (비기능적 변경)
CI: Chromatic 정리 추가
.github/workflows/chromatic.yml
CHROMATIC_TEMP_DIR 환경변수 추가 및 storybook 캐시 정리 스텝 추가

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Page as 앱 페이지 / 익스텐션
    participant DS as 디자인시스템 유틸
    participant gtag as window.gtag
    participant GA as GoogleAnalytics

    User->>Page: 페이지 방문 / 버튼 클릭
    Page->>DS: trackPageView(...) / sendGAEvent(...)
    alt window.gtag 존재
        DS->>gtag: gtag('event', ...) / gtag('config', ...)
        gtag->>GA: 이벤트 전송
    else
        DS-->>Page: 안전하게 무시 (no-op)
    end
Loading
sequenceDiagram
    actor User
    participant SW as 서비스워커
    participant GA as GoogleCollectAPI
    participant Client as 브라우저 탭/윈도우

    User->>SW: 푸시 알림 클릭
    SW->>GA: fetch MP collect (client_id, reminder_push_click 등)
    Note over GA: 실패시 콘솔 경고 기록
    SW->>Client: 기존 클라이언트 포커스(일치하는 URL) 또는 새 창 열기
    SW->>SW: notification.close()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Fix(client): FCM 로직 수정 #187 — 동일 서비스워커 파일(apps/client/public/firebase-messaging-sw.js)을 수정하고 있어 충돌 가능성 및 행위 중복 여부 검토 필요.
  • fix: FCM 로직 수정  #180 — 서비스워커의 notificationclick 리스너 관련 변경 이력(추가/제거)으로 직접적 충돌 가능성.
  • Feat(landing): url 변경 #191 — 랜딩페이지의 설치 버튼 동작을 변경한 PR로, 이번 PR의 GA 호출과 상호작용 가능성 큼.

Suggested labels

🛠️ Feature, frontend

Suggested reviewers

  • constantly-dev
  • jjangminii

Poem

🐰 깡총깡총 데이터 밭에서

클릭 하나, 방문 하나 세며 뛰네,
당근 대신 이벤트를 모아,
통계 수레에 실어 보내는 나날—
기쁨의 점프, 기록의 소리! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning #192의 코딩 요구사항은 충족됩니다: GA 기초 세팅(각 앱의 index.html에 GA4 스니펫 추가), 사용자 방문 추적(OnBoarding.tsx, Remind.tsx의 trackPageView 호출), 버튼 클릭률 추적(extension, landing 컴포넌트의 sendGAEvent 호출, 푸시 알림 클릭 이벤트 추적). 그러나 #25(Progress bar 구현)는 이 PR에서 전혀 구현되지 않았으며, 랜딩 페이지와 익스텐션에서 GA 이벤트 추적만 추가되었습니다.
Out of Scope Changes Check ❓ Inconclusive 대부분의 변경사항은 #192의 GA 세팅 및 푸시 알림 기능과 직접 관련이 있습니다. 그러나 .github/workflows/chromatic.yml의 변경사항(Storybook 캐시 정리 단계 추가)은 GA 설정이나 푸시 알림 기능과 직접적인 연관이 없어 보입니다. 또한 apps/landing/src/App.tsx의 공백 라인 제거는 포맷팅 변경으로 범위에 포함되나 별도 주목이 필요합니다. .github/workflows/chromatic.yml 변경사항이 이 PR의 주요 목표(GA 설정 및 푸시 알림 기능)와 관련이 있는지 명확히 하기 위해 리뷰어에게 확인이 필요합니다. 해당 변경이 빌드 파이프라인 최적화와 무관하다면 별도 PR로 분리하거나 명확한 정당성을 제시하기를 권장합니다.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed 제목 "Feat: GA 세팅 및 연결"은 PR의 주요 변경사항을 명확하게 요약합니다. Google Analytics 설정 및 연결이라는 핵심 내용이 간결하게 표현되었으며, 각 앱(client, landing, extension)의 GA4 스니펫 추가, 공용 이벤트 로깅 함수 생성, 푸시 알림 트래킹 등의 주요 변경사항을 적절히 대표합니다.
Description Check ✅ Passed PR 설명이 저장소의 템플릿 구조를 적절히 따르고 있습니다. 필수 섹션인 "관련된 Issue" (#192 명시), "Tasks" (3개의 작업 항목 상세 기재), "PR Point (To Reviewer)" (FCM 푸시 알림 트래킹 및 GA 이벤트 관리에 대한 상세 설명)가 모두 포함되어 있습니다. 스크린샷은 선택 사항이며 생략되어 있습니다.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#192/GA4-task

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jllee000 jllee000 added the feat 기능 개발하라 개발 달려라 달려 label Oct 20, 2025
@github-actions
Copy link

github-actions bot commented Oct 20, 2025

✅ Storybook chromatic 배포 확인:
🐿️ storybook

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
apps/extension/src/App.tsx (1)

26-29: 이벤트 트래킹이 구현되었지만, 파라미터 명명 규칙을 재검토해주세요.

sendGAEvent의 파라미터가 (action, category, label) 순서인데, 현재 ('익스텐션', '익스텐션', '대시보드 가기 버튼 클릭')로 action과 category가 동일합니다.

GA 이벤트 구조 권장사항:

  • action: 구체적인 동작 (예: 'click', 'navigate')
  • category: 이벤트 그룹 (예: '익스텐션')
  • label: 상세 설명 (예: '대시보드 가기 버튼')

프로젝트의 GA 이벤트 명명 규칙이 정의되어 있는지 확인하고, 일관성을 위해 다른 이벤트들과 비교해주세요.

packages/design-system/src/components/gtag/utils/gtag.ts (1)

1-1: 모듈 증강을 위한 빈 export 설명 추가 권장

export {} 구문은 이 파일을 모듈로 만들어 전역 타입 증강을 가능하게 하기 위한 것이지만, 코드만 보면 의도가 불명확합니다.

다음과 같이 주석을 추가하면 가독성이 향상됩니다:

+// 전역 타입 증강을 위해 이 파일을 모듈로 만듦
 export {};
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cf97a29 and 72ae80c.

📒 Files selected for processing (12)
  • apps/client/index.html (1 hunks)
  • apps/client/public/firebase-messaging-sw.js (1 hunks)
  • apps/client/src/pages/onBoarding/OnBoarding.tsx (1 hunks)
  • apps/client/src/pages/remind/Remind.tsx (2 hunks)
  • apps/extension/popup.html (1 hunks)
  • apps/extension/src/App.tsx (2 hunks)
  • apps/landing/index.html (1 hunks)
  • apps/landing/src/App.tsx (0 hunks)
  • apps/landing/src/components/FinalCTASection.tsx (2 hunks)
  • apps/landing/src/components/Header.tsx (1 hunks)
  • packages/design-system/src/components/gtag/utils/gtag.ts (1 hunks)
  • packages/design-system/src/components/index.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/landing/src/App.tsx
🧰 Additional context used
🧬 Code graph analysis (6)
apps/client/src/pages/remind/Remind.tsx (2)
packages/design-system/src/components/gtag/utils/gtag.ts (1)
  • trackPageView (29-35)
packages/design-system/src/components/index.ts (1)
  • trackPageView (20-20)
packages/design-system/src/components/gtag/utils/gtag.ts (1)
packages/design-system/src/components/index.ts (2)
  • sendGAEvent (20-20)
  • trackPageView (20-20)
apps/landing/src/components/Header.tsx (2)
packages/design-system/src/components/gtag/utils/gtag.ts (1)
  • sendGAEvent (15-27)
packages/design-system/src/components/index.ts (1)
  • sendGAEvent (20-20)
apps/client/src/pages/onBoarding/OnBoarding.tsx (2)
packages/design-system/src/components/gtag/utils/gtag.ts (1)
  • trackPageView (29-35)
packages/design-system/src/components/index.ts (1)
  • trackPageView (20-20)
apps/landing/src/components/FinalCTASection.tsx (2)
packages/design-system/src/components/gtag/utils/gtag.ts (1)
  • sendGAEvent (15-27)
packages/design-system/src/components/index.ts (1)
  • sendGAEvent (20-20)
apps/extension/src/App.tsx (2)
packages/design-system/src/components/gtag/utils/gtag.ts (1)
  • sendGAEvent (15-27)
packages/design-system/src/components/index.ts (1)
  • sendGAEvent (20-20)
🔇 Additional comments (13)
apps/extension/popup.html (1)

7-20: GA 스크립트 통합이 올바르게 구현되었습니다.

표준 gtag.js 구현 방식을 따르고 있으며, 비동기 로딩과 dataLayer 초기화가 적절합니다.

apps/client/index.html (1)

30-43: GA 스크립트 통합이 올바르게 구현되었습니다.

다른 앱들과 일관된 방식으로 GA4가 통합되었습니다.

apps/landing/index.html (1)

30-43: GA 스크립트 통합이 올바르게 구현되었습니다.

모든 앱에서 일관된 GA 초기화 방식을 사용하고 있습니다.

apps/client/public/firebase-messaging-sw.js (1)

73-94: 알림 클릭 시 윈도우 처리 로직이 적절합니다.

기존 윈도우를 재사용하고, 없으면 새 윈도우를 여는 로직이 올바르게 구현되었습니다.

apps/extension/src/App.tsx (1)

7-7: GA 유틸리티 import가 올바릅니다.

design-system에서 제공하는 sendGAEvent를 적절히 import하고 있습니다.

apps/client/src/pages/remind/Remind.tsx (2)

1-6: 필요한 import가 올바르게 추가되었습니다.

useEffecttrackPageView가 적절히 import되었습니다.


28-30: 페이지 뷰 트래킹이 올바르게 구현되었습니다.

컴포넌트 마운트 시 한 번만 실행되도록 빈 의존성 배열을 사용하여 페이지 방문을 추적하고 있습니다.

apps/landing/src/components/Header.tsx (2)

2-2: GA 유틸리티 import가 올바릅니다.

design-system에서 sendGAEvent를 적절히 import하고 있습니다.


5-14: 클릭 이벤트 트래킹이 올바르게 구현되었습니다.

GA 이벤트 전송 후 페이지 이동이 순차적으로 처리되어 이벤트 손실 위험이 줄어듭니다. 핸들러 함수로 분리하여 가독성도 좋습니다.

apps/client/src/pages/onBoarding/OnBoarding.tsx (2)

4-5: 필요한 import가 올바르게 추가되었습니다.

useEffecttrackPageView가 적절히 import되었습니다.


7-9: 페이지 뷰 트래킹이 올바르게 구현되었습니다.

다른 페이지들(Remind.tsx)과 일관된 방식으로 페이지 방문을 추적하고 있습니다.

packages/design-system/src/components/index.ts (1)

19-20: GA 유틸리티 export 추가 확인

새로운 GA 이벤트 추적 유틸리티가 design-system에서 제공되도록 export가 추가되었습니다. 공통 패키지에서 제공하는 것이 적절합니다.

packages/design-system/src/components/gtag/utils/gtag.ts (1)

3-7: Window 인터페이스 확장 확인

gtag 함수를 안전하게 사용하기 위한 타입 선언이 적절하게 추가되었습니다.

Comment on lines +54 to +71
fetch(
`https://www.google-analytics.com/mp/collect?measurement_id=G-847ZNSCC3J&api_secret=1hei57fPTKyGX5Cw73rwgA`,
{
method: 'POST',
body: JSON.stringify({
client_id: 'serviceworker',
events: [
{
name: 'reminder_push_click',
params: {
category: '리마인드 알림',
label: '리마인드 푸시 알림 클릭 (대시보드 이동)',
},
},
],
}),
}
).catch((err) => console.warn('GA 이벤트 전송 실패', err));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

CRITICAL: API 시크릿이 클라이언트 코드에 노출되어 있습니다.

Line 55에서 GA Measurement Protocol API 시크릿(1hei57fPTKyGX5Cw73rwgA)이 서비스 워커 코드에 하드코딩되어 있습니다. 이는 심각한 보안 취약점입니다:

  • 모든 사용자가 소스 코드를 통해 API 시크릿을 추출할 수 있습니다
  • 악의적인 사용자가 이 시크릿을 악용하여 잘못된 데이터를 전송할 수 있습니다
  • Google Analytics 모범 사례를 위반합니다

권장 해결 방안:

  1. 서버 사이드 프록시 사용 (권장): 백엔드 API를 통해 GA 이벤트를 전송하여 API 시크릿을 서버에만 보관
  2. gtag.js 사용: 서비스 워커가 아닌 환경에서는 이미 사용 중인 gtag.js를 활용 (API 시크릿 불필요)
  3. API 시크릿 재발급: 현재 노출된 시크릿은 즉시 재발급 필요

추가 이슈:

  • Line 59: client_id: 'serviceworker'가 모든 사용자에게 동일하게 사용되어 개별 사용자 추적이 불가능합니다. 고유한 client_id 생성을 고려해주세요.

현재 노출된 API 시크릿이 프로덕션에서 사용 중인지 확인해주세요:


🌐 Web query:

Google Analytics Measurement Protocol API secret security best practices

💡 Result:

Key best practices for protecting GA4 Measurement Protocol API secrets

  • Never put the api_secret in client-side code (browser, mobile app) — keep Measurement Protocol requests server-side. [1][2]
  • Store secrets in a secure secret manager / environment variables (HashiCorp Vault, GCP Secret Manager, AWS Secrets Manager) and avoid checking them into source control or logs. [2]
  • Limit who and what can read the secret: apply least-privilege IAM to the service account or runtime that needs it. Use short-lived credentials where possible. [2]
  • Rotate secrets regularly and after any suspected exposure; revoke compromised MeasurementProtocolSecret via the Admin API. [3][8]
  • Use a separate secret per data stream / integration (don’t reuse one secret across unrelated streams). Give descriptive display names so you can audit and revoke individually. [3][5]
  • Keep sensitive user fields hashed client-side as required (SHA‑256 + hex) before sending via Measurement Protocol; never send raw PII in plain text. [9]
  • Prevent accidental leakage: do not log the api_secret or full request URLs containing it; redact or omit secrets in telemetry/monitoring. [4][9]
  • Throttle, validate and authenticate incoming server-side traffic: validate payload structure, apply rate limiting, and require your own upstream authentication (service token/API key) before forwarding events to Google. This reduces abuse if your server endpoint is called by outsiders. [1][6]
  • Monitor usage and anomalies (unexpected volume, unknown sources, unusual event types) and alert on suspicious activity so you can rotate/revoke quickly. [4]
  • Prefer server-side tagging (Measurement Protocol) as an augmentation to client tagging — follow Google’s guidance that Measurement Protocol is intended to augment automatic collection, not replace it. [6]

Primary sources
[1] Measurement Protocol reference (GA4) — required api_secret guidance.
[2] Measurement Protocol sending events & admin secrets docs — secret creation/storage notes.
[3] Admin API: properties.dataStreams.measurementProtocolSecrets (create/get/list/patch/delete).
[4] GA4 docs recommending keeping API secrets private and rotating if client-side deployed.
[9] Send user-provided data: require SHA‑256 hashing for sensitive user fields.

(Links: Google Developers Measurement Protocol & Admin API pages cited above.)



GA 계측 프로토콜 API 시크릿이 클라이언트 코드에 노출되어 있습니다. 긴급 조치가 필요합니다.

apps/client/public/firebase-messaging-sw.js 파일의 55번 줄에서 GA Measurement Protocol API 시크릿(1hei57fPTKyGX5Cw73rwgA)이 하드코딩되어 있습니다. API 시크릿은 절대 클라이언트 사이드 코드(브라우저, 모바일 앱)에 포함되어서는 안 되며, Measurement Protocol 요청은 서버 사이드에서만 수행되어야 합니다.

즉시 조치 사항:

  1. API 시크릿을 보안 시크릿 관리자 또는 환경 변수에 저장하고(HashiCorp Vault, GCP Secret Manager, AWS Secrets Manager), 소스 코드나 로그에 커밋하지 않아야 합니다.
  2. 서버 사이드에 Measurement Protocol 요청을 이동하여 백엔드를 통해 GA 이벤트를 전송합니다.
  3. 노출된 시크릿을 즉시 회전하거나 폐지해야 합니다.

추가 이슈:

  • Line 59에서 client_id: 'serviceworker'가 모든 사용자에게 동일하므로, 고유한 클라이언트 ID 생성을 고려하세요.
🤖 Prompt for AI Agents
In apps/client/public/firebase-messaging-sw.js around lines 54 to 71, the GA
Measurement Protocol API secret is hardcoded and used in client-side code;
remove the secret from this file, stop sending Measurement Protocol requests
directly from the service worker, and instead call a backend endpoint that you
will implement to forward GA events using the secret stored securely (e.g.,
environment variable or secrets manager). Update the service worker to POST
event payloads to your server API (no secret in client), rotate/revoke the
exposed secret immediately, and change the client_id generation to use a
per-user or per-install unique identifier rather than the static
'serviceworker'.

Comment on lines +5 to +9
const handleInstallClick = () => {
sendGAEvent('랜딩페이지', '랜딩페이지', '하단 설치 버튼 클릭');
window.location.href =
'https://chromewebstore.google.com/detail/pinback-extension/engpidnjjbemfjmpcplchpfhokkgnbec?hl=ko&utm_source=ext_sidebar';
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

GA 이벤트 파라미터 명명 규칙 검토 필요

현재 sendGAEvent의 첫 번째 파라미터(action)에 '랜딩페이지'를 전달하고 있는데, 이는 GA4 이벤트 명명 규칙과 맞지 않습니다.

일반적인 GA 이벤트 구조:

  • action: 실제 행동을 나타내는 동사 (예: 'click', 'install', 'button_click')
  • category: 이벤트가 발생한 영역/페이지 (예: '랜딩페이지', 'header')
  • label: 구체적인 대상 (예: '하단 설치 버튼')

다음과 같이 수정하는 것을 권장합니다:

  const handleInstallClick = () => {
-    sendGAEvent('랜딩페이지', '랜딩페이지', '하단 설치 버튼 클릭');
+    sendGAEvent('설치_버튼_클릭', '랜딩페이지', '하단_CTA_섹션');
    window.location.href =
      'https://chromewebstore.google.com/detail/pinback-extension/engpidnjjbemfjmpcplchpfhokkgnbec?hl=ko&utm_source=ext_sidebar';
  };

혹은 더 명확하게:

  const handleInstallClick = () => {
-    sendGAEvent('랜딩페이지', '랜딩페이지', '하단 설치 버튼 클릭');
+    sendGAEvent('install_click', 'landing_page', 'final_cta_button');
    window.location.href =
      'https://chromewebstore.google.com/detail/pinback-extension/engpidnjjbemfjmpcplchpfhokkgnbec?hl=ko&utm_source=ext_sidebar';
  };

참고: Header.tsx 등 다른 컴포넌트에서도 동일한 패턴을 사용하고 있다면 일관되게 수정이 필요합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleInstallClick = () => {
sendGAEvent('랜딩페이지', '랜딩페이지', '하단 설치 버튼 클릭');
window.location.href =
'https://chromewebstore.google.com/detail/pinback-extension/engpidnjjbemfjmpcplchpfhokkgnbec?hl=ko&utm_source=ext_sidebar';
};
const handleInstallClick = () => {
sendGAEvent('설치_버튼_클릭', '랜딩페이지', '하단_CTA_섹션');
window.location.href =
'https://chromewebstore.google.com/detail/pinback-extension/engpidnjjbemfjmpcplchpfhokkgnbec?hl=ko&utm_source=ext_sidebar';
};
Suggested change
const handleInstallClick = () => {
sendGAEvent('랜딩페이지', '랜딩페이지', '하단 설치 버튼 클릭');
window.location.href =
'https://chromewebstore.google.com/detail/pinback-extension/engpidnjjbemfjmpcplchpfhokkgnbec?hl=ko&utm_source=ext_sidebar';
};
const handleInstallClick = () => {
sendGAEvent('install_click', 'landing_page', 'final_cta_button');
window.location.href =
'https://chromewebstore.google.com/detail/pinback-extension/engpidnjjbemfjmpcplchpfhokkgnbec?hl=ko&utm_source=ext_sidebar';
};
🤖 Prompt for AI Agents
In apps/landing/src/components/FinalCTASection.tsx around lines 5-9, the
sendGAEvent call uses '랜딩페이지' as the action which violates the GA4 naming
convention; change the arguments so the first parameter is a verb describing the
action (e.g., 'click' or 'install'), the second parameter is the category/page
('랜딩페이지'), and the third is the label ('하단 설치 버튼' or '하단 설치 버튼 클릭'); update the
call accordingly and also search for and update other components (e.g.,
Header.tsx) to use the same action/category/label pattern for consistency.

Comment on lines +15 to +27
export const sendGAEvent = (
action: string,
category?: string,
label?: string,
value?: number
) => {
if (typeof window === 'undefined' || !window.gtag) return;
window.gtag('event', action, {
event_category: category,
event_label: label,
value,
});
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

sendGAEvent 파라미터 명명 규칙 확인 필요

함수 시그니처에서 첫 번째 파라미터 action을 "이벤트 이름"이라고 문서화했지만, 실제 사용처(예: FinalCTASection.tsx)에서는 '랜딩페이지'와 같은 카테고리성 값을 전달하고 있습니다.

Google Analytics 표준 명명 규칙에서는:

  • event_name (action): 'click', 'view', 'purchase' 등의 동작
  • event_category: 이벤트가 속한 카테고리
  • event_label: 구체적인 식별자

현재 구현은 기술적으로 동작하지만, 팀 전체가 일관된 명명 규칙을 따르도록 가이드라인을 수립하고 문서화하는 것이 좋습니다.

코드베이스 전체에서 sendGAEvent 사용 패턴을 확인하고, 필요시 명명 가이드를 수립하세요:


🏁 Script executed:

#!/bin/bash
# Description: sendGAEvent 사용 패턴 조사

# sendGAEvent 호출 위치와 파라미터 패턴 확인
rg -n -A 2 'sendGAEvent\(' --type=ts --type=tsx -g '!node_modules'

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for sendGAEvent usage with glob patterns instead of type flags
rg -n -A 2 'sendGAEvent\(' -g '*.ts' -g '*.tsx' 2>/dev/null || rg -n -A 2 'sendGAEvent\(' 

Length of output: 900


🏁 Script executed:

#!/bin/bash
# Also specifically check FinalCTASection mentioned in review
fd -e ts -e tsx -name '*FinalCTA*' -x cat {}

Length of output: 230


🏁 Script executed:

#!/bin/bash
# Search for import or definition of sendGAEvent to understand usage better
rg -n 'import.*sendGAEvent|export.*sendGAEvent' 

Length of output: 509


sendGAEvent 파라미터와 실제 사용 패턴의 명명 불일치 확인 필요

코드베이스 전체의 sendGAEvent 호출을 조사한 결과, 리뷰 우려가 정확합니다. 모든 사용처에서 첫 번째 action 파라미터에 카테고리 값을 전달하고 있습니다:

  • apps/extension/src/App.tsx: sendGAEvent('익스텐션', '익스텐션', '대시보드 가기 버튼 클릭')
  • apps/landing/src/components/Header.tsx: sendGAEvent('랜딩페이지', '랜딩페이지', '헤더 설치 버튼 클릭')
  • apps/landing/src/components/FinalCTASection.tsx: sendGAEvent('랜딩페이지', '랜딩페이지', '하단 설치 버튼 클릭')

Google Analytics 표준 명명 규칙과 불일치:

  • event_name (action): 'click', 'view', 'purchase' 등의 동작이어야 하나, 현재는 '익스텐션', '랜딩페이지' 같은 카테고리 값 수신 중
  • event_category: 올바르게 사용 중
  • event_label: 올바르게 사용 중

파라미터 이름을 표준에 맞게 재정의하거나, 함수 구현과 사용처를 일관되게 수정하는 것을 권장합니다.

🤖 Prompt for AI Agents
In packages/design-system/src/components/gtag/utils/gtag.ts around lines 15 to
27 the parameter names are misaligned with how callers pass values (callers pass
category as the first arg); rename the function parameters so the first param is
category and the second is action (e.g., (category: string, action?: string,
label?: string, value?: number)) and update the gtag invocation to use the new
variables (call window.gtag('event', action, { event_category: category,
event_label: label, value })) and adjust the TypeScript types accordingly so
existing call sites keep working without changes.

Comment on lines +29 to +35
export const trackPageView = (title?: string) => {
if (!window.gtag) return;
window.gtag('event', '화면 접근', {
page_title: title ?? document.title,
page_path: window.location.pathname,
});
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

SSR 환경에서 에러 발생 가능

trackPageView 함수에서 typeof window 체크가 누락되어 있습니다. Line 21의 sendGAEvent와 달리, Line 30에서는 window.gtag만 확인하고 있어 SSR 환경(window가 undefined)에서 런타임 에러가 발생할 수 있습니다.

다음과 같이 수정하세요:

 export const trackPageView = (title?: string) => {
-  if (!window.gtag) return;
+  if (typeof window === 'undefined' || !window.gtag) return;
   window.gtag('event', '화면 접근', {
     page_title: title ?? document.title,
     page_path: window.location.pathname,
   });
 };
🤖 Prompt for AI Agents
In packages/design-system/src/components/gtag/utils/gtag.ts around lines 29 to
35, trackPageView accesses window.gtag without ensuring window exists which
causes errors in SSR; update the function to first check typeof window !==
'undefined' (and then window.gtag) before using it, and use the safe
document/window access (or optional chaining) when reading document.title and
window.location.pathname so the function returns early in SSR environments.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/chromatic.yml (1)

57-58: 캐시 정리 단계의 조건 및 목적을 명확히 해야 합니다.

캐시 정리 단계가 Chromatic 게시 성공 여부와 관계없이 항상 실행됩니다. 다음을 확인하세요:

  1. 이 정리 단계가 실패해도 괜찮은지 (현재 if: 조건이 없음)
  2. Chromatic 게시 실패 시에도 캐시를 정리할지 여부
  3. 캐시 정리의 목적과 대안 (예: 워크플로우 수준에서 정리 여부)

현재 단계에 명시적 조건을 추가하면 의도가 명확해질 것 같습니다.

고려사항: Chromatic 성공 시에만 정리하려면 아래처럼 조건 추가를 권장합니다:

-      - name: Clean storybook cache
-        run: rm -rf packages/design-system/node_modules/.cache/storybook
+      - name: Clean storybook cache
+        if: success()
+        run: rm -rf packages/design-system/node_modules/.cache/storybook
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72ae80c and d5ffe7f.

📒 Files selected for processing (1)
  • .github/workflows/chromatic.yml (1 hunks)

Comment on lines +55 to +56
env:
CHROMATIC_TEMP_DIR: './.chromatic-tmp'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

CHROMATIC_TEMP_DIR 환경 변수가 Chromatic 작업에서 지원되는지 확인이 필요합니다.

Chromatic GitHub Action에서 CHROMATIC_TEMP_DIR 환경 변수를 공식적으로 지원하는지 검증이 필요합니다. 지원되지 않는 경우 이 설정이 작동하지 않을 수 있습니다.


🌐 Web query:

Does Chromatic GitHub Action support CHROMATIC_TEMP_DIR environment variable?

💡 Result:

Short answer: No — Chromatic's docs and configuration reference do not list a CHROMATIC_TEMP_DIR environment variable (they document the supported CHROMATIC_* env vars instead). See the environment-variable list in the Configuration Reference and the GitHub Actions docs. [1][2]

Sources:
[1] Chromatic configuration reference — "Environment variables" list.
[2] Chromatic GitHub Actions docs — "Support for environment variables" guidance.


CHROMATIC_TEMP_DIR 환경 변수는 Chromatic GitHub Action에서 지원되지 않습니다.

검증 결과, Chromatic의 공식 문서와 Configuration Reference에서 CHROMATIC_TEMP_DIR은 지원되는 환경 변수 목록에 포함되어 있지 않습니다. 따라서 55-56줄의 이 설정은 작동하지 않으며 제거되거나 Chromatic에서 실제로 지원하는 설정 방법으로 대체되어야 합니다.

🤖 Prompt for AI Agents
.github/workflows/chromatic.yml around lines 55-56: the env variable
CHROMATIC_TEMP_DIR is not a supported Chromatic setting and should be removed or
replaced with a supported configuration; delete the CHROMATIC_TEMP_DIR env entry
from the workflow (or convert it to a supported Chromatic CLI argument or
documented env var per Chromatic docs) so the workflow only uses officially
supported options.

@jllee000 jllee000 merged commit 00bb01b into develop Oct 20, 2025
8 of 9 checks passed
@vercel vercel bot temporarily deployed to Preview – pinback-client-client October 20, 2025 07:39 Inactive
jllee000 added a commit that referenced this pull request Oct 20, 2025
jllee000 added a commit that referenced this pull request Oct 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 기능 개발하라 개발 달려라 달려

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] GA 세팅 및 심기

1 participant