[κ³ λν] μ½ν μΈ μΊλ¦°λ & Google Analytics/Search Console μ΄λλ―Ό μ°λ
π λΈλ‘κ·Έ μ΄λλ―Ό νλ«νΌ κ³ λν μμ β μ½ν μΈ μΊλ¦°λ UI ꡬν + Google Analytics 4 & Search Console μ΄λλ―Ό λμ보λ μ°λ
κ°μ
λΈλ‘κ·Έ μ΄λλ―Ό νλ«νΌμ κ³ λν κ³ν(ENHANCEMENT_PLAN.md) Phase 2μ ν΄λΉνλ λ κ°μ§ κΈ°λ₯μ ꡬννλ€. μ½ν μΈ μΊλ¦°λλ‘ μλ³ λ°ν νν©μ μκ°ννκ³ , Google Analytics 4 λ° Search Console λ°μ΄ν°λ₯Ό μ΄λλ―Ό λ΄μμ λ°λ‘ νμΈν μ μλ λμ보λλ₯Ό λ§λ€μλ€.
β μ½ν μΈ μΊλ¦°λ (/admin/calendar)
κΈ°ν λ°°κ²½
μ€μΌμ€ μλ λ°νμ΄ νμ±νλλ©΄μ "μΈμ μ΄λ€ κΈμ΄ μΌλ§λ λκ°λμ§" νλμ νμ νκΈ° μ΄λ €μμ‘λ€. λ°ν μ΄λ ₯μ ν μ΄λΈλ‘λ§ λ³΄λ κΈ°μ‘΄ λ°©μμμ λ²μ΄λ, μλ³ μΊλ¦°λ λ·°λ‘ μκ°ννμ¬ λ°ν λ°λμ μΉ΄ν κ³ λ¦¬ λΆν¬λ₯Ό μ§κ΄μ μΌλ‘ νμΈν μ μλλ‘ νλ€.
ꡬν λ΄μ©
- 7ΓN 그리λ μΊλ¦°λ β μΌ/μ/ν/μ/λͺ©/κΈ/ν μμΌ ν€λ, μ€λ λ μ§ primary μμ κ°μ‘°, μΌ/ν λΉ¨κ°Β·νλ ꡬλΆ
- μΉ΄ν κ³ λ¦¬λ³ μ»¬λ¬ μ (dot) β κ° λ μ§μ λ°ν μλ§νΌ μΉ΄ν κ³ λ¦¬ μ»¬λ¬ μ νμ(μ΅λ 6κ° + λλ¨Έμ§ κ±΄μ)
- λ μ§ ν΄λ¦ β μ°μΈ‘ μμΈ ν¨λ β ν΄λΉ λ μ§μ ν¬μ€νΈ λͺ©λ‘(μ λͺ©, μΉ΄ν κ³ λ¦¬ λ±μ§, μΈμ΄, μμ λ§ν¬)
- μ΄μ /λ€μ λ¬ μ΄λ + μ€λ λ²νΌ β μ λ¨μ λ€λΉκ²μ΄μ
- μΉ΄ν κ³ λ¦¬ νν° β μ 체 / κ°λ° / μ¬ν λ± μ ν μ μΊλ¦°λ + ν΅κ³ λκΈ°ν
- μ΄λ² λ¬ μΉ΄ν κ³ λ¦¬λ³ λ° μ°¨νΈ β μ°μΈ‘ νλ¨ ν¨λμ λ°ν μ μκ°ν
μμ± νμΌ
app/admin/calendar/page.tsx # μΊλ¦°λ νμ΄μ§ (client component)
components/admin/AdminSidebar.tsx # μ½ν
μΈ μΊλ¦°λ λ©λ΄ μΆκ°
β‘ Google Analytics 4 & Search Console μ΄λλ―Ό μ°λ
κΈ°ν λ°°κ²½
λΈλ‘κ·Έλ₯Ό μ΄μνλ©΄μ νΈλν½ λ°μ΄ν°λ₯Ό νμΈνλ €λ©΄ GA μ½μ, Search Consoleμ λ³λλ‘ μ΄μ΄μΌ νλ€. μ΄λλ―Ό λμ보λ μμμ λ°λ‘ μ‘°νμ νΈλ λΒ·κ²μ ν€μλΒ·μμ νμ΄μ§λ₯Ό νμΈν μ μλλ‘ ν΅ν© μ λ리ν±μ€ νμ΄μ§λ₯Ό λ§λ€μλ€.
μν€ν μ²
googleapis ν¨ν€μ§λ₯Ό μ€μΉνμ§ μκ³ Node.js λ΄μ₯ crypto λͺ¨λλ§μΌλ‘ Google Service Account JWT μΈμ¦μ ꡬννλ€. μλΉμ€ κ³μ λΉλ°ν€λ‘ RS256 JWTλ₯Ό μλͺ β Google OAuth2 ν ν° μλν¬μΈνΈμμ μ‘μΈμ€ ν ν° κ΅ν β GA4 Data API / Search Console API νΈμΆ.
Service Account JSON Key β βΌ lib/google-auth.ts (RS256 JWT μλͺ + ν ν° λ°κΈ) β βββ /api/analytics/ga4 β GA4 Data API β μΌλ³ νΈλ λ / μμ νμ΄μ§ / μμ½ ν΅κ³ β βββ /api/analytics/gsc β Search Console API μμ 쿼리 / μμ νμ΄μ§ / ν΄λ¦Β·λ ΈμΆΒ·CTRΒ·μμ
ꡬν λ΄μ©
lib/google-auth.tsβ Node.js cryptoλ‘ RS256 JWT μμ±, OAuth2 μ‘μΈμ€ ν ν° λ°κΈ. normalizePem() ν¨μλ‘ νκ²½λ³μμ \n μ΄μ€μΌμ΄νλ₯Ό μ€μ κ°νμΌλ‘ λ³ν ν PEMμ 64μ λ¨μλ‘ μ¬ν¬λ§·νμ¬ OpenSSL νμ± μ€λ₯ λ°©μ§/api/analytics/ga4β μ΅κ·Ό 7μΌ/28μΌ μΌλ³ μΈμ Β·νμ΄μ§λ·°Β·νμ±μ¬μ©μ νΈλ λ, μμ νμ΄μ§ 10건. λ μ§ ν¬λ§·μ GA4 μꡬμ¬νμΈ YYYY-MM-DD νμ μ μ©/api/analytics/gscβ μ΅κ·Ό 7μΌ/28μΌ μμ κ²μ 쿼리 10건, μμ νμ΄μ§ 10건, ν΄λ¦Β·λ ΈμΆΒ·CTRΒ·νκ· μμ μ§κ³/admin/analyticsβ recharts LineChartλ‘ μΌλ³ νΈλ λ μκ°ν, μμ½ ν΅κ³ μΉ΄λ 6κ°, GA4/GSC μμ ν μ΄λΈ. νκ²½λ³μ λ―Έμ€μ μ λ Έλ μλ΄ λ°°λ, API μ€λ₯ μ λΉ¨κ° μλ¬ λ°°λ νμ- GTM + GA4 μ§μ μ°λ β app/layout.tsxμ NEXT_PUBLIC_GTM_ID κΈ°λ° GTM ν€λ μ€ν¬λ¦½νΈ + body noscript μ½μ , NEXT_PUBLIC_GA_MEASUREMENT_ID κΈ°λ° gtag μ§μ μ°λ(GTM λ―Έμ¬μ© fallback)
νΈλ¬λΈμν
error:1E08010C:DECODER routines::unsupportedβ μμΈ: .env.localμμ \nμ΄ μ€μ κ°νμΌλ‘ λ³νλμ§ μμ PEM ν¬λ§· νμ± μ€ν¨ β ν΄κ²°: normalizePem() ν¨μλ‘ \n μΉν ν base64 λ°λλ₯Ό 64μ λ¨μ μ¬ν¬λ§·GA4 400: Invalid startDateβ μμΈ: formatDate() ν¨μκ° YYYYMMDD νμμΌλ‘ λ μ§λ₯Ό μμ± β ν΄κ²°: YYYY-MM-DD νμμΌλ‘ μμ (νμ΄ν μΆκ°)GA4/GSC 403: Insufficient permissionsβ μμΈ: μλΉμ€ κ³μ μ΄λ©μΌμ΄ GA4 μμ±/Search Console μ¬μ΄νΈμ μΆκ°λμ§ μμ β ν΄κ²°: GA4 μμ± μ‘μΈμ€ κ΄λ¦¬μμ μλΉμ€ κ³μ μ λ·°μ΄λ‘ μΆκ°, GSC μ¬μ©μ κΆνμ μ νλ¨ μν λ‘ μΆκ°. Google Analytics Data API & Search Console API Cloud μ½μμμ νμ±ν
μμ±/μμ νμΌ
# μ κ· μμ±
lib/google-auth.ts # Google OAuth2 JWT μ νΈ
app/api/analytics/ga4/route.ts # GA4 Data API λΌμ°νΈ
app/api/analytics/gsc/route.ts # Search Console API λΌμ°νΈ
app/admin/analytics/page.tsx # μ΄λλ―Ό μ λ리ν±μ€ λμ보λ
app/.mcp.json # Notion MCP μλ² μ€μ
# μμ
app/layout.tsx # GTM + GA4 μ€ν¬λ¦½νΈ μΆκ°
components/admin/AdminSidebar.tsx # μ λ리ν±μ€ λ©λ΄ μΆκ°
.env.example # μ κ· νκ²½λ³μ 7κ° λ¬Έμν
νκ²½λ³μ μ€μ κ°μ΄λ
# Google Tag Manager (μ¦μ μ μ©)
NEXT_PUBLIC_GTM_ID=GTM-NBTS7P8W
# GA4 μ΄λλ―Ό λμ보λμ©
GA4_PROPERTY_ID= # GA4 μμ± μ«μ ID (analytics.google.com β κ΄λ¦¬ β μμ± μ€μ )
GOOGLE_SERVICE_ACCOUNT_EMAIL= # μλΉμ€ κ³μ μ΄λ©μΌ
GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY= # private_key κ° (\n κ·Έλλ‘)
# Search Console
GSC_SITE_URL=https://www.manbalboy.com
λ€μ μμ μμ
SEO λΆμ ν¨λ ꡬν (P0) β Preview νμ΄μ§μ ν€μλ λ°λΒ·λ©ν κΈΈμ΄ κ²μ¦ ν¨λ μΆκ°
μλ νκ·Έ/ν΄μνκ·Έ μ μ (P1) β AI 1ν νΈμΆλ‘ Preview νμ΄μ§μ νκ·Έ μ μ λ²νΌ μΆκ°
OG μ΄λ―Έμ§ μλ μμ± (P2) β Next.js ImageResponse νμ©, μΈλ€μΌ μλ κ²μλ¬Ό μλ λμ
β¬οΈ If this helped, please click the ad below! It supports me a lot πββοΈ β¬οΈ
Related Posts
Chanel vs. Louis Vuitton for Momβs 60th Birthday: A Luxury Handbag Gift Guide
Trying to choose between Chanel and Louis Vuitton for your momβs 60th birthday? This guide breaks down prestige, practicality, weight, and style so you can pick the luxury bag sheβll actually love using.
The Ultimate Guide to Choosing the Right Ferragamo Loafers for You
Discover the differences between Ferragamo's iconic Gancini and sleek Rollo loafers, and learn how to choose the perfect pair for your style and budget.
The Ultimate Guide to Buying Pre-Owned Van Cleef & Arpels Necklaces: Prices, Models, and Pro Tips
Thinking about buying a pre-owned Van Cleef & Arpels necklace? Discover current resale prices for popular Alhambra models, essential authentication tips, and what to look for regarding chain lengths and gemstone conditions.