# 機能設計書 27-説明文編集

## 概要

本ドキュメントは、Wikipedia iOSアプリケーションにおける説明文編集機能の設計を記載する。この機能により、ユーザーは記事の短い説明文（Short Description）を追加・編集できる。

### 本機能の処理概要

説明文編集機能は、記事のWikidataまたはWikipedia本文内の{{Short description}}テンプレートを通じて、記事を説明する短いテキストを編集する。

**業務上の目的・背景**：説明文は検索結果やリンクプレビューで記事の概要を示すために使用される。適切な説明文は読者の情報アクセシビリティを向上させる。

**機能の利用シーン**：記事ページから「説明文を追加/編集」をタップした際に使用する。説明文が存在しない場合は新規追加、存在する場合は編集となる。

**主要な処理内容**：
1. 現在の説明文の取得と表示
2. テキスト入力による説明文の編集
3. 文字数警告（90文字推奨上限）
4. 大文字開始警告（非英語Wikipedia）
5. Wikidata APIまたはWikitextへの説明文公開
6. 一時アカウント対応（ログイン状態に応じた通知）
7. AbuseFilter/ブロックエラー対応

**関連システム・外部連携**：Wikidata API、Wikipedia API、WikitextFetcher、WikiTextSectionUploader

**権限による制御**：編集権限を持つユーザーのみ使用可能（ブロック時はエラー表示）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 記事表示画面 | 遷移元 | 説明文編集を開始 |
| - | 説明文編集画面 | メイン画面 | 説明文入力と公開 |
| - | Wikidataヘルプ画面 | 参照 | Learn Moreから遷移 |
| - | ライセンス確認画面 | 参照 | ライセンスリンクタップ |

## 機能種別

テキスト入力、API連携、コンテンツ編集

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| dataStore | MWKDataStore | Yes | データストア | - |
| theme | Theme | Yes | テーマ設定 | - |
| articleDescriptionController | ArticleDescriptionControlling | Yes | 説明文コントローラー | - |
| isAddingNewTitleDescription | Bool | Yes | 新規追加かどうか | descriptionSourceから算出 |

### 入力データソース

- ArticleViewControllerからのWMFArticle
- 既存の説明文（Wikidataまたはwikitext）
- ユーザー入力テキスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ArticleDescriptionPublishResult | struct | 新リビジョンIDと新説明文 |
| didPublishNotification | Notification | 公開完了通知 |

### 出力先

- Wikidata API（WikidataDescriptionController使用時）
- Wikipedia API（ShortDescriptionController使用時）
- DescriptionEditViewControllerDelegate.descriptionEditViewControllerEditSucceeded

## 処理フロー

### 処理シーケンス

```
1. 初期化
   ├─ viewDidLoadでUI設定
   ├─ 現在の説明文取得（currentDescription）
   └─ 一時アカウント状態確認（checkWikiStatus）

2. UI設定
   ├─ プレースホルダー設定
   ├─ 警告ラベル初期化
   ├─ ナビゲーションバー設定
   └─ テキストビュー初期設定

3. ユーザー入力
   ├─ テキスト入力
   ├─ 文字数警告更新
   └─ 大文字警告更新（非EN）

4. 公開処理
   ├─ 説明文正規化
   ├─ publishDescription呼び出し
   ├─ 成功: デリゲート通知・通知発行
   └─ 失敗: エラーパネル表示
```

### フローチャート

```mermaid
flowchart TD
    A[説明文編集開始] --> B[現在の説明文取得]
    B --> C{説明文あり?}
    C -->|Yes| D[editType = change]
    C -->|No| E[editType = add]
    D --> F[UI初期化]
    E --> F
    F --> G{ブロック済み?}
    G -->|Yes| H[ブロックパネル表示]
    G -->|No| I[テキスト入力待機]
    I --> J{公開ボタン}
    J --> K[説明文正規化]
    K --> L{Wikidata/Wikitext?}
    L -->|Wikidata| M[WikidataFetcher.publish]
    L -->|Wikitext| N[ShortDescriptionController.publish]
    M --> O{成功?}
    N --> O
    O -->|Yes| P[成功通知・dismiss]
    O -->|No| Q{エラー種別}
    Q -->|Blocked| H
    Q -->|AbuseFilter| R[AbuseFilterパネル]
    Q -->|Other| S[エラーアラート]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 推奨文字数 | 説明文は90文字以内を推奨 | 常時 |
| BR-002 | 大文字警告 | 固有名詞以外は小文字開始を推奨 | 非ENウィキ |
| BR-003 | 空白正規化 | 連続空白を単一空白に、前後空白を除去 | 公開時 |
| BR-004 | 編集タグ | add/changeに応じたタグ付与 | 公開時 |
| BR-005 | 一時アカウント通知 | 一時アカウント作成時は通知表示 | 非ログイン編集時 |
| BR-006 | ブロック検出 | ブロック済みユーザーは編集不可 | 初期化時・公開時 |

### 計算ロジック

| 計算項目 | 計算式・ロジック |
|---------|----------------|
| 文字数超過判定 | description.count > 90 |
| 大文字開始判定 | firstCharacter.isLetter && firstCharacter.isUppercase |
| 空白正規化 | `\\s+` を単一スペースに置換後、前後trim |

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

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

本機能はローカルDBを直接操作しない。API経由でWikidata/Wikipediaに反映。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 処理内容 |
|-----------|---------|---------|
| blocked | ユーザーがブロック済み | wmf_showBlockedPanel表示、編集無効化 |
| abuseFilterDisallow | AbuseFilterにより拒否 | AbuseFilterDisallowパネル表示 |
| abuseFilterWarning | AbuseFilter警告 | 警告パネル表示（公開続行可能） |
| unexpectedResponse | API応答エラー | エラーアラート表示 |
| missingSelf | メモリ解放エラー | 処理中断 |

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

該当なし（API呼び出しのみ）

## パフォーマンス要件

特になし

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

- CC0ライセンスへの同意表示
- 利用規約リンクの提供
- ブロック状態の検証

## 備考

- 説明文のソースは2種類: Wikidata（WikidataDescriptionController）とWikitext（ShortDescriptionController）
- 英語Wikipediaでは{{Short description}}テンプレートを使用
- 非英語WikipediaではWikidataを使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ArticleDescriptionControlling.swift | `Wikipedia/Code/Controllers/ArticleDescriptionControlling.swift` | ArticleDescriptionControllingプロトコル（L21-29） |
| 1-2 | ArticleDescriptionControlling.swift | `Wikipedia/Code/Controllers/ArticleDescriptionControlling.swift` | ArticleDescriptionWarningTypes（L4-9） |
| 1-3 | ArticleDescriptionControlling.swift | `Wikipedia/Code/Controllers/ArticleDescriptionControlling.swift` | ArticleDescriptionPublishResult（L11-14） |

**読解のコツ**: プロトコルの各メソッドがどのような責務を持つか確認する。descriptionMaxLength=90がデフォルト値。

#### Step 2: View Controller初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | DescriptionEditViewController.swift | `Wikipedia/Code/DescriptionEditViewController.swift` | with(dataStore:theme:articleDescriptionController:)（L46-53） |
| 2-2 | DescriptionEditViewController.swift | `Wikipedia/Code/DescriptionEditViewController.swift` | viewDidLoad（L55-113） |

**主要処理フロー**:
- **L58-59**: 警告ラベルテキスト設定
- **L61**: 公開ボタンタイトル設定
- **L72-94**: currentDescription取得とeditType設定
- **L101-112**: 一時アカウント状態チェック

#### Step 3: テキスト入力と警告を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DescriptionEditViewController.swift | `Wikipedia/Code/DescriptionEditViewController.swift` | UITextViewDelegate（L214-233、L518-523） |
| 3-2 | DescriptionEditViewController.swift | `Wikipedia/Code/DescriptionEditViewController.swift` | updateWarningLabels（L502-511） |
| 3-3 | ArticleDescriptionControlling.swift | `Wikipedia/Code/Controllers/ArticleDescriptionControlling.swift` | warningTypesForDescription（L35-47） |

**主要処理フロー**:
- **L506**: 警告タイプ取得（length/casing）
- **L508-510**: 警告ラベルの表示/非表示切替

#### Step 4: 公開処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | DescriptionEditViewController.swift | `Wikipedia/Code/DescriptionEditViewController.swift` | save()（L335-459） |
| 4-2 | WikidataDescriptionController.swift | `Wikipedia/Code/Controllers/WikidataDescriptionController.swift` | publishDescription（L37-48） |
| 4-3 | ShortDescriptionController.swift | `Wikipedia/Code/Controllers/ShortDescriptionController.swift` | publishDescription（L57-80） |

**主要処理フロー**:
- **L340-347**: テキスト正規化と空チェック
- **L354**: articleDescriptionController.publishDescription呼び出し
- **L363-416**: 成功時処理（デリゲート通知、一時アカウント対応）
- **L417-456**: 失敗時エラーハンドリング

#### Step 5: エラーパネル表示を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | DescriptionEditViewController.swift | `Wikipedia/Code/DescriptionEditViewController.swift` | presentBlockedPanel（L461-469） |
| 5-2 | DescriptionEditViewController.swift | `Wikipedia/Code/DescriptionEditViewController.swift` | presentAbuseFilterDisallowedPanel（L471-479） |
| 5-3 | DescriptionEditViewController.swift | `Wikipedia/Code/DescriptionEditViewController.swift` | presentAbuseFilterWarningPanel（L481-495） |

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

```
ArticleViewController
    │
    └─ showDescriptionEditor()
           │
           └─ DescriptionEditViewController.with(...)
                  │
                  ├─ viewDidLoad()
                  │      ├─ currentDescription() → ArticleDescriptionControlling
                  │      ├─ configureNavigationBar()
                  │      ├─ updateWarningLabels()
                  │      └─ checkWikiStatus() → WMFTempAccountDataController
                  │
                  ├─ textViewDidChange()
                  │      ├─ enableProgressiveButton()
                  │      └─ updateWarningLabels()
                  │
                  └─ save()
                         ├─ normalizedWhitespaceText()
                         ├─ publishDescription() → ArticleDescriptionControlling
                         │      │
                         │      ├─ [WikidataDescriptionController]
                         │      │      └─ WikidataFetcher.publish()
                         │      │
                         │      └─ [ShortDescriptionController]
                         │             ├─ wikitextFetcher.fetchSection()
                         │             └─ sectionUploader.uploadWikiText()
                         │
                         ├─ delegate?.descriptionEditViewControllerEditSucceeded()
                         ├─ NotificationCenter.post(didPublishNotification)
                         └─ [Error] presentBlockedPanel / presentAbuseFilterPanel
```

### データフロー図

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

WMFArticle           ───▶ DescriptionEditViewController.with()
                                │
                                ▼
currentDescription() ◀── ArticleDescriptionControlling ───▶ descriptionTextView.text
                                │
                                ▼
テキスト入力          ───▶ textViewDidChange()
                                │
                                ├─▶ updateWarningLabels() ───▶ 警告ラベル表示
                                │
                                ▼
公開ボタンタップ       ───▶ save()
                                │
                                ├─▶ normalizedWhitespaceText()
                                │
                                ▼
                         publishDescription()
                                │
                    ┌───────────┴───────────┐
                    ▼                       ▼
          WikidataFetcher           WikitextFetcher
                    │                       │
                    └───────────┬───────────┘
                                ▼
                    ArticleDescriptionPublishResult ───▶ デリゲート通知
                                │
                                ▼
                    didPublishNotification ───▶ NotificationCenter
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DescriptionEditViewController.swift | `Wikipedia/Code/DescriptionEditViewController.swift` | ソース | 説明文編集メインVC |
| ArticleDescriptionControlling.swift | `Wikipedia/Code/Controllers/ArticleDescriptionControlling.swift` | ソース | 説明文コントローラープロトコル |
| WikidataDescriptionController.swift | `Wikipedia/Code/Controllers/WikidataDescriptionController.swift` | ソース | Wikidata説明文コントローラー |
| ShortDescriptionController.swift | `Wikipedia/Code/Controllers/ShortDescriptionController.swift` | ソース | Wikipedia短い説明コントローラー |
| ArticleViewController+Editing.swift | `Wikipedia/Code/ArticleViewController+Editing.swift` | ソース | 記事画面からの遷移処理 |
| WikidataFetcher.swift | `Wikipedia/Code/WikidataFetcher.swift` | ソース | Wikidata API通信 |
| WikitextFetcher.swift | `Wikipedia/Code/WikitextFetcher.swift` | ソース | Wikitext取得 |
| WikiTextSectionUploader.swift | `Wikipedia/Code/WikiTextSectionUploader.swift` | ソース | Wikitextアップロード |
