[κ³ λν] μ½ν μΈ μΊλ¦°λ & 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 νμ©, μΈλ€μΌ μλ κ²μλ¬Ό μλ λμ
β¬οΈ μ΄ κΈμ΄ λμμ΄ λμ ¨λ€λ©΄, μλ κ΄κ³ λ₯Ό ν λ²λ§ ν΄λ¦ν΄μ£ΌμΈμ! μ μκ² ν° νμ΄ λ©λλ€ πββοΈ β¬οΈ