# 機能設計書 70-Wiki履歴

## 概要

本ドキュメントは、GitLabにおけるWiki履歴機能の設計仕様を記載する。Wikiページの変更履歴（コミット履歴）を閲覧し、バージョン間の差分を確認する機能である。

### 本機能の処理概要

Wiki履歴機能は、Gitリポジトリとして管理されるWikiコンテンツのコミット履歴を表示し、特定バージョンの閲覧やバージョン間の差分比較を可能にする。各変更はGitコミットとして記録され、作者情報、コミットメッセージ、変更日時などの情報を参照できる。

**業務上の目的・背景**：ドキュメントの変更履歴を追跡することは、品質管理やコンプライアンス上重要である。本機能により、誰がいつどのような変更を行ったかを確認でき、必要に応じて過去のバージョンを参照・復元できる。

**機能の利用シーン**：
- ページの変更履歴一覧の確認
- 特定バージョンのページ内容閲覧
- 2つのバージョン間の差分比較
- 変更作者・日時の確認
- コミットメッセージの確認
- 過去バージョンへのリンク共有

**主要な処理内容**：
1. コミット履歴の取得（WikiPage#versions）
2. コミット件数の取得（WikiPage#count_versions）
3. 特定バージョンのページ取得（Wiki#find_page with version）
4. 差分の計算・表示（WikiPage#diffs）
5. 履歴のページネーション

**関連システム・外部連携**：
- Gitaly（コミット履歴取得、差分計算）
- Gitリポジトリ（Wikiストレージ）

**権限による制御**：
- `read_wiki`権限：Wiki閲覧（履歴閲覧含む）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | Wiki履歴一覧 | 主機能 | コミット履歴表示 |
| - | Wiki差分表示 | 主機能 | バージョン差分表示 |
| - | Wikiページ表示（バージョン指定） | 副機能 | 過去バージョン閲覧 |

## 機能種別

履歴表示 / バージョン管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | String | Yes | ページスラッグ（URLパス） | - |
| version_id | String | No | 表示するバージョン（コミットSHA） | - |
| page | Integer | No | ページ番号（ページネーション） | デフォルト: 1 |
| per_page | Integer | No | 1ページあたりの件数 | デフォルト: Kaminari設定 |

### 入力データソース

- URLパラメータ
- Wikiリポジトリ（Git履歴）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| commits | Array | コミット一覧（CommitCollection） |
| commits_count | Integer | 総コミット数 |
| sha | String | コミットSHA |
| message | String | コミットメッセージ |
| author_name | String | 作者名 |
| author_email | String | 作者メールアドレス |
| committed_date | DateTime | コミット日時 |
| diffs | DiffCollection | 差分情報（差分表示時） |

### 出力先

- Web UI（履歴一覧、差分表示）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信（history/diff）
   └─ 権限チェック（authorize_read_wiki!）
   └─ ページ取得

2. 履歴取得
   └─ WikiPage#versions
   │      └─ repository.commits
   │             └─ Gitaly ListCommits RPC
   └─ WikiPage#count_versions
          └─ repository.count_commits

3. ページネーション
   └─ Kaminari.paginate_array

4. レンダリング
   └─ 【履歴】shared/wikis/history
   └─ 【差分】shared/wikis/diff
          └─ WikiPage#diffs
                 └─ Gitlab::Diff::FileCollection::WikiPage
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B{read_wiki権限?}
    B -->|No| C[403 Forbidden]
    B -->|Yes| D{ページ存在?}
    D -->|No| E[リダイレクト（404）]
    D -->|Yes| F{アクション種別}
    F -->|history| G[WikiPage#versions]
    F -->|diff| H[WikiPage#diffs]
    G --> I[count_versions取得]
    I --> J[ページネーション]
    J --> K[履歴一覧表示]
    H --> L[Diff::FileCollection::WikiPage]
    L --> M[差分表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルトページサイズ | Kaminari.config.default_per_page | 履歴一覧 |
| BR-02 | 履歴取得パス | ページのpathでコミット履歴をフィルタ | 履歴取得時 |
| BR-03 | 差分展開 | 差分は常に展開表示（expanded: true） | 差分表示時 |
| BR-04 | パスフィルタ | 差分計算時は対象ページのpathのみ | 差分計算時 |
| BR-05 | 過去バージョン判定 | version.sha != last_commit_sha で判定 | ページ表示時 |
| BR-06 | 差分コメント無効 | diff_notes_disabled: true | 差分表示時 |

### 計算ロジック

- オフセット計算: `(page - 1) * per_page`
- 過去バージョン判定: `page.historical? && last_commit_sha != version.sha`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 履歴表示 | - | - | DBアクセスなし（Git操作のみ） |

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

履歴機能はGitリポジトリからの読み取りのみで、データベース操作は発生しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------
| 403 | Forbidden | read_wiki権限なし | 権限確認 |
| 404 | Not Found | ページが存在しない | Wikiトップへリダイレクト |
| - | Git Timeout | Gitaly操作タイムアウト | git_error画面表示 |

### リトライ仕様

Gitalyタイムアウト時はユーザーにエラー画面を表示し、手動でリトライを促す。

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

- 履歴表示はDBトランザクションを使用しない
- Git操作のみで完結

## パフォーマンス要件

- コミット履歴取得は件数制限（per_page）とオフセット（offset）で制御
- 差分計算は対象ファイルパスで絞り込み

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

- read_wiki権限による閲覧制御
- 作者情報はGitコミットから取得（ユーザーが存在しない場合はメールアドレス表示）

## 備考

- 本機能はプロジェクト・グループの両方で利用可能
- feature_category: `wiki`
- 差分表示はリポジトリの差分機能を流用

---

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

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

### 推奨読解順序

#### Step 1: コントローラーアクションを理解する

履歴・差分表示のアクションを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | wiki_actions.rb | `app/controllers/concerns/wiki_actions.rb` | Wiki共通アクション |

**読解のコツ**:
- **13行目**: RESCUE_GIT_TIMEOUTS_IN - historyとdiffがタイムアウト対象
- **260-274行目**: history - 履歴表示アクション
- **262行目**: count_versions - コミット総数取得
- **263-265行目**: page.versions - コミット一覧取得（ページネーション）
- **277-287行目**: diff - 差分表示アクション
- **281行目**: apply_diff_view_cookie! - 差分表示形式設定
- **283行目**: page.diffs - 差分取得
- **284行目**: diff_notes_disabled = true - コメント無効化

#### Step 2: WikiPageモデルを理解する

コミット履歴・差分の取得メソッドを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | wiki_page.rb | `app/models/wiki_page.rb` | WikiPageモデル |

**主要処理フロー**:
- **199-203行目**: version - 現在バージョン取得
- **216-228行目**: versions - コミット履歴取得（ページネーション対応）
- **230-234行目**: count_versions - コミット総数取得
- **236-238行目**: last_version - 最新コミット取得
- **250-254行目**: historical? - 過去バージョン判定
- **256-260行目**: latest? - 最新バージョン判定
- **394-396行目**: diffs - 差分コレクション取得

#### Step 3: 差分計算を理解する

差分ファイルコレクションの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | wiki_page.rb (diff) | `lib/gitlab/diff/file_collection/wiki_page.rb` | 差分コレクション |

**主要処理フロー**:
- **7-19行目**: initialize - 差分コレクション初期化
- **8行目**: page.wiki.commit - コミット取得
- **9-12行目**: diff_options - expanded: true, paths: [page.path]
- **14-19行目**: super呼び出し（Base継承）

#### Step 4: ヘルパーを理解する

履歴表示のヘルパーを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | wiki_page_version_helper.rb | `app/helpers/wiki_page_version_helper.rb` | バージョンヘルパー |

**主要処理フロー**:
- **6-9行目**: wiki_page_version_author_url - 作者URLの生成
  - ユーザー存在時: ユーザープロフィールURL
  - ユーザー不在時: mailto:リンク

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

```
HTTP Request (history/diff)
    │
    ├─ WikiActions#history
    │      └─ page (WikiPage取得)
    │      └─ page.count_versions
    │             └─ repository.count_commits
    │      └─ page.versions(page: N)
    │             └─ repository.commits
    │                    └─ Gitaly ListCommits RPC
    │      └─ Kaminari.paginate_array
    │
    └─ WikiActions#diff
           └─ page (WikiPage取得)
           └─ page.diffs(diff_options)
                  └─ Gitlab::Diff::FileCollection::WikiPage
                         └─ commit.diff_refs
                         └─ Gitaly CommitDiff RPC
```

### データフロー図

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

URL Parameters ────▶ WikiActions#history ──────────▶ Commits List
(id, page)                 │                              (shared/wikis/history)
                           │
                           ▼
                    WikiPage#versions
                           │
                           ▼
                    repository.commits
                    (Gitaly RPC)
                           │
                           ▼
                    CommitCollection
                    (sha, message, author, date)

---

URL Parameters ────▶ WikiActions#diff ─────────────▶ Diff View
(id, version_id)           │                              (shared/wikis/diff)
                           │
                           ▼
                    WikiPage#diffs
                           │
                           ▼
                    Gitlab::Diff::FileCollection::WikiPage
                           │
                           ▼
                    DiffCollection
                    (additions, deletions, changes)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| wiki_actions.rb | `app/controllers/concerns/wiki_actions.rb` | Concern | Wiki共通アクション |
| wiki_page.rb | `app/models/wiki_page.rb` | モデル | WikiPageモデル |
| wiki_page.rb (diff) | `lib/gitlab/diff/file_collection/wiki_page.rb` | ライブラリ | 差分コレクション |
| wiki_page_version_helper.rb | `app/helpers/wiki_page_version_helper.rb` | ヘルパー | バージョンヘルパー |
| wiki.rb | `app/models/wiki.rb` | モデル | Wikiモデル |
| diff_helper.rb | `app/helpers/diff_helper.rb` | ヘルパー | 差分表示ヘルパー |
