# 帳票設計書 4-Year in Review Highlights Shareable

## 概要

本ドキュメントは、Wikipedia iOSアプリケーションにおける「Year in Review Highlights Shareable」帳票の設計仕様を定義する。この帳票は年間ハイライト（最も読んだ記事、読書時間、お気に入りカテゴリなど）のサマリーを共有可能な画像として生成する機能を提供する。

### 本帳票の処理概要

本帳票は、ユーザーの一年間のWikipedia利用活動の総括として、複数の統計情報をInfobox形式で集約表示した共有可能な画像を生成する機能である。

**業務上の目的・背景**：Year in Reviewの締めくくりとして、ユーザーの年間活動を一目で把握できるサマリーカードを提供する。最も読んだ記事、読書時間、お気に入りの曜日、読んだ記事数、お気に入りカテゴリ、編集数など、複数の指標を一枚の画像にまとめることで、SNS共有時のインパクトを最大化する。

**帳票の利用シーン**：Year in Review機能の最終スライドにおいて、ユーザーが年間活動の総括をソーシャルメディアで共有したい場合に使用される。Wikipedia利用の「ハイライト」を友人やフォロワーと共有することで、知的コミュニティへの参加感を醸成する。

**主要な出力内容**：
1. ハッシュタグ（#WikipediaYearInReview）
2. Wikipediaグローブロゴ（globe_yir）とキャプション
3. Infobox形式のテーブル（複数の統計項目）
4. プレーンテキストURL
5. 外枠ボーダー

**帳票の出力タイミング**：Year in Review画面のHighlightsスライド表示中に、ユーザーが「Share」ボタンをタップした時点で画像が生成される。

**帳票の利用者**：Wikipediaアプリのユーザー（パーソナライズ版は2項目以上のデータがあるログインユーザー、コレクティブ版は全ユーザー）

## 帳票種別

共有画像（Infobox形式サマリーカード画像）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Year in Review Highlights Slide View | WMFYearInReviewSlideHighlightsView | Shareボタンタップ |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | PNG（UIImage） |
| 用紙サイズ | 393 x 852ポイント（最小高さ） |
| 向き | 縦 |
| ファイル名 | システム生成（UIActivityViewController経由） |
| 出力方法 | UIActivityViewController（共有シート） |
| 文字コード | UTF-8 |

### 画像固有設定

| 項目 | 内容 |
|-----|------|
| スケール | UIScreen.main.scale（デバイス解像度対応） |
| 背景色 | WMFColor.white |
| レンダリング | SwiftUI ImageRenderer |
| ボーダー | WMFColor.gray300、1pt幅 |

## 帳票レイアウト

### レイアウト概要

Infobox形式の情報カードで、ハッシュタグ、ロゴ、テーブル、URLの構成となっている。

```
┌─────────────────────────────────────┐
│   #WikipediaYearInReview            │
│         (ハッシュタグ)               │
├─────────────────────────────────────┤
│                                     │
│      [globe_yir 166x166]            │
│      "Your 2024 on Wikipedia"       │
│              ロゴ部                  │
├─────────────────────────────────────┤
│  Top articles    │ 1. Article A     │
│                  │ 2. Article B     │
│                  │ 3. Article C     │
│──────────────────┼──────────────────│
│  Minutes read    │ 1,234            │
│──────────────────┼──────────────────│
│  Favorite day    │ Saturday         │
│──────────────────┼──────────────────│
│  Articles read   │ 567              │
│              テーブル部               │
├─────────────────────────────────────┤
│      wikipedia.org/year-in-review   │
│              URL部                   │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | ハッシュタグ | キャンペーンタグ固定 | ハードコード | helveticaLargeHeadline、黒色 |

### ロゴ部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | グローブロゴ | Wikipedia YiRロゴ | Bundle.module "globe_yir" | 166x166pt |
| 2 | ロゴキャプション | 年度キャプション | viewModel.logoCaption | helveticaCaption1 |

### テーブル部（Infobox）

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | タイトル列 | 項目名 | TableItem.title | helveticaBodyBold | 108pt（デフォルト） |
| 2 | 値列（テキスト） | 単一値 | TableItem.text | helveticaBody | 残り幅 |
| 3 | 値列（リッチ） | 番号付きリスト | TableItem.richRows | helveticaBody | 残り幅 |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | URL | プレーンテキストURL | viewModel.plaintextURL | body、黒色 |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| viewModel | WMFYearInReviewSlideHighlightsViewModel | Yes |
| infoBoxViewModel | WMFInfoboxViewModel | Yes |
| tableItems | 2項目以上（パーソナライズ版） | Yes（パーソナライズ版） |

### パーソナライズ版の項目

| 項目名 | 表示条件 |
|--------|---------|
| Top articles | highlightsTopReadArticles存在時 |
| Minutes read | highlightsMinutesRead存在時 |
| Favorite day | highlightsFavoriteReadingDay存在時 |
| Articles read | highlightsReadCount存在時 |
| Favorite categories | highlightsFrequentCategories存在時 |
| Edited articles | highlightsEditNumber > 0時 |

### コレクティブ版（英語）の項目

| 項目名 | 内容 |
|--------|------|
| enWikiTopArticlesTitle | トップ記事リスト |
| hoursSpentReadingTitle | 読書時間 |
| numberOfChangesMadeTitle | 変更数 |

### コレクティブ版（非英語）の項目

| 項目名 | 内容 |
|--------|------|
| numberOfViewedArticlesTitle | 閲覧記事数 |
| numberOfEditsTitle | 編集数 |
| editFrequencyTitle | 編集頻度 |

### ソート順

該当なし（単一画像出力のため）

### 改ページ条件

該当なし（単一画像出力のため）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| CDYearInReviewReport | 年間レポートデータ | year = 対象年 |
| CDYearInReviewSlide | 複数スライドデータ | report.year = 対象年 |

### 参照スライドID一覧

| スライドID | 用途 |
|-----------|------|
| readCount | 読んだ記事数、読書時間 |
| topArticles | トップ記事リスト |
| mostReadDate | お気に入りの曜日 |
| mostReadCategories | お気に入りカテゴリ |
| editCount | 編集数 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 画像スケール | UIScreen.main.scale | - | デバイス解像度に応じた値 |
| 提案サイズ幅 | 393ポイント固定 | - | レンダラー設定 |
| タイトル列幅 | (containerWidth / 5) * 2 | - | アダプティブ幅有効時 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[Shareボタンタップ] --> B[tappedShare呼び出し]
    B --> C{スライドタイプ判定}
    C -->|highlights| D[WMFYearInReviewSlideHighlightShareableView生成]
    D --> E[ImageRenderer初期化]
    E --> F[proposedSize設定 393x nil]
    F --> G[scale設定 UIScreen.main.scale]
    G --> H[renderer.uiImage取得]
    H --> I{画像生成成功?}
    I -->|Yes| J[coordinatorDelegate.share呼び出し]
    I -->|No| K[処理終了]
    J --> L[UIActivityViewController表示]
    L --> M[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 画像生成失敗 | renderer.uiImageがnil | なし（サイレント失敗） | 処理を中断 |
| データ不足 | tableItems < 2（パーソナライズ版） | なし | コレクティブ版にフォールバック |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1件/回 |
| 目標出力時間 | 1秒以内 |
| 同時出力数上限 | 1件 |

## セキュリティ考慮事項

- 個人情報：ユーザーの読書履歴、編集履歴の集約情報を含む
- プライバシー：興味関心分野が推測される可能性
- アクセス制御：ユーザーの明示的な操作（Shareボタンタップ）が必要
- 出力ログ：loggingDelegateを通じてlogYearInReviewDidTapShareで記録

## 備考

- Helveticaフォントファミリーを使用した統一感のあるデザイン
- ハードコードされた色（WMFColor.white, black, gray100, gray300）で一貫性確保
- 番号付きリスト（richRows）はAttributedStringで色分け表示
- パーソナライズ版とコレクティブ版の2パターンあり

---

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

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

### 推奨読解順序

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

まず、プログラム間で受け渡されるデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WMFYearInReviewHighlightsViewModel.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/View Models/WMFYearInReviewHighlightsViewModel.swift` | ViewModelのプロパティ構成（infoBoxViewModel, hashtag, plaintextURL）を理解 |
| 1-2 | WMFInfoboxViewModel.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/View Models/WMFInfoboxViewModel.swift` | Infoboxデータモデル（logoCaption, tableItems）、TableItem構造を理解 |

**読解のコツ**: TableItemのtextとrichRowsの使い分け、InfoboxRichRowによる番号付きリストの構造を把握する。

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

処理の起点となるファイル・関数を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | WMFYearInReviewViewModel.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/View Models/WMFYearInReviewViewModel.swift` | tappedShare()関数内のhighlightsケース（行1008-1016）が共有処理 |

**主要処理フロー**:
1. **行1008**: highlightsスライドの場合の分岐
2. **行1009**: WMFYearInReviewSlideHighlightShareableViewを生成
3. **行1010-1015**: ImageRendererで画像化、coordinatorDelegate.share呼び出し

#### Step 3: 共有可能ビューの構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WMFYearInReviewSlideHighlightShareableView.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/Views/Shareable Slide Views/WMFYearInReviewSlideHighlightShareableView.swift` | SwiftUIビューの構造、infoboxViewの組み込みを理解 |

**主要処理フロー**:
- **行26-56**: body定義 - ZStack背景、VStack縦並び
- **行34-36**: infoboxView（WMFYearInReviewInfoboxView使用）
- **行42-46**: plaintextURL表示
- **行52-55**: ボーダーオーバーレイ

#### Step 4: Infoboxビューの詳細を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | WMFYearInReviewInfoboxView.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/Views/Slide Views/WMFYearInReviewInfoboxView.swift` | テーブルレイアウト、richRows/text切り替え |

**主要処理フロー**:
- **行43-117**: body定義 - ハッシュタグ、ロゴ、テーブル
- **行62-112**: ForEachでtableItems反復、HStackで2列レイアウト
- **行72-89**: richRowsの場合（番号付きリスト）
- **行90-100**: textの場合（単一値）

#### Step 5: パーソナライズデータの構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | WMFYearInReviewViewModel.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/View Models/WMFYearInReviewViewModel.swift` 行629-680 | getPersonalizedHighlights関数 |

**主要処理フロー**:
- **行631-638**: トップ記事からTableItem生成
- **行640-642**: 読書時間からTableItem生成
- **行644-647**: お気に入り曜日からTableItem生成
- **行649-652**: 読んだ記事数からTableItem生成
- **行654-660**: カテゴリからTableItem生成
- **行662-665**: 編集数からTableItem生成
- **行667-679**: itemArray >= 2ならViewModel生成

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

```
WMFYearInReviewView (UI)
    │
    ├─ WMFYearInReviewViewModel.tappedShare()
    │      │
    │      ├─ case .highlights(let viewModel)
    │      │
    │      ├─ WMFYearInReviewSlideHighlightShareableView(viewModel:)
    │      │      │
    │      │      └─ body: View
    │      │             ├─ ZStack (白背景)
    │      │             │
    │      │             ├─ VStack
    │      │             │     ├─ infoboxView
    │      │             │     │     └─ WMFYearInReviewInfoboxView(viewModel:isSharing:)
    │      │             │     │           ├─ Text("#WikipediaYearInReview")
    │      │             │     │           ├─ Image("globe_yir")
    │      │             │     │           ├─ Text(logoCaption)
    │      │             │     │           └─ ForEach(tableItems)
    │      │             │     │                 ├─ Text(item.title)
    │      │             │     │                 └─ richRows or text
    │      │             │     │
    │      │             │     └─ Text(plaintextURL)
    │      │             │
    │      │             └─ overlay (gray300 border)
    │      │
    │      ├─ ImageRenderer(content: view)
    │      │      └─ renderer.uiImage
    │      │
    │      └─ coordinatorDelegate.handleYearInReviewAction(.share(image:))
    │
    └─ UIActivityViewController (システム共有シート)
```

### データフロー図

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

Year in Review           getPersonalizedHighlights()      ユーザー共有先
スライドデータ ───────────▶     or                         (Twitter/Facebook等)
  │                      getEnglishCollectiveHighlights()
  ├─ topArticles              or
  ├─ minutesRead         getCollectiveHighlights()
  ├─ favoriteDay               │
  ├─ articlesRead              ▼
  ├─ categories         WMFInfoboxViewModel
  └─ editCount                 │
                               ├─ logoCaption
                               └─ tableItems[]
                                    │
                                    ▼
                    WMFYearInReviewSlide
                    HighlightShareableView
                               │
                               ▼
                    WMFYearInReviewInfoboxView
                               │
                               ▼
                          ImageRenderer
                               │
                               ▼
                          UIImage
                               │
                               ▼
                    UIActivityViewController
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| WMFYearInReviewSlideHighlightShareableView.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/Views/Shareable Slide Views/` | ソース | 共有用ビュー定義 |
| WMFYearInReviewHighlightsViewModel.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/View Models/` | ソース | ハイライトViewModel |
| WMFInfoboxViewModel.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/View Models/` | ソース | Infoboxデータモデル |
| WMFYearInReviewInfoboxView.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/Views/Slide Views/` | ソース | Infobox表示ビュー |
| WMFYearInReviewViewModel.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/View Models/` | ソース | 共有処理ロジック |
| WMFYearInReviewSlideHighlightsView.swift | `WMFComponents/Sources/WMFComponents/Components/Year in Review/Views/Slide Views/` | ソース | 表示用ビュー |
