# 画面設計書 279-スニペット詳細

## 概要

本ドキュメントは、GitLabの「スニペット詳細」画面の設計書です。個人スニペットの内容を表示し、コメントやリアクションを行う画面の仕様を記載しています。

### 本画面の処理概要

**業務上の目的・背景**：スニペットは、コードの断片やメモを保存・共有するための機能です。プロジェクトに属さない個人スニペットを作成することで、よく使うコード片、設定ファイル、テンプレートなどを保存し、必要なときに参照・共有できます。

**画面へのアクセス方法**：ダッシュボードのスニペット一覧、探索のスニペット探索、またはスニペットの直接URLからアクセスします。

**主要な操作・処理内容**：
1. スニペットタイトル・説明の表示
2. スニペットファイル内容の表示（シンタックスハイライト対応）
3. 絵文字リアクション（Award Emoji）の追加・削除
4. コメントの表示・追加
5. スニペットの編集画面への遷移
6. 不正利用報告の送信

**画面遷移**：スニペット一覧から遷移。編集ボタンでスニペット編集画面（280）へ遷移します。作成者以外がアクセスした場合は探索レイアウトで表示されます。

**権限による表示制御**：スニペットの公開設定（public/internal/private）に応じてアクセス可否が決まります。自分のスニペットまたは公開設定により閲覧可能なスニペットのみ表示されます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 72 | 個人スニペット | 主機能 | 個人スニペット詳細表示 |

## 画面種別

詳細

## URL/ルーティング

```
GET /-/snippets/:id
```

## 入出力項目

| 項目名 | 入出力 | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| id | 入力（URL） | Integer | 必須 | スニペットID |

## 表示項目

### スニペット情報

| 項目名 | 説明 |
|--------|------|
| タイトル | スニペットのタイトル |
| 説明 | スニペットの説明（Markdown対応） |
| ファイル内容 | スニペットの内容（Monaco Editor、シンタックスハイライト） |
| 作成者 | スニペット作成者のユーザー情報 |
| 作成日時 | スニペットの作成日時 |
| 公開設定 | public/internal/private |
| リファレンス | $123 形式のスニペット参照 |

### Award Emoji

| 項目名 | 説明 |
|--------|------|
| 絵文字リアクション一覧 | 各絵文字とリアクション数 |
| 絵文字追加ボタン | 絵文字リアクション追加用ボタン |

### コメント

| 項目名 | 説明 |
|--------|------|
| コメント一覧 | スニペットへのコメント |
| コメント入力フォーム | 新規コメント入力用 |

## イベント仕様

### 1-絵文字リアクション追加

**トリガー**: 絵文字ボタン押下

**処理フロー**:
1. 選択された絵文字をAPIに送信
2. Award Emojiを作成
3. 絵文字リアクション一覧を更新

### 2-絵文字リアクション削除

**トリガー**: 既にリアクションした絵文字を再度押下

**処理フロー**:
1. 該当絵文字リアクションの削除リクエスト
2. Award Emojiを削除
3. 絵文字リアクション一覧を更新

### 3-コメント追加

**トリガー**: コメントフォーム送信

**処理フロー**:
1. コメント内容をAPIに送信
2. Noteを作成
3. コメント一覧に追加表示

### 4-不正利用報告

**トリガー**: 報告ボタン押下

**処理フロー**:
1. 不正利用報告画面へ遷移
2. 報告内容を入力・送信

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 詳細表示 | snippets | SELECT | スニペット情報取得 |
| 絵文字追加 | award_emoji | INSERT | リアクション追加 |
| 絵文字削除 | award_emoji | DELETE | リアクション削除 |
| コメント追加 | notes | INSERT | コメント追加 |

### テーブル別更新項目詳細

#### award_emoji（リアクション追加時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | 絵文字名 | |
| INSERT | user_id | 現在ユーザーID | |
| INSERT | awardable_type | 'Snippet' | |
| INSERT | awardable_id | スニペットID | |
| INSERT | created_at | 現在日時 | |

#### notes（コメント追加時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | note | コメント内容 | |
| INSERT | author_id | 現在ユーザーID | |
| INSERT | noteable_type | 'Snippet' | |
| INSERT | noteable_id | スニペットID | |
| INSERT | created_at | 現在日時 | |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| - | - | - | 特定のメッセージなし |

## 例外処理

| 例外 | 処理内容 |
|------|---------|
| スニペット読み取り権限なし | 404エラーページを表示 |
| スニペットID不正 | 404エラーページを表示 |
| 作成者がBANされている場合 | hidden_due_to_author_ban?で判定 |

## 備考

- GraphQL APIを使用してスニペット情報を取得（`add_page_startup_graphql_call`）
- Monaco Editorでファイル内容を表示
- 作成者と現在ユーザーが異なる場合は`explore`レイアウトを使用
- Awardable、Noteable、Participableモジュールを使用
- スパム判定機能（Spammable）を実装
- secret_tokenによるシークレットスニペット機能（暗号化保存）

---

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

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

### 推奨読解順序

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

スニペットモデルとその関連を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | snippet.rb | `app/models/snippet.rb` | スニペットモデル、バリデーション、スコープ |

**読解のコツ**:
- 3-22行目で包含されるモジュール（Awardable、Noteable等）を確認
- 49-56行目でアソシエーション（notes、user_mentions等）を確認
- 59-66行目でバリデーションを確認
- 74-84行目でスコープ定義を確認

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

コントローラの処理フローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | snippets_controller.rb | `app/controllers/snippets_controller.rb` | コントローラ（showアクションはSnippetsActionsで定義） |
| 2-2 | snippets_actions.rb | `app/controllers/concerns/snippets_actions.rb` | 共通アクション定義 |

**主要処理フロー**:
1. **9行目**: before_actionでスニペット取得
2. **12-13行目**: 権限チェック
3. **36-42行目**: `determine_layout`で作成者に応じてレイアウト切り替え

#### Step 3: ビューを理解する

画面構成を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.haml | `app/views/snippets/show.html.haml` | 詳細画面テンプレート |

**主要処理フロー**:
- **1-6行目**: GraphQL呼び出しの設定（スニペット情報、blob内容、権限）
- **7-11行目**: パンくずリスト設定（作成者かどうかで分岐）
- **13行目**: ページタイトル設定
- **17行目**: Vue.jsコンポーネントのマウントポイント
- **19-20行目**: Award Emoji表示
- **22行目**: コメント表示・フォーム

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

```
SnippetsController#show
    │
    ├─ snippet (before_action)
    │      └─ Snippet.find(params[:id])
    │
    ├─ authorize_read_snippet! (before_action)
    │      └─ can?(:read_snippet, @snippet)
    │
    ├─ determine_layout
    │      └─ @snippet.author != current_user ? 'explore' : 'snippets'
    │
    └─ render show.html.haml
           ├─ add_page_startup_graphql_call（スニペット情報）
           ├─ #js-snippet-view（Vue.jsコンポーネント）
           ├─ award_emoji/awards_block（絵文字リアクション）
           └─ shared/notes/notes_with_form（コメント）
```

### データフロー図

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

URLパラメータ(id) ───▶ SnippetsController#show
                          │
                          ├─▶ @snippet = Snippet.find(id)
                          │
                          ├─▶ authorize_read_snippet!
                          │
                          ├─▶ GraphQL calls（startup）
                          │       ├─▶ snippet/snippet
                          │       ├─▶ snippet/snippet_blob_content
                          │       └─▶ snippet/*_permissions
                          │
                          └─▶ render show.html.haml ───▶ 画面表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| snippet.rb | `app/models/snippet.rb` | モデル | スニペットデータモデル |
| snippets_controller.rb | `app/controllers/snippets_controller.rb` | コントローラ | スニペット表示処理 |
| snippets_actions.rb | `app/controllers/concerns/snippets_actions.rb` | Concern | 共通アクション |
| show.html.haml | `app/views/snippets/show.html.haml` | ビュー | 詳細画面テンプレート |
| _awards_block.html.haml | `app/views/award_emoji/_awards_block.html.haml` | ビュー | 絵文字リアクションパーシャル |
| _notes_with_form.html.haml | `app/views/shared/notes/_notes_with_form.html.haml` | ビュー | コメントパーシャル |
