# 機能設計書 57-記事キャッシュ

## 概要

本ドキュメントは、Wikipedia iOSアプリにおける記事キャッシュ機能の設計を記述する。この機能は、Wikipedia記事のオフラインアクセスを可能にするための永続キャッシュシステムを提供する。

### 本機能の処理概要

**業務上の目的・背景**：ユーザーがインターネット接続のない環境でも以前閲覧した記事を読めるようにするため、記事コンテンツをローカルにキャッシュする。保存済み記事のオフライン閲覧、および通常閲覧記事の一時キャッシュ機能を提供する。

**機能の利用シーン**：
- 保存リストに記事を追加した際の自動キャッシュ
- オフライン環境での記事閲覧
- 再訪問時の高速表示

**主要な処理内容**：
1. 記事URLをキーとしたキャッシュ追加
2. DBへのメタデータ書き込み
3. ファイルシステムへのコンテンツ書き込み
4. mobile-html-offline-resources/media-listとの同期
5. キャッシュ削除と整合性維持
6. グループキーによるキャッシュ管理

**関連システム・外部連携**：
- Core Data（キャッシュメタデータ管理）
- ファイルシステム（コンテンツ保存）
- Mobile HTML API（記事コンテンツ取得）
- ImageCacheController（画像キャッシュ連携）

**権限による制御**：特別な権限は不要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | Article画面 | 利用画面 | キャッシュからの記事表示 |
| 13 | SavedArticles画面 | 利用画面 | 保存記事のオフライン表示 |

## 機能種別

キャッシュ管理 / ファイル操作 / CRUD操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| url | URL | Yes | キャッシュ対象のURL | 有効なURL形式 |
| groupKey | GroupKey | Yes | キャッシュグループの識別子 | 空文字列でないこと |

### 入力データソース

記事取得API（Mobile HTML、offline-resources、media-list）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| uniqueKey | UniqueKey | キャッシュ済みアイテムの識別子 |
| FinalIndividualResult | Enum | 個別アイテムの処理結果 |
| FinalGroupResult | Enum | グループ全体の処理結果 |

### 出力先

- Core Data（Cache.sqlite）
- ファイルシステム（Permanent Cache/ディレクトリ）

## 処理フロー

### 処理シーケンス

```
1. キャッシュ追加リクエスト
   └─ add(url:groupKey:...)
2. Gatekeeper確認
   └─ 同一グループの処理待ち管理
3. DB書き込み
   └─ dbWriter.add(url:groupKey:)
4. URLRequestリスト取得
   └─ 成功時にダウンロード対象URL取得
5. ファイルダウンロード
   └─ fileWriter.add(groupKey:urlRequest:)
6. ダウンロード完了
   └─ dbWriter.markDownloaded()
7. グループ完了通知
   └─ groupCompletion(.success) or (.failure)
```

### フローチャート

```mermaid
flowchart TD
    A[キャッシュ追加リクエスト] --> B{Gatekeeper: 待機必要?}
    B -->|Yes| C[キューに追加]
    B -->|No| D[currentlyAddingに追加]
    C --> E[待機]
    D --> F[dbWriter.add]
    E --> F
    F --> G{DB書き込み成功?}
    G -->|No| H[failure通知]
    G -->|Yes| I[URLRequestリスト取得]
    I --> J[各URLをダウンロード]
    J --> K{ダウンロード成功?}
    K -->|Yes| L[markDownloaded]
    K -->|No| M[individualFailure記録]
    L --> N{全アイテム完了?}
    M --> N
    N -->|Yes| O[グループ完了通知]
    N -->|No| J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-01 | グループ管理 | 同一groupKeyで関連リソースをまとめる | 記事キャッシュ |
| BR-57-02 | 競合制御 | Gatekeeperで同一グループの並行処理を防止 | 追加/削除操作 |
| BR-57-03 | バリアント管理 | 言語バリアントごとにキャッシュ管理 | バリアント対応言語 |
| BR-57-04 | リソース同期 | offline-resources/media-listと同期 | キャッシュ更新時 |
| BR-57-05 | バックアップ除外 | キャッシュディレクトリはバックアップ対象外 | 常時 |

### 計算ロジック

- UniqueKey: itemKey + variant のハッシュ値

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| キャッシュ追加 | CacheItem | INSERT | アイテムメタデータ追加 |
| ダウンロード完了 | CacheItem | UPDATE | isDownloaded=true |
| キャッシュ削除 | CacheItem | DELETE | アイテム削除 |
| グループ削除 | CacheGroup | DELETE | グループ削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| unableToCreateBackgroundCacheContext | 初期化エラー | コンテキスト作成失敗 | アサート（開発時） |
| atLeastOneItemFailedInFileWriter | ダウンロードエラー | 1つ以上のファイル取得失敗 | エラーログ、部分成功許容 |
| atLeastOneItemFailedInSync | 同期エラー | 同期処理で失敗 | エラーログ |

### リトライ仕様

個別アイテムの失敗はエラーログ記録、グループ全体のリトライは呼び出し元の責任

## トランザクション仕様

Core Dataコンテキストで管理。privateQueueConcurrencyTypeで非同期処理

## パフォーマンス要件

- DispatchGroupで並列ダウンロード管理
- userInitiatedキューで処理

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

- キャッシュディレクトリはApp Container内
- isExcludedFromBackup = true

## 備考

CacheControllerは基底クラスで、ArticleCacheControllerとImageCacheControllerがこれを継承する。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CacheController.swift | `WMF Framework/CacheController.swift` | 基底クラスと型定義 |

**読解のコツ**:
- **109-138行目**: ItemKey, GroupKey, UniqueKey, ItemKeyAndVariantの型定義
- **130-138行目**: FinalIndividualResult, FinalGroupResultの列挙型

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CacheController.swift | `WMF Framework/CacheController.swift` | 基底クラス |
| 2-2 | ArticleCacheController.swift | `WMF Framework/ArticleCacheController.swift` | 記事キャッシュ |

**主要処理フロー**:
1. **149-170行目**: add(url:groupKey:...) - キャッシュ追加
2. **186-284行目**: finishDBAdd() - DB追加後のファイルダウンロード
3. **290-404行目**: remove(groupKey:...) - キャッシュ削除
4. **ArticleCacheController 20-126行目**: syncCachedResources() - リソース同期

#### Step 3: DB/ファイル書き込みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CacheDBWriting.swift | `WMF Framework/` | DB書き込みプロトコル |
| 3-2 | CacheFileWriter.swift | `WMF Framework/` | ファイル書き込み |

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

```
MWKDataStore.cacheController (ArticleCacheController)
    │
    ├─ add(url:groupKey:...)
    │      ├─ gatekeeper.shouldQueueAddCompletion()
    │      ├─ dbWriter.add(url:groupKey:)
    │      │      └─ ArticleCacheDBWriter
    │      │             └─ ArticleFetcher.fetchMobileHTMLOfflineResourceURLs()
    │      │
    │      └─ fileWriter.add(groupKey:urlRequest:)
    │             └─ CacheFileWriter
    │                    └─ Fetcher.dataTaskForURL()
    │
    ├─ syncCachedResources(url:groupKey:)
    │      └─ dbWriter.syncResources()
    │
    └─ remove(groupKey:...)
           ├─ fileWriter.remove(itemKey:variant:)
           └─ dbWriter.remove()
```

### データフロー図

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

記事URL ───▶ ArticleCacheController ───▶ ArticleCacheDBWriter
               │                              │
               │                              ▼
               │                        Core Data
               │                        (Cache.sqlite)
               │                              │
               ▼                              ▼
        CacheFileWriter ───────────▶ ファイルシステム
               │                    (Permanent Cache/)
               │
               ▼
        ImageCacheController
        (画像リソース連携)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CacheController.swift | `WMF Framework/` | ソース | 基底クラス |
| ArticleCacheController.swift | `WMF Framework/` | ソース | 記事キャッシュ管理 |
| CacheDBWriting.swift | `WMF Framework/` | ソース | DB書き込みプロトコル |
| ArticleCacheDBWriter.swift | `WMF Framework/` | ソース | 記事DB書き込み |
| CacheFileWriter.swift | `WMF Framework/` | ソース | ファイル書き込み |
| CacheGatekeeper.swift | `WMF Framework/` | ソース | 競合制御 |
| ArticleFetcher.swift | `WMF Framework/` | ソース | 記事API呼び出し |
