# 機能設計書 71-プロジェクトスニペット

## 概要

本ドキュメントは、GitLabのプロジェクトスニペット機能について、その処理概要、入出力仕様、処理フロー、データベース操作仕様を定義する。

### 本機能の処理概要

プロジェクトスニペット機能は、プロジェクト内でコードスニペット（コード断片）を共有・管理するための機能である。

**業務上の目的・背景**：開発プロジェクトにおいて、チームメンバー間でコード断片やスクリプト、設定ファイルなどを共有する必要がある場合、個別のファイルとしてリポジトリに保存するほどではないが、アクセスしやすい場所に保管したいケースがある。プロジェクトスニペットは、このような軽量なコード共有のニーズに応え、プロジェクトのコンテキスト内でスニペットを管理・共有できるようにする。

**機能の利用シーン**：
- チーム内でよく使うスクリプトやコマンドを共有する場合
- 設定ファイルのテンプレートをプロジェクトメンバーに提供する場合
- コードレビュー時に参照用のコードサンプルを共有する場合
- プロジェクト固有のユーティリティコードを保管する場合

**主要な処理内容**：
1. スニペットの作成（タイトル、説明、コード内容、ファイル名、可視性レベルの設定）
2. スニペットの編集（既存スニペットの内容更新）
3. スニペットの削除
4. スニペット一覧の表示とフィルタリング
5. スニペットへのコメント付与（Noteable機能）
6. スニペットへのアワード絵文字付与

**関連システム・外部連携**：
- Gitリポジトリ（スニペットの内容はGitリポジトリとして管理される）
- Akismetスパム検知（スパムチェック機能）
- Markdownレンダリング

**権限による制御**：
- スニペットの作成: プロジェクトへのアクセス権限が必要（Developerロール以上推奨）
- スニペットの編集: スニペット作成者またはプロジェクトMaintainer以上
- スニペットの削除: スニペット作成者またはプロジェクトMaintainer以上
- スニペットの閲覧: スニペットの可視性レベルとプロジェクトへのアクセス権限に依存

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 137 | スニペット一覧 | 主画面 | プロジェクトスニペットの一覧表示 |
| 138 | スニペット詳細 | 結果表示画面 | スニペットの詳細表示 |
| 139 | スニペット新規作成 | 入力画面 | 新規スニペットの作成 |
| 140 | スニペット編集 | 入力画面 | スニペットの編集 |

## 機能種別

CRUD操作 / テキスト処理 / バージョン管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| title | String | Yes | スニペットのタイトル | 最大255文字 |
| description | String | No | スニペットの説明 | 最大1MB |
| file_name | String | No | ファイル名（シンタックスハイライト用） | 最大255文字 |
| content | String | Yes | スニペットの内容（コード） | 必須、サイズ制限あり（設定値による） |
| visibility_level | Integer | No | 可視性レベル（0:Private, 10:Internal, 20:Public） | 0, 10, 20のいずれか |
| scope | String | No | 一覧表示時のスコープフィルタ | all/personal |

### 入力データソース

- 画面入力（新規作成・編集フォーム）
- URLパラメータ（スコープ、ページ番号）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | スニペットID |
| title | String | タイトル |
| description | String | 説明 |
| content | String | スニペット内容 |
| file_name | String | ファイル名 |
| visibility_level | Integer | 可視性レベル |
| author | User | 作成者情報 |
| created_at | DateTime | 作成日時 |
| updated_at | DateTime | 更新日時 |
| web_url | String | スニペットのWebURL |

### 出力先

- 画面表示（HTML）
- JSON API レスポンス

## 処理フロー

### 処理シーケンス

```
1. 認証確認
   └─ ユーザーがログイン済みか確認
2. プロジェクトアクセス権限確認
   └─ プロジェクトのスニペット機能が有効か確認
3. スニペット操作権限確認
   └─ 作成/編集/削除の権限をチェック
4. バリデーション実行
   └─ 入力パラメータの検証
5. スパムチェック（作成/編集時）
   └─ Akismetによるスパム判定
6. スニペット保存
   └─ DBへのレコード保存
7. リポジトリ操作
   └─ Gitリポジトリの作成/コミット
8. レスポンス返却
   └─ 成功/失敗の結果を返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{認証済み?}
    B -->|No| C[ログイン画面へ]
    B -->|Yes| D{スニペット機能有効?}
    D -->|No| E[404エラー]
    D -->|Yes| F{操作権限あり?}
    F -->|No| G[403エラー]
    F -->|Yes| H[バリデーション]
    H -->|失敗| I[エラー表示]
    H -->|成功| J{スパムチェック}
    J -->|スパム| K[スパム警告]
    J -->|正常| L[DB保存]
    L --> M[リポジトリ操作]
    M --> N[成功レスポンス]
    N --> O[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-01 | 可視性レベル制限 | プロジェクトの可視性レベルより高い可視性は設定不可 | スニペット作成・編集時 |
| BR-71-02 | ファイル数上限 | 1つのスニペットには最大10ファイルまで | 複数ファイルスニペット作成時 |
| BR-71-03 | サイズ制限 | コンテンツサイズはシステム設定の上限値以内 | スニペット作成・編集時 |
| BR-71-04 | 作成者変更不可 | スニペットの作成者は変更不可 | 編集時 |

### 計算ロジック

なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| スニペット作成 | snippets | INSERT | 新規スニペットレコード作成 |
| スニペット作成 | snippet_repositories | INSERT | スニペット用リポジトリ情報作成 |
| スニペット作成 | snippet_statistics | INSERT | スニペット統計情報作成 |
| スニペット編集 | snippets | UPDATE | スニペット情報更新 |
| スニペット削除 | snippets | DELETE | スニペットレコード削除 |
| 一覧取得 | snippets | SELECT | スニペット一覧取得 |

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

#### snippets

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | title | ユーザー入力値 | 必須 |
| INSERT | description | ユーザー入力値 | 任意 |
| INSERT | content | ユーザー入力値 | 必須 |
| INSERT | file_name | ユーザー入力値 | 任意 |
| INSERT | author_id | current_user.id | 作成者 |
| INSERT | project_id | プロジェクトID | プロジェクトスニペットの場合 |
| INSERT | visibility_level | ユーザー入力値またはデフォルト | 可視性 |
| INSERT | created_at | 現在日時 | 自動設定 |
| INSERT | updated_at | 現在日時 | 自動設定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | 未ログイン状態でのアクセス | ログイン画面へリダイレクト |
| 403 | 権限エラー | 権限不足での操作試行 | エラーメッセージ表示 |
| 404 | NotFound | 存在しないスニペットへのアクセス | 404ページ表示 |
| 422 | バリデーションエラー | 入力値の検証失敗 | エラー内容を表示して再入力促進 |

### リトライ仕様

リポジトリ操作失敗時は、スニペットレコードを削除してロールバックする。

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

- スニペット作成時、DBレコード保存とリポジトリ作成は同一トランザクションで管理
- リポジトリ作成失敗時はDBレコードもロールバック

## パフォーマンス要件

- 一覧取得: ページネーション適用（デフォルト20件/ページ）
- 個別取得: 1秒以内のレスポンス

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

- 可視性レベルに基づくアクセス制御
- スパム検知（Akismet連携）
- XSS対策（コンテンツのサニタイズ）
- CSRF対策

## 備考

- スニペットのコンテンツはGitリポジトリとして管理され、バージョン管理が可能
- Markdownフォーマットでの説明文記述をサポート

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | snippet.rb | `app/models/snippet.rb` | Snippetモデルの属性、バリデーション、関連定義を確認 |
| 1-2 | project_snippet.rb | `app/models/project_snippet.rb` | プロジェクトスニペット固有の実装を確認 |

**読解のコツ**: Snippetモデルは多くのconcern（Noteable, Awardable, Mentionable等）をincludeしており、これらが各機能を提供している。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | snippets_controller.rb | `app/controllers/projects/snippets_controller.rb` | プロジェクトスニペット用コントローラーの構造を確認 |

**主要処理フロー**:
1. **9行目**: `check_snippets_available!` でスニペット機能の有効性確認
2. **11行目**: before_actionでsnippetの読み込み
3. **19-34行目**: `index`アクションでスニペット一覧を取得
4. **36-38行目**: `new`アクションで新規スニペット用オブジェクト作成

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create_service.rb | `app/services/snippets/create_service.rb` | スニペット作成のビジネスロジック |
| 3-2 | update_service.rb | `app/services/snippets/update_service.rb` | スニペット更新のビジネスロジック |
| 3-3 | base_service.rb | `app/services/snippets/base_service.rb` | 共通処理の確認 |

**主要処理フロー（create_service.rb）**:
- **14-42行目**: `execute`メソッドでスニペット作成のメインフロー
- **26-27行目**: スパムチェックの実行
- **29行目**: `save_and_commit`でDB保存とリポジトリコミット
- **78-104行目**: `save_and_commit`メソッドでトランザクション処理

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

```
Projects::SnippetsController
    │
    ├─ index
    │      └─ SnippetsFinder
    │             └─ Snippet (model)
    │
    ├─ new
    │      └─ project.snippets.build
    │
    └─ (SnippetsActions concern経由)
           ├─ create
           │      └─ Snippets::CreateService
           │             ├─ Snippet.save
           │             └─ snippet.create_repository
           │
           └─ update
                  └─ Snippets::UpdateService
                         ├─ Snippet.save
                         └─ snippet_repository.multi_files_action
```

### データフロー図

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

フォーム入力 ───▶ Controller ───▶ HTML/JSON
    │                │
    │                ▼
    │          CreateService
    │                │
    │                ├─▶ Snippetモデル ───▶ snippetsテーブル
    │                │
    │                └─▶ Repository ───▶ Gitリポジトリ
    │
    └── params[:snippet]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| snippets_controller.rb | `app/controllers/projects/snippets_controller.rb` | コントローラー | プロジェクトスニペットのルーティング処理 |
| snippets_actions.rb | `app/controllers/concerns/snippets_actions.rb` | コンサーン | スニペット共通アクション |
| snippet.rb | `app/models/snippet.rb` | モデル | スニペットのデータ構造定義 |
| project_snippet.rb | `app/models/project_snippet.rb` | モデル | プロジェクトスニペット固有実装 |
| create_service.rb | `app/services/snippets/create_service.rb` | サービス | スニペット作成処理 |
| update_service.rb | `app/services/snippets/update_service.rb` | サービス | スニペット更新処理 |
| destroy_service.rb | `app/services/snippets/destroy_service.rb` | サービス | スニペット削除処理 |
| snippets_finder.rb | `app/finders/snippets_finder.rb` | ファインダー | スニペット検索・フィルタリング |
