Skip to content

Conversation

@cl-o-lc
Copy link
Collaborator

@cl-o-lc cl-o-lc commented Oct 20, 2025

📌 작업 내용

구글 애드샌스와 구글 애널리틱스를 적용합니다.

📝 기타

정원이가 환경변수 추가해주면 머지할 것!

Summary by CodeRabbit

릴리즈 노트

  • 새로운 기능

    • Google Analytics 분석 추적 기능이 추가되었습니다. 환경 변수 설정에 따라 자동으로 활성화되며, 사용자 행동 데이터를 수집하여 서비스 개선에 활용합니다.
  • Chores

    • 광고 플랫폼 설정 스크립트가 추가되었습니다.

@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)
checktime Ready Ready Preview Comment Oct 20, 2025 6:03am

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

@coderabbitai
Copy link

coderabbitai bot commented Oct 20, 2025

워크스루

Google Analytics 통합을 추가하기 위해 새로운 GoogleAnalytics 클라이언트 컴포넌트를 생성하고, 루트 레이아웃에 임포트하여 Adsense 스크립트 태그와 함께 주입했습니다. GA ID는 환경 변수에서 읽습니다.

변경사항

코호트 / 파일(들) 요약
Google Analytics 통합
src/components/GoogleAnalytics.tsx
새로운 클라이언트 컴포넌트 추가. NEXT_PUBLIC_GA_ID 환경 변수를 읽고, GA ID가 있을 때 GA 스크립트를 next/script(afterInteractive 전략)로 로드한 후 gtag 초기화 스크립트를 주입합니다. GA ID가 없으면 null을 반환합니다.
루트 레이아웃 업데이트
src/app/layout.tsx
GoogleAnalytics 컴포넌트를 임포트하고, head에 Adsense 스크립트 태그를 추가하며, body에서 ClientHeader 옆에 GoogleAnalytics 컴포넌트를 렌더링합니다.

시퀀스 다이어그램

sequenceDiagram
    participant App as Root Layout
    participant GA as GoogleAnalytics Component
    participant Script as next/script
    participant Browser as Browser/Window
    
    App->>GA: Render GoogleAnalytics
    GA->>GA: Read NEXT_PUBLIC_GA_ID
    alt GA ID Present
        GA->>Script: Load GA script (afterInteractive)
        Script->>Browser: Inject gtag library
        GA->>Script: Initialize gtag script (afterInteractive)
        Script->>Browser: Initialize dataLayer & configure GA
        Browser->>Browser: Start tracking page views
    else GA ID Not Set
        GA->>GA: Return null
    end
Loading

예상 코드 리뷰 노력

🎯 2 (단순) | ⏱️ ~12분

두 개의 파일로 제한된 변경 사항이며, 패턴이 일관되고 로직이 직관적입니다(환경 변수 읽기, 조건부 스크립트 로드, 컴포넌트 렌더링). 새로운 엔티티는 하나이고 기존 코드에 미치는 영향이 최소적입니다.

🐰 분석의 토끼가 왔네요,
추적 스크립트를 심으며 깡충!
GA는 클릭을 세고,
Adsense는 광고 하나,
사용자의 여정을 밝히는 마법이요! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description Check ❓ Inconclusive PR 설명은 템플릿의 기본 구조를 따르고 있으며, 필수 섹션인 "📌 작업 내용"과 "📝 기타" 섹션이 모두 포함되어 있습니다. 그러나 작업 내용 설명이 "구글 애드샌스와 구글 애널리틱스를 적용합니다"로만 매우 간단하고 포괄적이어서, 구체적인 구현 내용이나 변경 사항에 대한 상세한 설명이 부족합니다. 프론트엔드 컴포넌트 추가 작업임에도 불구하고 📸 스크린샷 섹션이 비워져 있으며, 환경 변수 대기 상황만 기재되어 있어 리뷰어가 변경 사항을 충분히 이해하기 어렵습니다. PR 설명을 보다 구체적으로 작성하여 clarity를 높일 것을 권장합니다. 구체적으로 어떤 파일이 추가/수정되었는지, GoogleAnalytics 및 Adsense 컴포넌트가 어떻게 구현되었는지, 그리고 필요한 환경 변수가 무엇인지 명시하는 것이 좋겠습니다. 또한 시각적 변화가 있다면 📸 스크린샷을 추가하여 리뷰어의 이해를 돕는 것을 권장합니다.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed PR 제목 "[chore] Google Adsense/Analytics 적용"은 변경 사항의 주요 내용을 정확하게 반영하고 있습니다. raw_summary에 따르면 GoogleAnalytics 컴포넌트 추가 및 AdSense 스크립트 주입이 주요 변경 사항인데, 제목이 이를 명확하고 간결하게 요약하고 있습니다. "[chore]" 태그는 변경 유형을 나타내는 관례적 표기이며, "적용"이라는 단어는 구현의 의도를 명확히 전달합니다.
✨ 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 chore/marketing

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.

@cl-o-lc cl-o-lc added the chore💭 환경 세팅 etc. label Oct 20, 2025
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)
src/components/GoogleAnalytics.tsx (1)

6-11: GA ID 형식 유효성 검증 추가를 권장합니다.

환경 변수가 설정되지 않은 경우를 처리하는 것은 좋지만, GA ID의 형식(G-XXXXXXXXXX 또는 UA-XXXXXXXXXX)을 검증하는 로직을 추가하면 더 안전합니다. 잘못된 형식의 ID가 설정된 경우 조기에 감지할 수 있습니다.

다음과 같이 형식 검증을 추가할 수 있습니다:

 const GoogleAnalytics = () => {
   const gaId = process.env.NEXT_PUBLIC_GA_ID;
 
-  // 환경 변수가 설정되지 않았다면 아무것도 렌더링하지 않습니다.
-  if (!gaId) {
+  // 환경 변수가 설정되지 않았거나 유효하지 않다면 아무것도 렌더링하지 않습니다.
+  if (!gaId || !/^(G-|UA-|AW-|DC-)[A-Z0-9]+$/i.test(gaId)) {
+    if (gaId && process.env.NODE_ENV === 'development') {
+      console.warn(`Invalid GA ID format: ${gaId}`);
+    }
     return null;
   }
📜 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 9334e87 and cee1340.

📒 Files selected for processing (2)
  • src/app/layout.tsx (2 hunks)
  • src/components/GoogleAnalytics.tsx (1 hunks)
🧰 Additional context used
🪛 ast-grep (0.39.6)
src/components/GoogleAnalytics.tsx

[warning] 23-23: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
src/components/GoogleAnalytics.tsx

[error] 28-29: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🔇 Additional comments (4)
src/components/GoogleAnalytics.tsx (2)

16-19: LGTM!

외부 GA 스크립트를 afterInteractive 전략으로 로드하는 것은 Next.js의 권장사항에 부합하며, 페이지 성능에 미치는 영향을 최소화합니다.


21-32: dangerouslySetInnerHTML 사용 시 보안 검토가 필요합니다.

현재 구현은 Google Analytics의 표준 패턴이지만, gaId가 환경 변수에서 직접 템플릿 리터럴에 삽입되고 있습니다. NEXT_PUBLIC_ 접두사를 가진 환경 변수는 클라이언트에 노출되므로, 만약 악의적인 값이 주입되면 XSS 공격의 위험이 있습니다.

위에서 제안한 형식 검증을 추가하면 이 위험을 크게 줄일 수 있습니다. 또한 GA ID는 빌드 타임에 설정되므로 런타임에 변경되지 않습니다.

환경 변수 설정 시 GA ID 형식이 올바른지 확인해 주세요. 정상적인 GA4 ID는 G-XXXXXXXXXX 형식이며, Universal Analytics ID는 UA-XXXXXXXXXX-X 형식입니다.

src/app/layout.tsx (2)

5-5: LGTM!

GoogleAnalytics 컴포넌트 import가 올바르게 추가되었습니다.


40-41: LGTM!

GoogleAnalytics 컴포넌트가 올바른 위치에 배치되었습니다. body 태그 내부에서 렌더링되는 것이 적절합니다.

Comment on lines +29 to +36
<head>
{/* 구글 애드센스 스크립트 */}
<script
async
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3712642250263014"
crossOrigin="anonymous"
></script>
</head>
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

AdSense 클라이언트 ID도 환경 변수로 관리해야 합니다.

현재 AdSense 클라이언트 ID가 하드코딩되어 있는데, GoogleAnalytics 컴포넌트와 동일하게 환경 변수로 관리하는 것이 일관성 있고 안전합니다. 또한 Next.js 13+ App Router에서는 next/script의 Script 컴포넌트를 사용하는 것이 권장됩니다.

다음과 같이 별도의 GoogleAdsense 컴포넌트를 생성하여 일관성을 유지할 수 있습니다:

src/components/GoogleAdsense.tsx 파일을 새로 생성:

'use client';

import Script from 'next/script';

const GoogleAdsense = () => {
  const adsenseId = process.env.NEXT_PUBLIC_ADSENSE_ID;

  if (!adsenseId) {
    return null;
  }

  return (
    <Script
      async
      src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${adsenseId}`}
      crossOrigin="anonymous"
      strategy="afterInteractive"
    />
  );
};

export default GoogleAdsense;

src/app/layout.tsx에 적용:

 import ClientHeader from '@/components/ClientHeader';
 import GoogleAnalytics from '@/components/GoogleAnalytics';
+import GoogleAdsense from '@/components/GoogleAdsense';

...

 return (
   <html lang="en">
-    <head>
-      {/* 구글 애드센스 스크립트 */}
-      <script
-        async
-        src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3712642250263014"
-        crossOrigin="anonymous"
-      ></script>
-    </head>
     <body
       className={`${geistSans.variable} ${geistMono.variable} antialiased bg-gray-50 text-gray-900`}
     >
+      {/* 구글 애드센스 컴포넌트 */}
+      <GoogleAdsense />
+
       {/* 구글 애널리틱스 컴포넌트 */}
       <GoogleAnalytics />

그런 다음 .env 파일에 다음을 추가:

NEXT_PUBLIC_ADSENSE_ID=ca-pub-3712642250263014
🤖 Prompt for AI Agents
In src/app/layout.tsx around lines 29 to 36, the AdSense client ID is hardcoded
and a plain script tag is used; create a new client component
src/components/GoogleAdsense.tsx that uses 'use client' and next/script's Script
component to load the ads script with strategy="afterInteractive", read the
client ID from process.env.NEXT_PUBLIC_ADSENSE_ID and return null if it's
missing, then remove the hardcoded <script> from layout.tsx and import/include
the new GoogleAdsense component there; also add
NEXT_PUBLIC_ADSENSE_ID=ca-pub-3712642250263014 to the .env file (or set the
appropriate env value).

@hannah0352
Copy link
Collaborator

추가했어용 수고했어유

@cl-o-lc cl-o-lc merged commit d2b9e6e into main Oct 20, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore💭 환경 세팅 etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants