# 帳票設計書 9-Year in Review Report Data

## 概要

本ドキュメントは、Wikipedia iOSアプリケーションにおける「Year in Review Report Data」帳票の設計仕様を定義する。この帳票は年間振り返りのスライドデータをCore Dataに永続化するレポート構造を提供する。

### 本帳票の処理概要

本帳票は、Year in Review機能で表示されるスライドデータを構造化し、Core Dataを通じて永続化するためのモデル定義である。年度ごとのレポートと、その中に含まれる複数のスライド情報を管理する。

**業務上の目的・背景**：Year in Review機能のパーソナライズデータ（読んだ記事数、編集数、お気に入りの時間帯など）を効率的に保存・取得するためのデータ構造を提供する。ユーザーが何度もYear in Reviewを閲覧する際に、毎回データを再計算せずにキャッシュから取得できるようにする。

**帳票の利用シーン**：Year in Review機能を開く際に、データコントローラーがこのレポート構造を使用してパーソナライズデータを取得・保存する。初回アクセス時にデータを収集・計算し、以降はCore Dataからキャッシュを読み込む。

**主要な出力内容**：
1. 年度情報（Int）
2. スライドコレクション（WMFYearInReviewSlide配列）

**帳票の出力タイミング**：Year in Review機能のデータ初期化時にCore Dataに保存、以降の画面表示時に読み込まれる。

**帳票の利用者**：Wikipediaアプリのログインユーザー（Year in Review機能利用者）

## 帳票種別

データ永続化構造（Core Data Entity）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Year in Review | WMFYearInReviewView | データ読み込み/保存 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| 永続化方式 | Core Data |
| エンティティ名 | CDYearInReviewReport, CDYearInReviewSlide |
| データ格納 | SQLite（Core Dataバックエンド） |

### データモデル構造

```swift
public class WMFYearInReviewReport: Identifiable {
    public let year: Int
    public let slides: [WMFYearInReviewSlide]
}
```

## 帳票レイアウト

### WMFYearInReviewReport構造

| No | プロパティ名 | 型 | 説明 | 必須 |
|----|------------|-----|------|-----|
| 1 | year | Int | 対象年度 | Yes |
| 2 | slides | [WMFYearInReviewSlide] | スライド配列 | Yes |

### WMFYearInReviewSlide構造

| No | プロパティ名 | 型 | 説明 | 必須 |
|----|------------|-----|------|-----|
| 1 | year | Int | 対象年度 | Yes |
| 2 | id | WMFYearInReviewPersonalizedSlideID | スライド識別子 | Yes |
| 3 | data | Data? | スライド固有データ | No |

### WMFYearInReviewPersonalizedSlideID列挙型

| 値 | 説明 | データ型（data） |
|-----|------|-----------------|
| readCount | 読んだ記事数 | WMFYearInReviewReadData |
| editCount | 編集数 | Int |
| donateCount | 寄付・編集情報 | DonateAndEditCounts |
| saveCount | 保存記事数 | SavedArticleSlideData |
| mostReadDate | 最も読んだ日時 | WMFPageViewDates |
| viewCount | 編集閲覧数 | Int |
| topArticles | トップ記事 | [String] |
| mostReadCategories | よく読んだカテゴリ | [String] |
| location | 位置情報 | [WMFLegacyPageView] |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| year | 対象年度 | Yes |
| ログイン状態 | ユーザーがログインしていること | No（コレクティブ版は不要） |

### データ保存タイミング

| タイミング | 処理 |
|-----------|------|
| Year in Review初回アクセス | パーソナライズデータ計算・保存 |
| 寄付完了後 | donateCountスライド更新 |
| データリフレッシュ | 全スライド再計算・保存 |

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

### Core Dataエンティティ一覧

| エンティティ名 | 用途 | 属性 |
|--------------|------|------|
| CDYearInReviewReport | 年間レポート | year, slides(relationship) |
| CDYearInReviewSlide | スライドデータ | id, year, data, report(relationship) |

### CDYearInReviewReport属性

| 属性名 | 型 | 説明 |
|--------|-----|------|
| year | Int32 | 対象年度 |
| slides | Set<CDYearInReviewSlide> | スライドリレーション |

### CDYearInReviewSlide属性

| 属性名 | 型 | 説明 |
|--------|-----|------|
| id | String | スライドID（rawValue） |
| year | Int32 | 対象年度 |
| data | Binary | JSON形式のスライドデータ |
| report | CDYearInReviewReport | レポートリレーション |

### リレーション定義

| From | To | 関係 | 削除ルール |
|------|-----|------|----------|
| CDYearInReviewReport.slides | CDYearInReviewSlide | One-to-Many | Cascade |
| CDYearInReviewSlide.report | CDYearInReviewReport | Many-to-One | Nullify |

## 計算仕様

### データ変換処理

| 項目名 | 処理 | 備考 |
|-------|------|------|
| CDReport → WMFReport | init(cdReport:) | Core DataからSwiftモデル変換 |
| slideID変換 | WMFYearInReviewPersonalizedSlideID(rawValue:) | String → Enum |
| dataデコード | JSONDecoder | Binary → 各種構造体 |

## 処理フロー

### データ読み込みフロー

```mermaid
flowchart TD
    A[Year in Review表示] --> B[WMFYearInReviewDataController]
    B --> C[fetchYearInReviewReport]
    C --> D{Core Dataにレポート存在?}
    D -->|Yes| E[CDYearInReviewReport取得]
    D -->|No| F[データ計算・生成]
    E --> G[WMFYearInReviewReport初期化]
    G --> H[CDReportからスライド変換]
    H --> I[WMFYearInReviewSlide配列生成]
    I --> J[レポート返却]
    F --> K[各スライドデータ計算]
    K --> L[Core Dataに保存]
    L --> J
```

### データ変換フロー

```mermaid
flowchart TD
    A[CDYearInReviewReport] --> B[init cdReport]
    B --> C[year取得 Int cdReport.year]
    B --> D[slides取得]
    D --> E{cdSlides as Set?}
    E -->|Yes| F[compactMap処理]
    E -->|No| G[空配列返却]
    F --> H{cdSlide.id存在?}
    H -->|Yes| I[slideID変換]
    H -->|No| J[nil返却]
    I --> K[WMFYearInReviewSlide生成]
    K --> L[slides配列完成]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| Core Dataエラー | DB操作失敗 | なし | エラーログ記録 |
| デコードエラー | data形式不正 | なし | スライドをnilとして扱う |
| ID変換エラー | 不明なslideID | なし | スライドをスキップ |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1レポート/年、最大10スライド程度 |
| 目標読み込み時間 | 数十ミリ秒（キャッシュ読み込み） |
| 初回計算時間 | 数秒（API呼び出し含む） |

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

- 個人情報：ユーザーの閲覧・編集統計を含む
- データ保存：デバイスローカルのCore Dataに保存
- 暗号化：iOS標準のデータ保護に依存
- アクセス制御：アプリ内のみアクセス可能

## 備考

- Identifiableプロトコル準拠でSwiftUI対応
- Cascade削除でレポート削除時にスライドも削除
- targetYearはWMFYearInReviewDataControllerで定義
- hasSeenYiRIntroSlideでイントロスライド表示済みフラグ管理

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WMFYearInReviewReport.swift | `WMFData/Sources/WMFData/Models/Year In Review/WMFYearInReviewReport.swift` | レポートモデルのプロパティと初期化を理解 |
| 1-2 | WMFYearInReviewSlide.swift | `WMFData/Sources/WMFData/Models/Year In Review/WMFYearInReviewSlide.swift` | スライドモデルとPersonalizedSlideID列挙型を理解 |

**読解のコツ**: WMFYearInReviewReportはSwiftモデル、CDYearInReviewReportはCore Dataエンティティ。init(cdReport:)でCore DataからSwiftモデルへの変換を行う。

#### Step 2: Core Dataエンティティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | WMFData 5.xcdatamodel | `WMFData/Sources/WMFData/Resources/WMFData.xcdatamodeld/WMFData 5.xcdatamodel/contents` | エンティティ定義、属性、リレーションを確認 |

**主要処理フロー**:
- **行50-53**: CDYearInReviewReport定義 - year属性、slidesリレーション
- **行54-59**: CDYearInReviewSlide定義 - id, year, data属性、reportリレーション

#### Step 3: モデル変換処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WMFYearInReviewReport.swift | `WMFData/Sources/WMFData/Models/Year In Review/WMFYearInReviewReport.swift` 行12-31 | init(cdReport:)の変換処理 |

**主要処理フロー**:
- **行12-14**: init(cdReport:)開始、year取得
- **行16-19**: cdSlides取得、Set型へのキャスト確認
- **行21-30**: compactMapでCDSlide → WMFSlide変換

#### Step 4: スライドID列挙型を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | WMFYearInReviewSlide.swift | `WMFData/Sources/WMFData/Models/Year In Review/WMFYearInReviewSlide.swift` 行15-52 | WMFYearInReviewPersonalizedSlideID定義 |

**主要処理フロー**:
- **行15-24**: 列挙型ケース定義（readCount, editCount, donateCount等）
- **行26-28**: Comparable実装（rawValueで比較）
- **行30-51**: dataController()関数（各スライドのデータコントローラー取得）

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

```
WMFYearInReviewView (UI)
    │
    ├─ WMFYearInReviewViewModel
    │      │
    │      └─ WMFYearInReviewDataController
    │             │
    │             ├─ fetchYearInReviewReport(forYear:)
    │             │      │
    │             │      ├─ Core Data NSFetchRequest
    │             │      │     └─ CDYearInReviewReport
    │             │      │
    │             │      └─ WMFYearInReviewReport(cdReport:)
    │             │            │
    │             │            └─ compactMap { cdSlide in
    │             │                  WMFYearInReviewSlide(year:id:)
    │             │               }
    │             │
    │             └─ saveYearInReviewReport(_:)
    │                    │
    │                    └─ Core Data NSManagedObjectContext.save()
    │
    └─ slides: [WMFYearInReviewSlide]
```

### データフロー図

```
[Core Data]                [Swift Model]               [UI]

CDYearInReviewReport ────▶ WMFYearInReviewReport ────▶ WMFYearInReview
  │                              │                     ViewModel
  ├─ year: Int32                 ├─ year: Int
  └─ slides ◀──────────────────▶ └─ slides: [WMFYearInReviewSlide]
       │                                   │
       │                                   └─ year: Int
CDYearInReviewSlide                        └─ id: PersonalizedSlideID
  │                                        └─ data: Data?
  ├─ id: String ─────▶ rawValue変換 ─▶ PersonalizedSlideID
  ├─ year: Int32
  ├─ data: Binary ───▶ JSONDecoder ─▶ 各種構造体
  └─ report ◀──────────────────────────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| WMFYearInReviewReport.swift | `WMFData/Sources/WMFData/Models/Year In Review/` | ソース | レポートモデル定義 |
| WMFYearInReviewSlide.swift | `WMFData/Sources/WMFData/Models/Year In Review/` | ソース | スライドモデル定義 |
| WMFData 5.xcdatamodel | `WMFData/Sources/WMFData/Resources/WMFData.xcdatamodeld/` | 設定 | Core Dataエンティティ定義 |
| WMFYearInReviewDataController.swift | `WMFData/Sources/WMFData/Data Controllers/Year In Review/` | ソース | データ操作コントローラー |
| WMFYearInReviewSlideDataControllerProtocol.swift | `WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/` | ソース | スライドデータコントローラープロトコル |
