# 画面設計書 24-成長分析画面

## 概要

Ghost管理画面の統計機能における成長分析画面の設計書である。メンバー数の増減、有料会員数、MRR（月間経常収益）の推移を分析し、どのコンテンツやソースが成長に貢献しているかを可視化する。

### 本画面の処理概要

成長分析画面は、サイトの成長指標（メンバー獲得・収益）を多角的に分析するための専門画面である。

**業務上の目的・背景**：サイト運営者がメンバーシップビジネスの成長状況を把握し、どのコンテンツや流入経路が会員獲得・収益に貢献しているかを特定するために使用する。無料会員/有料会員の獲得数、MRR（月間経常収益）の推移を時系列で追跡し、効果的なコンテンツ戦略や収益化施策の立案に役立てる。

**画面へのアクセス方法**：統計画面のナビゲーションから「Growth」タブをクリックするか、直接 `/analytics/growth` にアクセスする。

**主要な操作・処理内容**：
1. 日付範囲セレクターで分析期間を変更
2. Total Members / Free members / Paid members / MRRの各タブでKPIチャートを切り替え
3. コンテンツタイプ（Posts & pages / Posts / Pages / Sources）の切り替え
4. Free members / Paid members / MRR impactでソート順変更
5. 個別投稿をクリックして投稿分析画面へ遷移
6. ソースをクリックして流入経路詳細を確認

**画面遷移**：
- 遷移元：統計概要画面（/analytics）、タブナビゲーション
- 遷移先：投稿分析画面（/posts/analytics/:postId）、メンバー一覧画面（/members）

**権限による表示制御**：有料メンバーシップ機能（paidMembersEnabled）が無効の場合、Paid members/MRR impactのカラムとソートボタンは非表示となる。メンバーソース追跡（membersTrackSources）が無効の場合、DisabledSourcesIndicatorが表示される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 53 | メンバー分析 | 主機能 | メンバー増減・収益の成長分析 |
| 92 | メンバー属性 | 補助機能 | 獲得経路・リファラー分析 |

## 画面種別

ダッシュボード / 分析

## URL/ルーティング

| パス | コンポーネント | 説明 |
|------|---------------|------|
| `/analytics/growth` | Growth | 成長分析画面 |

## 入出力項目

### 入力項目

| 項目名 | 項目ID | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| 日付範囲 | range | number | Yes | 分析期間 |
| KPIタブ | tab | string | No | URLパラメータ：total-members/free/paid/mrr |
| ソート順 | sortBy | string | No | ソート：free_members desc/paid_members desc/mrr desc |
| コンテンツタイプ | selectedContentType | string | No | posts_and_pages/posts/pages/sources |

### 出力項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| 総メンバー数 | number | 期間終了時点の総メンバー数 |
| 無料メンバー数 | number | 無料会員の総数 |
| 有料メンバー数 | number | 有料会員の総数 |
| MRR | number | 月間経常収益（セント単位） |
| チャートデータ | array | 日別メンバー数/MRRの時系列データ |
| トップコンテンツ | array | 成長に貢献したコンテンツ一覧 |
| トップソース | array | 成長に貢献した流入経路一覧 |

## 表示項目

### KPIタブ

| タブ名 | 値 | 説明 | 表示条件 |
|--------|---|------|---------|
| Total members | total-members | 総メンバー数推移 | 常時表示 |
| Free | free | 無料メンバー数推移 | 常時表示 |
| Paid | paid | 有料メンバー数推移 | paidMembersEnabled時 |
| MRR | mrr | MRR推移 | paidMembersEnabled時 |

### コンテンツタブ

| タブ名 | 値 | 説明 |
|--------|---|------|
| Posts & pages | posts_and_pages | 投稿とページ両方 |
| Posts | posts | 投稿のみ |
| Pages | pages | ページのみ |
| Sources | sources | 流入経路 |

### トップコンテンツテーブル

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| title | string | コンテンツタイトル |
| published_at | string | 公開日時 |
| free_members | number | 獲得した無料メンバー数 |
| paid_members | number | 獲得した有料メンバー数 |
| mrr | number | MRRへの貢献額（セント） |

## イベント仕様

### 1-日付範囲変更

**トリガー**: DateRangeSelectで期間を選択

**処理フロー**:
1. GlobalDataContext経由でrangeが更新
2. useGrowthStatsが新しい期間で再実行
3. useTopPostsStatsWithRangeが再実行
4. チャート・テーブルが再描画

### 2-KPIタブ切り替え

**トリガー**: Total members/Free/Paid/MRRタブをクリック

**処理フロー**:
1. GrowthKPIsコンポーネント内でタブ状態が変更
2. チャートに表示するデータ系列が切り替わる
3. URLのtabパラメータが更新される

### 3-コンテンツタイプ切り替え

**トリガー**: Posts & pages/Posts/Pages/Sourcesタブをクリック

**処理フロー**:
1. setSelectedContentType関数でstate更新
2. selectedContentTypeがposts/pages/posts_and_pagesの場合、useTopPostsStatsWithRangeが再実行
3. Sourcesの場合、GrowthSourcesコンポーネントに切り替わる

**関連コード**: `apps/stats/src/views/Stats/Growth/growth.tsx` 159-168行目

### 4-ソート変更

**トリガー**: Free members/Paid members/MRR impactのSortButtonをクリック

**処理フロー**:
1. setSortBy関数でソート順を更新
2. useTopPostsStatsWithRangeのsortByパラメータが変更
3. APIから新しいソート順でデータ取得
4. テーブルが再描画

**関連コード**: `apps/stats/src/views/Stats/Growth/growth.tsx` 172-189行目

### 5-投稿クリック

**トリガー**: テーブル内の投稿タイトルをクリック

**処理フロー**:
1. getClickHandler関数でクリックハンドラを取得
2. navigate関数で `/posts/analytics/:postId` に遷移

**関連コード**: `apps/stats/src/views/Stats/Growth/growth.tsx` 228行目

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | members | SELECT | Ghost APIから成長統計取得 |
| 画面表示 | posts | SELECT | Ghost APIからトップ投稿取得 |

### API呼び出し詳細

#### Ghost API

| エンドポイント | パラメータ | 用途 |
|---------------|-----------|------|
| /ghost/api/admin/stats/member_count/ | range指定 | 成長チャートデータ取得 |
| /ghost/api/admin/stats/referrers/posts/ | range, order_by, post_type | トップ投稿取得 |
| /ghost/api/admin/stats/referrers/sources/ | range, order_by | トップソース取得 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| - | 情報 | No conversions {period} | データがない場合 |
| - | 情報 | Try adjusting your date range to see more data | データなしの補足 |
| - | 情報 | Enable source tracking... | membersTrackSources無効時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| データなし | EmptyIndicatorコンポーネント表示 |
| membersTrackSources無効 | DisabledSourcesIndicator表示 |
| API取得失敗 | StatsErrorBoundaryでエラーページ表示 |

## 備考

- MRRはセント単位で保存されており、centsToDollars関数でドル変換して表示
- currencySymbolはuseGrowthStatsから取得
- コンテンツ重複はpost_id/titleをキーにしてクライアント側で統合（69-91行目）
- Published onの日付はsiteTimezone設定に基づいて表示

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | growth.tsx | `apps/stats/src/views/Stats/Growth/growth.tsx` | UnifiedGrowthContentData型、ソート型定義（21-40行目） |
| 1-2 | content-helpers.ts | `apps/stats/src/utils/content-helpers.ts` | CONTENT_TYPES定数、getContentTitle関数 |

**読解のコツ**: TopPostsOrder/SourcesOrder型がソートの許容値を定義。UnifiedGrowthContentDataがトップコンテンツの統一データ構造。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | growth.tsx | `apps/stats/src/views/Stats/Growth/growth.tsx` | Growthコンポーネント全体（42-280行目） |
| 2-2 | routes.tsx | `apps/stats/src/routes.tsx` | /growthルート定義（22-25行目） |

**主要処理フロー**:
1. **43-51行目**: useGlobalData, useNavigate, useState（sortBy, selectedContentType）
2. **54行目**: initialTabをURLパラメータから取得
3. **57行目**: useGrowthStatsで成長統計取得
4. **60-64行目**: useTopPostsStatsWithRangeでトップ投稿取得
5. **69-124行目**: transformedTopPostsでデータ変換・重複排除・パーセンテージ計算

#### Step 3: KPIコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | growth-kpis.tsx | `apps/stats/src/views/Stats/Growth/components/growth-kpis.tsx` | KPIカード・チャート表示 |

#### Step 4: ソースコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | growth-sources.tsx | `apps/stats/src/views/Stats/Growth/components/growth-sources.tsx` | ソース別成長データ表示 |

#### Step 5: カスタムフックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | use-growth-stats.ts | `apps/stats/src/hooks/use-growth-stats.ts` | 成長チャートデータ取得・加工 |
| 5-2 | use-top-posts-stats-with-range.ts | `apps/stats/src/hooks/use-top-posts-stats-with-range.ts` | トップ投稿取得 |
| 5-3 | use-top-sources-growth.ts | `apps/stats/src/hooks/use-top-sources-growth.ts` | トップソース取得 |

### プログラム呼び出し階層図

```
Growth (growth.tsx)
    │
    ├─ useGlobalData()
    │      └─ range, site, settings取得
    │
    ├─ useGrowthStats(range)
    │      └─ chartData, totals, currencySymbol, subscriptionData取得
    │
    ├─ useTopPostsStatsWithRange(range, sortBy, selectedContentType)
    │      └─ トップ投稿データ取得
    │
    ├─ useMemo: transformedTopPosts
    │      └─ 重複排除、パーセンテージ計算
    │
    ├─ GrowthKPIs
    │      └─ Total members/Free/Paid/MRRチャート表示
    │
    ├─ Table with Tabs
    │      ├─ Posts & pages
    │      ├─ Posts
    │      ├─ Pages
    │      └─ Sources -> GrowthSources
    │
    └─ GrowthSources (selectedContentType === 'sources'時)
           └─ ソース別成長データ表示
```

### データフロー図

```
[入力]                        [処理]                           [出力]

range ─────────────────▶ useGrowthStats ────────────▶ chartData, totals
                                  │
                                  ▼
                           GrowthKPIs
                                  │
                                  ▼
                           Area Chart表示

range + sortBy + ──────▶ useTopPostsStatsWithRange ──▶ topPostsData
selectedContentType              │
                                 ▼
                        transformedTopPosts
                                 │
                                 ▼
                        Table表示 or GrowthSources

投稿クリック ─────────▶ getClickHandler ──────────▶ navigate('/posts/analytics/:postId')
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| growth.tsx | `apps/stats/src/views/Stats/Growth/growth.tsx` | ソース | 成長分析画面メイン |
| growth-kpis.tsx | `apps/stats/src/views/Stats/Growth/components/growth-kpis.tsx` | ソース | KPIチャートカード |
| growth-sources.tsx | `apps/stats/src/views/Stats/Growth/components/growth-sources.tsx` | ソース | ソース別データ |
| use-growth-stats.ts | `apps/stats/src/hooks/use-growth-stats.ts` | ソース | 成長統計フック |
| use-top-posts-stats-with-range.ts | `apps/stats/src/hooks/use-top-posts-stats-with-range.ts` | ソース | トップ投稿フック |
| use-top-sources-growth.ts | `apps/stats/src/hooks/use-top-sources-growth.ts` | ソース | トップソースフック |
| sort-button.tsx | `apps/stats/src/views/Stats/components/sort-button.tsx` | ソース | ソートボタン |
| date-range-select.tsx | `apps/stats/src/views/Stats/components/date-range-select.tsx` | ソース | 日付範囲選択 |
| content-helpers.ts | `apps/stats/src/utils/content-helpers.ts` | ソース | コンテンツヘルパー |
| url-helpers.ts | `apps/stats/src/utils/url-helpers.ts` | ソース | URLヘルパー（getClickHandler） |
| chart-helpers.ts | `apps/stats/src/utils/chart-helpers.ts` | ソース | チャートヘルパー |
| disabled-sources-indicator.tsx | `apps/stats/src/views/Stats/components/disabled-sources-indicator.tsx` | ソース | ソース追跡無効表示 |
