# 画面設計書 23-Webトラフィック画面

## 概要

Ghost管理画面の統計機能におけるWebトラフィック分析画面の設計書である。サイトへの訪問者数、ページビュー数、直帰率、滞在時間などのWeb解析指標を詳細に分析し、トップコンテンツ、参照元、地域別アクセス状況を可視化する。

### 本画面の処理概要

Webトラフィック画面は、サイトへのWeb訪問者の行動を多角的に分析するための専門画面である。

**業務上の目的・背景**：サイト運営者がWebトラフィックの詳細を把握し、コンテンツ戦略やSEO施策の効果を検証するために使用する。どのコンテンツが閲覧されているか、訪問者がどこから来ているか、どの地域からアクセスが多いかを分析することで、ターゲットオーディエンスへのリーチを最適化できる。

**画面へのアクセス方法**：統計画面のナビゲーションから「Web」タブをクリックするか、直接 `/analytics/web` にアクセスする。Webアナリティクス機能が無効の場合は、概要画面（/analytics）にリダイレクトされる。

**主要な操作・処理内容**：
1. 日付範囲の選択による分析期間の変更
2. KPIチャート（訪問者数/ページビュー/直帰率/滞在時間）の切り替え表示
3. フィルタリング機能によるデータ絞り込み（オーディエンス、ソース、UTMパラメータ等）
4. トップコンテンツ一覧の確認と投稿分析への遷移
5. トップソース（参照元）一覧の確認とクリックフィルタリング
6. 地域別アクセス分布の確認とクリックフィルタリング

**画面遷移**：
- 遷移元：統計概要画面（/analytics）、タブナビゲーション
- 遷移先：投稿分析画面（/posts/analytics/:postId）、ソースでフィルタリング後の同画面

**権限による表示制御**：Webアナリティクス（appSettings.analytics.webAnalytics）が無効の場合、本画面は表示されず概要画面にリダイレクトされる。オーディエンスフィルタはメンバーシップ機能が有効な場合のみ使用可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 51 | サイト統計 | 主機能 | Webトラフィックの詳細分析 |
| 55 | Tinybird連携 | 補助機能 | Tinybirdからのアナリティクスデータ取得 |

## 画面種別

ダッシュボード / 分析

## URL/ルーティング

| パス | コンポーネント | 説明 |
|------|---------------|------|
| `/analytics/web` | Web | Webトラフィック分析画面 |

## 入出力項目

### 入力項目

| 項目名 | 項目ID | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| 日付範囲 | range | number | Yes | 分析期間（7, 30, 90, -1など） |
| オーディエンス | audience | string | No | フィルタ：all/free/paid |
| ソース | source | string | No | フィルタ：参照元ドメイン |
| ロケーション | location | string | No | フィルタ：国/地域名 |
| 投稿 | post | string | No | フィルタ：post_uuidまたはpathname |
| UTMソース | utm_source | string | No | フィルタ：UTMソース |
| UTMメディア | utm_medium | string | No | フィルタ：UTMメディア |
| UTMキャンペーン | utm_campaign | string | No | フィルタ：UTMキャンペーン |

### 出力項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| 訪問者数 | number | 選択期間内のユニーク訪問者数 |
| ページビュー数 | number | 選択期間内の総ページビュー数 |
| 直帰率 | number | 1ページのみ閲覧して離脱した割合 |
| 平均滞在時間 | number | 訪問あたりの平均滞在秒数 |
| トップコンテンツ | array | 閲覧数上位のコンテンツ一覧 |
| トップソース | array | 参照元上位の一覧 |
| 地域別データ | array | 国/地域別訪問者数 |

## 表示項目

### KPIメトリクス

| メトリクスキー | dataKey | ラベル | フォーマッター | チャート色 |
|---------------|---------|--------|--------------|-----------|
| visits | visits | Visitors | formatNumber | chart-blue |
| views | pageviews | Pageviews | formatNumber | chart-teal |
| bounce-rate | bounce_rate | Bounce rate | formatPercentage | chart-teal |
| visit-duration | avg_session_sec | Visit duration | formatDuration | chart-teal |

### トップコンテンツセクション

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| pathname | string | コンテンツのパス |
| visits | number | 訪問者数 |
| percentage | number | 全体に対する割合 |

### トップソースセクション

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| source | string | 参照元（ドメインまたは"Direct"） |
| visits | number | 訪問者数 |
| percentage | number | 全体に対する割合 |

### 地域別セクション

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| location | string | 国/地域名 |
| visits | number | 訪問者数 |
| percentage | number | 全体に対する割合 |

## イベント仕様

### 1-日付範囲変更

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

**処理フロー**:
1. setRange関数で新しい期間値を設定
2. paramsのdate_from/date_toが更新
3. useTinybirdQueryが新しいparamsで再実行
4. KPIチャート・テーブルが再描画

### 2-フィルタ適用

**トリガー**: StatsFilterコンポーネントでフィルタを設定

**処理フロー**:
1. setAnalyticsFilters関数でフィルタ配列を更新
2. filterParamsがuseMemoで再計算
3. Tinybird APIにフィルタパラメータが追加
4. データが絞り込まれて再表示
5. scrollToTop関数でページ先頭にスクロール

**関連コード**: `apps/stats/src/views/Stats/Web/web.tsx` 81-118行目

### 3-ソースクリック

**トリガー**: トップソース一覧のソース名をクリック

**処理フロー**:
1. handleSourceClick関数が発火
2. createFilterでsourceフィルタを作成
3. setAnalyticsFiltersでフィルタ適用
4. データがソースで絞り込まれて再表示

**関連コード**: `apps/stats/src/views/Stats/Web/web.tsx` 137行目

### 4-ロケーションクリック

**トリガー**: 地域別一覧の国/地域名をクリック

**処理フロー**:
1. handleLocationClick関数が発火
2. createFilterでlocationフィルタを作成
3. setAnalyticsFiltersでフィルタ適用
4. データがロケーションで絞り込まれて再表示

**関連コード**: `apps/stats/src/views/Stats/Web/web.tsx` 136行目

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | - | SELECT | Tinybird APIからKPI/ソース/ロケーションデータ取得 |

### Tinybird API呼び出し詳細

| エンドポイント | パラメータ | 戻り値 | 用途 |
|---------------|-----------|--------|------|
| api_kpis | site_uuid, date_from, date_to, timezone, member_status, [filters] | visits, pageviews, bounce_rate, avg_session_sec | KPIデータ |
| api_top_sources | site_uuid, date_from, date_to, timezone, member_status, [filters] | source, visits配列 | トップソース |
| api_top_locations | site_uuid, date_from, date_to, timezone, member_status, [filters] | location, visits配列 | 地域別データ |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| - | 情報 | No visitors {period} | データがない場合 |
| - | 情報 | Try adjusting filters to see more data | フィルタ適用後データなし |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| webAnalytics無効 | /analytics（概要）にリダイレクト |
| データなし | EmptyIndicatorコンポーネントを表示 |
| API取得失敗 | StatsErrorBoundaryでエラーページ表示 |

## 備考

- フィルタパラメータはURLに同期されるため、ブックマークや共有が可能
- "Direct"トラフィック（source=""）は空文字列でフィルタリング
- Unknown地域（UNKNOWN_LOCATION_VALUES）は「Unknown」として集約表示
- STATS_DEFAULT_SOURCE_ICON_URLがソースアイコンのデフォルト

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | web.tsx | `apps/stats/src/views/Stats/Web/web.tsx` | SourcesData型、KPI_METRICS定義（19-51行目） |
| 1-2 | use-filter-params.ts | `apps/stats/src/hooks/use-filter-params.ts` | フィルタのURL同期ロジック |

**読解のコツ**: KPI_METRICSオブジェクトで各メトリクスのdataKey、フォーマッター、チャート色が定義されている。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | web.tsx | `apps/stats/src/views/Stats/Web/web.tsx` | Webコンポーネント全体（53-240行目） |
| 2-2 | routes.tsx | `apps/stats/src/routes.tsx` | /webルート定義（18-21行目） |

**主要処理フロー**:
1. **54-56行目**: useGlobalDataでstatsConfig/range取得
2. **59行目**: useFilterParamsでURLフィルタ同期
3. **62-65行目**: オーディエンスフィルタ抽出
4. **81-118行目**: filterParamsの構築（UTM、ソース、ポスト等）
5. **140-147行目**: 共通paramsの構築
6. **150-168行目**: useTinybirdQueryでKPI/ソース/ロケーション取得
7. **176-179行目**: webAnalytics無効時リダイレクト

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | web-kpis.tsx | `apps/stats/src/views/Stats/Web/components/web-kpis.tsx` | KPIチャート表示ロジック |
| 3-2 | top-content.tsx | `apps/stats/src/views/Stats/Web/components/top-content.tsx` | トップコンテンツ一覧 |
| 3-3 | sources-card.tsx | `apps/stats/src/views/Stats/Web/components/sources-card.tsx` | トップソース一覧 |
| 3-4 | locations-card.tsx | `apps/stats/src/views/Stats/Locations/components/locations-card.tsx` | 地域別一覧 |

#### Step 4: フィルタロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | stats-filter.tsx | `apps/stats/src/views/Stats/components/stats-filter.tsx` | フィルタUIコンポーネント |
| 4-2 | audience.ts | `apps/stats/src/utils/audience.ts` | オーディエンスフィルタヘルパー |

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

```
Web (web.tsx)
    │
    ├─ useGlobalData()
    │      └─ statsConfig, range, data取得
    │
    ├─ useFilterParams()
    │      └─ analyticsFilters, setAnalyticsFilters取得
    │
    ├─ useMemo: audience計算
    │      └─ getAudienceFromFilterValues()
    │
    ├─ useMemo: filterParams構築
    │      └─ source, location, post, utm_*パラメータ
    │
    ├─ useMemo: params構築
    │      └─ site_uuid, date_from, date_to, timezone, member_status, filters
    │
    ├─ useTinybirdQuery({endpoint: 'api_kpis'})
    │      └─ kpiData取得
    │
    ├─ useTinybirdQuery({endpoint: 'api_top_sources'})
    │      └─ sourcesData取得
    │
    ├─ useTinybirdQuery({endpoint: 'api_top_locations'})
    │      └─ locationsData取得
    │
    ├─ WebKPIs
    │      └─ KPIチャート表示
    │
    ├─ TopContent
    │      └─ トップコンテンツ一覧表示
    │
    ├─ SourcesCard
    │      └─ トップソース一覧（onSourceClickコールバック）
    │
    └─ LocationsCard
           └─ 地域別一覧（onLocationClickコールバック）
```

### データフロー図

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

range + filters ────────▶ useMemo: params構築 ───────▶ Tinybird API
                                  │
                         useTinybirdQuery x 3
                                  │
                                  ▼
                    ┌─────────────┼─────────────┐
                    ▼             ▼             ▼
                kpiData     sourcesData   locationsData
                    │             │             │
                    ▼             ▼             ▼
                WebKPIs     SourcesCard  LocationsCard
                    │             │             │
                    ▼             ▼             ▼
               チャート表示   テーブル表示   地図/テーブル

クリックイベント ───────▶ handleFilterClick ───────▶ setAnalyticsFilters
                                  │
                                  ▼
                         filterParams更新
                                  │
                                  ▼
                         データ再取得・再描画
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| web.tsx | `apps/stats/src/views/Stats/Web/web.tsx` | ソース | Webトラフィック画面メイン |
| web-kpis.tsx | `apps/stats/src/views/Stats/Web/components/web-kpis.tsx` | ソース | KPIチャートカード |
| top-content.tsx | `apps/stats/src/views/Stats/Web/components/top-content.tsx` | ソース | トップコンテンツ |
| sources-card.tsx | `apps/stats/src/views/Stats/Web/components/sources-card.tsx` | ソース | トップソース |
| locations-card.tsx | `apps/stats/src/views/Stats/Locations/components/locations-card.tsx` | ソース | 地域別データ |
| stats-filter.tsx | `apps/stats/src/views/Stats/components/stats-filter.tsx` | ソース | フィルタUI |
| date-range-select.tsx | `apps/stats/src/views/Stats/components/date-range-select.tsx` | ソース | 日付範囲選択 |
| use-filter-params.ts | `apps/stats/src/hooks/use-filter-params.ts` | ソース | フィルタURL同期 |
| audience.ts | `apps/stats/src/utils/audience.ts` | ソース | オーディエンスヘルパー |
| constants.ts | `apps/stats/src/utils/constants.ts` | ソース | 定数定義 |
