Skip to content

feat:add a/b test and author API#49

Merged
Rikublender3d merged 1 commit intomainfrom
feat/optimization
Mar 1, 2026
Merged

feat:add a/b test and author API#49
Rikublender3d merged 1 commit intomainfrom
feat/optimization

Conversation

@Rikublender3d
Copy link
Copy Markdown
Owner

@Rikublender3d Rikublender3d commented Mar 1, 2026

変更内容

変更の種類

  • 🐛 Bug fix (バグ修正)
  • ✨ New feature (新機能)
  • 💄 UI/Style update (見た目の変更)
  • ⚡ Performance improvement (パフォーマンス改善)
  • 📝 Documentation (ドキュメント)
  • 🔧 Maintenance (メンテナンス)

テスト

  • 新しいテストを追加した
  • 既存のテストがすべて通る
  • 手動テストを実施した

チェックリスト

  • ESLint エラーがない
  • TypeScript エラーがない
  • ビルドが通る
  • レスポンシブ対応している
  • アクセシビリティを考慮している

スクリーンショット(UI変更がある場合)

関連Issue

Closes #

追加情報

人気記事ロジック(GA4自動取得)(カテゴリ:新機能)

「人気記事」を最新順の仮実装からGA4のPVデータに基づく自動取得に切り替え。
src/lib/analytics/ga4.ts を新規作成(GA4 Data API連携)
getPopularArticles を GA4 から記事IDを取得する方式に変更
トップページ・サイドバーで人気記事を表示、取得失敗時は最新記事にフォールバック

medical-articles/[id] の動的メタデータ追加 (カテゴリ:バグ修正)

general/[id] にはあった generateMetadata(タイトル・OGP・Twitterカード)が medical-articles/[id] にはなかったため、同じロジックを適用。

著者情報のリファクタリング (カテゴリ:パフォーマンス改善)

microCMSで著者情報がコンポーネントベースのカスタムフィールドに変更されたことに対応。
AuthorInfo を API取得型 → props受け取り型に変更
著者未設定時のデフォルト「編集部」フォールバック実装
Author 型の bio / sns をオプショナルに変更

シェアボタンのブランドカラー準拠+共通化(カテゴリ:UI/UX改善,パフォーマンス改善)

3ページ(general/[id]、medical-articles/[id]、draft/[id])で重複していたシェアボタンを ShareButtons コンポーネントに切り出し、ブランドカラーに修正。

A/Bテスト機能の追加 (カテゴリ:新機能、)

5:5で割り当てる(セッション保持は行わない,GA4にてカスタム定義を行い記録を行う)


Note

Medium Risk
Adds server-side GA4 Data API integration (service-account credentials, caching) that now influences homepage/sidebar ranking and introduces new client-side A/B tracking; misconfiguration could affect rendering and analytics behavior but has fallbacks.

Overview
Replaces the placeholder “popular articles” logic with a GA4 Data API-backed ranking. A new GA4 client (src/lib/analytics/ga4.ts) fetches pageview-sorted article IDs (with TTL caching) and microcms.getPopularArticles()/getSidebarData() now use this, falling back to newest content when GA4 isn’t configured.

Introduces a hero A/B test on the homepage. ABHero randomly selects between the existing hero and a new carousel-based variant (HeroCarousel), and logs an ab_test_view event via gtag (ABTestTracker).

Refactors and updates article UX components. Adds AuthorInfo (now driven by article.author from microCMS) and consolidates duplicated social share UI into ShareButtons; modernizes the sidebar with collapsible sections and a popular/latest switch; updates the header search into a reusable SearchBar with tag suggestions (tags are now fetched in RootLayout).

Also adds generateMetadata for medical-articles/[id], updates assets (adds public/note.svg, removes public/next.svg), and bumps dependencies to include @google-analytics/data.

Written by Cursor Bugbot for commit 26d95aa. This will update automatically on new commits. Configure here.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 1, 2026

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

Project Deployment Actions Updated (UTC)
med-dent-hub Ready Ready Preview, Comment Mar 31, 2026 4:49pm

@Rikublender3d Rikublender3d merged commit 4c21bae into main Mar 1, 2026
4 checks passed
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Bugbot Free Tier Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

</>
) : (
<div key="hero-a">{heroA}</div>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A/B test tracker reports wrong variant to GA4

High Severity

ABTestTracker fires variant='b' to GA4 even when carouselArticles is empty and the user actually sees heroA. The tracker at line 28 always sends the randomly assigned variant, but line 29 falls back to heroA when carouselArticles.length === 0. This corrupts A/B test data — users counted as variant B actually experienced variant A, making experiment results unreliable.

Additional Locations (1)

Fix in Cursor Fix in Web

const popularArticles = sortedByNewest.slice(0, 9)
// 人気記事: GA4 PV順。取得できない場合は最新9件でフォールバック
const popularArticles =
popularFromIds.length > 0 ? popularFromIds : sortedByNewest.slice(0, 6)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Popular articles fallback count mismatches GA4 count

Medium Severity

The comment says "最新9件でフォールバック" but the code does sortedByNewest.slice(0, 6), producing only 6 articles. Meanwhile getPopularArticles(9) requests up to 9 from GA4. The "人気の記事" section shows a visibly different number of articles (9 vs 6 in a 3-column grid) depending on whether GA4 is available, creating an inconsistent layout.

Fix in Cursor Fix in Web

@@ -0,0 +1 @@
export type ABVariant = 'a' | 'b'
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Exported ABVariant type is never imported anywhere

Low Severity

src/lib/ab-test.ts exports ABVariant but no file in the codebase imports it. Both ABHero and ABTestTracker use inline 'a' | 'b' literal types instead. This is dead code that adds confusion about the intended architecture of the A/B test feature.

Fix in Cursor Fix in Web

const popularArticles = sidebarData.popularArticles ?? []
const sidebarListArticles =
popularArticles.length > 0 ? popularArticles : latestArticles
const sidebarListLabel = popularArticles.length > 0 ? '人気記事' : '最新記事'
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sidebar shows duplicate "最新記事" sections when popular empty

Medium Severity

When popularArticles is empty (GA4 unavailable), sidebarListArticles falls back to latestArticles and sidebarListLabel becomes "最新記事". The sidebar then renders two visually identical sections both labeled "最新記事" showing the same articles — the dynamic ranking section and the hardcoded latest articles section below it. This creates a confusing duplicate content block on every article detail page whenever GA4 data is unavailable.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant