# 機能設計書 17-リスト新規作成

## 概要

本ドキュメントは、Wikipedia iOSアプリにおける「リスト新規作成」機能の設計を記述する。この機能は、ユーザーが新しいリーディングリストを作成するためのUIと処理を提供するものである。

### 本機能の処理概要

**業務上の目的・背景**：ユーザーが保存記事を整理するために、カスタムのリーディングリストを作成できるようにする。目的別（仕事/趣味/学習など）、テーマ別（歴史/科学/文化など）にリストを分けることで、効率的な情報管理を実現する。

**機能の利用シーン**：Saved画面の「Create new list」ボタン、記事保存時の「Add to list」メニュー、共有リンクからのインポート時などにリスト作成画面が表示される。ユーザーはリスト名と任意の説明を入力してリストを作成する。

**主要な処理内容**：
1. リスト作成画面の表示
2. リスト名と説明の入力受付
3. 入力バリデーション（名前の重複チェック）
4. リストの作成とCore Dataへの保存
5. 作成完了後のデリゲート通知
6. 共有リンクからのリストインポート対応

**関連システム・外部連携**：ReadingListsController（WMFReadingListsController）と連携してリストを作成する。インポート機能ではPageIDToURLFetcherとArticleFetcherを使用。

**権限による制御**：本機能は認証不要で利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | Saved画面 | 呼び出し元画面 | 「Create new list」ボタン |
| 6 | Article画面 | 呼び出し元画面 | 「Add to list」メニュー |

## 機能種別

データ入力 / フォーム処理 / データ登録

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | リスト名 | 空白でないこと、重複しないこと |
| description | String? | No | リストの説明 | 最大文字数なし |
| articles | [WMFArticle] | No | 追加する記事配列 | - |
| encodedPageIds | String? | No | インポート用エンコード済みページID | Base64エンコード |

### 入力データソース

- 画面入力：readingListNameTextField, descriptionTextField
- 外部入力：共有リンクからのエンコード済みページID

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| readingList | ReadingList | 作成されたリーディングリスト |
| articles | [WMFArticle] | リストに追加された記事配列 |

### 出力先

- Core Data：ReadingList エンティティ
- デリゲート：CreateReadingListDelegate

## 処理フロー

### 処理シーケンス

```
1. リスト作成画面表示
   └─ CreateReadingListViewController を表示
2. リスト名入力
   └─ readingListNameTextField で入力受付
3. 説明入力（任意）
   └─ descriptionTextField で入力受付
4. 作成ボタンタップ
   └─ createReadingListButtonPressed() が呼ばれる
5. バリデーション
   └─ 空白チェック、名前重複チェック
6. リスト作成
   └─ delegate.createReadingListViewController(_:didCreateReadingListWith:) 通知
7. 画面を閉じる
   └─ navigationController?.dismiss(animated:)
```

### フローチャート

```mermaid
flowchart TD
    A[画面表示] --> B{インポートモード?}
    B -->|Yes| C[ページID取得]
    C --> D[記事情報フェッチ]
    D --> E[デフォルトリスト名設定]
    B -->|No| F[リスト名入力待ち]
    E --> F
    F --> G[リスト名入力]
    G --> H[説明入力（任意）]
    H --> I[作成ボタンタップ]
    I --> J{バリデーション}
    J -->|失敗| K[エラー表示]
    K --> G
    J -->|成功| L[デリゲート通知]
    L --> M[画面閉じる]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-17-01 | リスト名必須 | リスト名は空白のみでは不可 | 作成ボタン活性化条件 |
| BR-17-02 | リスト名一意性 | 同一名称のリストは作成不可 | 作成処理時 |
| BR-17-03 | 説明任意 | 説明フィールドは入力任意 | - |
| BR-17-04 | インポートモード | エンコード済みページIDがある場合はインポートモード | isInImportingMode |
| BR-17-05 | デフォルト名 | インポートモードでは「My Reading List」がデフォルト名 | インポート時 |

### 計算ロジック

空白チェック:
```swift
var isReadingListNameFieldEmpty: Bool {
    return !readingListNameTextField.wmf_hasNonWhitespaceText
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| リスト作成 | ReadingList | INSERT | 新しいリーディングリストを作成 |
| エントリ追加 | ReadingListEntry | INSERT | 指定記事をリストに追加 |

### テーブル別操作詳細

#### ReadingList

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | 入力されたリスト名 | 必須 |
| INSERT | readingListDescription | 入力された説明 | 任意 |
| INSERT | createdDate | 作成日時 | 自動設定 |
| INSERT | isDefault | false | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| listExistsWithTheSameName | ビジネスエラー | 同名リストが存在 | エラーラベル表示 |
| failureDecodingPayload | インポートエラー | ページIDデコード失敗 | アラート表示 |
| failureFetchingPageURLs | インポートエラー | ページURL取得失敗 | アラート表示 |
| missingDataStore | インポートエラー | データストア未設定 | アラート表示 |

### リトライ仕様

インポートエラー時は自動リトライなし。ユーザーが再度インポートを試行する必要がある。

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

リスト作成とエントリ追加は同一トランザクションで実行。

## パフォーマンス要件

- リスト作成は即座に完了
- インポート時は読み込みインジケータを表示

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

- リストデータはローカルに保存
- インポートリンクはBase64エンコード

## 備考

ReadingListsFunnel.sharedを通じてインポートイベントのログ記録が行われる。

---

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

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

### 推奨読解順序

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

インポートリストのデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ImportedReadingList | `Wikipedia/Code/CreateReadingListViewController.swift` | インポート用データ構造、name/description/list |
| 1-2 | ImportReadingListError | `Wikipedia/Code/CreateReadingListViewController.swift` | インポートエラー種別 |

**読解のコツ**: ImportedReadingListは共有リンクから復元されるデータ構造。listフィールドは言語コードをキーとしたページID配列のディクショナリ。

#### Step 2: ViewControllerを理解する

CreateReadingListViewControllerがリスト作成画面の中心。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CreateReadingListViewController.swift | `Wikipedia/Code/CreateReadingListViewController.swift` | リスト作成画面ViewController |

**主要処理フロー**:
1. **23-31行目**: IBOutlet定義（テキストフィールド、ボタン等）
2. **45-47行目**: isInImportingMode - インポートモード判定
3. **72-79行目**: 初期化 - articles, moveFromReadingList, encodedPageIds
4. **85-105行目**: viewDidLoad - UI設定、ラベルテキスト設定
5. **152-158行目**: createReadingListButtonPressed - 作成ボタン処理
6. **167-198行目**: setupForImportingReadingList - インポート設定
7. **277-301行目**: articlesFromEncodedPageIds - ページIDから記事取得

#### Step 3: インポート処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CreateReadingListViewController.swift (private extension) | `Wikipedia/Code/CreateReadingListViewController.swift` | インポート処理 |

**主要処理フロー**:
- **303-310行目**: decodedReadingListFromEncodedPageIds - Base64デコード
- **312-367行目**: pageURLsFromImportedReadingList - ページURL取得
- **369-401行目**: articleObjectsFromArticleURLs - 記事オブジェクト取得

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

```
CreateReadingListViewController
    │
    ├─ UITextFieldDelegate
    │      └─ 入力バリデーション
    │
    ├─ CreateReadingListDelegate
    │      └─ 作成完了通知
    │
    └─ インポート処理（isInImportingMode時）
           ├─ decodedReadingListFromEncodedPageIds
           ├─ pageURLsFromImportedReadingList
           │      └─ PageIDToURLFetcher
           └─ articleObjectsFromArticleURLs
                  └─ ArticleFetcher
```

### データフロー図

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

テキスト入力 ───▶ CreateReadingListViewController ───▶ デリゲート通知
                          │
                          ├─▶ バリデーション
                          │
                          └─▶ delegate.createReadingListViewController(...)
                                 └─▶ ReadingListsController.createReadingList()

[インポート]

共有リンク ───▶ Base64デコード ───▶ ページURL取得 ───▶ 記事フェッチ ───▶ リスト作成
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CreateReadingListViewController.swift | `Wikipedia/Code/` | ソース | リスト作成画面 |
| CreateReadingListViewController.xib | `Wikipedia/` | XIB | 画面レイアウト |
| ReadingListsController.swift | `Wikipedia/Code/` | ソース | リスト作成処理 |
| PageIDToURLFetcher | `WMF Framework/` | ソース | ページID→URL変換 |
| ArticleFetcher | `WMF Framework/` | ソース | 記事情報取得 |
| ReadingListsFunnel.swift | `Wikipedia/Code/` | ソース | イベントログ |
