# 機能設計書 76-参加コード管理

## 概要

本ドキュメントは、Fizzyアプリケーションにおけるアカウントへの参加コード（招待リンク）管理機能の設計を記述する。

### 本機能の処理概要

アカウントへのユーザー招待に使用する参加コードを表示・管理する機能である。参加コードはランダムに生成される12文字のコード（4文字x3、ハイフン区切り）で、このコードを含むURLを共有することで新しいユーザーをアカウントに招待できる。管理者は使用回数制限の設定やコードのリセット（再生成）が可能。

**業務上の目的・背景**：チームへの新メンバー招待を簡単かつ安全に行う必要がある。メールアドレスを事前に収集せず、リンクを共有するだけでチームに参加できる仕組みにより、招待プロセスを簡素化している。使用回数制限により無制限の参加を防ぎ、コードのリセットにより古いリンクを無効化できる。

**機能の利用シーン**：
- 新しいチームメンバーを招待したい場合
- 招待リンクをSlackやメールで共有したい場合
- QRコードを使用して物理的な場所で招待したい場合
- 使用回数を制限してセキュリティを高めたい場合
- 古いリンクを無効化して新しいコードを発行したい場合

**主要な処理内容**：
1. 参加コード表示画面（show）：現在のコードと招待URL、QRコード、使用状況を表示
2. 使用制限編集画面（edit）：使用回数上限を変更
3. コードリセット（destroy）：新しいコードを生成し、使用回数をリセット

**関連システム・外部連携**：QRコード生成機能（No.88）との連携

**権限による制御**：
- 全ユーザー：参加コードの閲覧、URLのコピー、QRコードの表示が可能
- 管理者（admin）のみ：使用回数制限の変更、コードのリセットが可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 57 | 参加コード表示画面 | 主画面 | 招待リンク・QRコードを表示 |
| 58 | 参加コード編集画面 | 編集画面 | 参加コードの利用制限を編集 |

## 機能種別

データ参照・更新（設定管理）

## 入力仕様

### 入力パラメータ

#### show（表示）
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | URLパラメータなし | - |

#### update（制限変更）
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| account_join_code[usage_limit] | Integer | Yes | 使用回数上限 | 0以上10,000,000,000以下 |

#### destroy（リセット）
| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | DELETEリクエストのみ | - |

### 入力データソース

- セッション：Current.account（現在のアカウント）
- 画面入力：使用回数上限（edit/updateアクション）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @join_code | Account::JoinCode | 参加コード情報 |
| 招待URL | String | 参加用の完全なURL |
| QRコード | Image | 招待URLのQRコード |

### 出力先

- 画面表示：show.html.erb、edit.html.erb

## 処理フロー

### 処理シーケンス（show）

```
1. 参加コード表示画面にアクセス
   └─ showアクションが実行

2. 参加コード取得
   └─ @join_code = Current.account.join_code

3. 画面レンダリング
   └─ 招待URL表示
   └─ コピーボタン（copy-to-clipboard）
   └─ QRコードダイアログ
   └─ 使用状況表示（x/y回使用）
   └─ 管理者のみ：リセットボタン、制限変更リンク
```

### 処理シーケンス（destroy - リセット）

```
1. リセットボタンをクリック
   └─ 確認ダイアログで確認

2. destroyアクション実行
   └─ ensure_adminで権限確認

3. コードリセット
   └─ @join_code.reset
   └─ 新しいコードを生成
   └─ usage_countを0にリセット

4. リダイレクト
   └─ 参加コード表示画面にリダイレクト
```

### フローチャート

```mermaid
flowchart TD
    A[開始: 参加コード画面アクセス] --> B[参加コード取得]
    B --> C[show.html.erb表示]
    C --> D{アクション選択}
    D -->|URLコピー| E[クリップボードにコピー]
    D -->|QRコード表示| F[ダイアログでQRコード表示]
    D -->|リセット| G{管理者?}
    D -->|制限変更| H{管理者?}
    G -->|No| I[操作不可]
    G -->|Yes| J[確認ダイアログ]
    J --> K[@join_code.reset]
    K --> L[新コード生成・カウントリセット]
    L --> M[show画面にリダイレクト]
    H -->|No| I
    H -->|Yes| N[edit.html.erb表示]
    N --> O[usage_limit入力]
    O --> P[@join_code.update]
    P --> Q{バリデーション成功?}
    Q -->|Yes| M
    Q -->|No| R[エラー表示]
    R --> N
    E --> S[終了]
    F --> S
    I --> S
    M --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-76-01 | コード形式 | 12文字のBase58形式、4文字ごとにハイフン区切り（例: XXXX-YYYY-ZZZZ） | コード生成時 |
| BR-76-02 | 使用制限 | 使用回数が上限に達するとコードは無効（使用不可）になる | redeem時 |
| BR-76-03 | 上限制限 | usage_limitは0以上10,000,000,000以下 | 更新時 |
| BR-76-04 | リセット動作 | リセットすると新しいコードが生成され、使用回数が0に戻る | destroy時 |
| BR-76-05 | 管理者権限 | 使用制限の変更とリセットは管理者のみ | update/destroy時 |
| BR-76-06 | デフォルト制限 | 新規作成時のデフォルト使用上限は10回 | アカウント作成時 |

### 計算ロジック

- 残り使用可能回数 = usage_limit - usage_count
- active? = usage_count < usage_limit

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 表示 | account_join_codes | SELECT | 参加コード情報取得 |
| 制限変更 | account_join_codes | UPDATE | usage_limitを更新 |
| リセット | account_join_codes | UPDATE | code再生成、usage_countを0に |

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

#### account_join_codes

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | code, usage_count, usage_limit | account_id一致 | show/edit |
| UPDATE | usage_limit | 入力値 | update |
| UPDATE | code | SecureRandom.base58(12)の変形 | reset |
| UPDATE | usage_count | 0 | reset |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | 権限エラー | 非管理者によるupdate/destroy試行 | Forbiddenエラー |
| 422 | バリデーションエラー | usage_limitが範囲外 | エラーメッセージ表示、edit画面再表示 |

### リトライ仕様

特になし

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

resetメソッドでは単一レコードの更新のためデフォルトのトランザクションが適用される。redeemメソッドではwith_lockを使用して排他制御を行う。

## パフォーマンス要件

- レスポンス時間：1秒以内
- QRコード生成は画面表示時にオンデマンドで実行

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

- ensure_adminによる管理者権限チェック（update/destroy）
- SecureRandom.base58によるセキュアなコード生成
- コード重複チェック（exists?によるユニーク保証）
- 使用回数制限による不正利用防止
- リセット時の確認ダイアログ（turbo_confirm）

## 備考

- 参加コードはアカウント作成時に自動的に1つ作成される（after_create :create_join_code）
- QRコード表示機能は別機能（No.88）として実装されている
- コードの使用（redeem）は別機能（No.4: 参加コードによるアカウント参加）で処理される

---

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

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

### 推奨読解順序

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

参加コードのデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Account::JoinCode | `app/models/account/join_code.rb` | 参加コードモデルの全体像 |

**読解のコツ**:
- 2行目: CODE_LENGTH = 12でコード長を定義
- 3行目: USAGE_LIMIT_MAX = 10,000,000,000で上限制限
- 7行目: バリデーションでusage_limitの範囲チェック
- 11行目: before_create :generate_codeでコード自動生成
- 13-17行目: redeem_if(&block)でコード使用時の処理
- 23-27行目: resetメソッドで新コード生成とカウントリセット
- 30-34行目: generate_codeでSecureRandom.base58を使用

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

処理の起点となるコントローラーを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | JoinCodesController | `app/controllers/account/join_codes_controller.rb` | CRUD操作の実装 |

**主要処理フロー**:
1. **2行目**: before_action :set_join_code - 全アクションで参加コード取得
2. **3行目**: before_action :ensure_admin, only: %i[update destroy] - 管理者権限チェック
3. **5-6行目**: showアクション（表示のみ）
4. **8-9行目**: editアクション（編集画面表示）
5. **11-16行目**: updateアクション - usage_limit更新
6. **18-21行目**: destroyアクション - resetメソッド呼び出し
7. **25-27行目**: set_join_code - Current.account.join_codeで取得

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

画面表示の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.erb | `app/views/account/join_codes/show.html.erb` | 参加コード表示画面 |
| 3-2 | edit.html.erb | `app/views/account/join_codes/edit.html.erb` | 制限編集画面 |

**読解のコツ**:
- show.html.erb:
  - 15行目: join_url(code: @join_code.code)で招待URL生成
  - 29-32行目: data-controller="copy-to-clipboard"でコピー機能
  - 47行目: qr_code_image(url)でQRコード表示
  - 20-24行目: 管理者のみリセットボタン表示
- edit.html.erb:
  - 16-19行目: number_fieldでusage_limit入力

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

```
Account::JoinCodesController
    │
    ├─ #show
    │      └─ set_join_code ─▶ Current.account.join_code
    │
    ├─ #edit
    │      └─ set_join_code
    │
    ├─ #update
    │      ├─ ensure_admin ─▶ 403 if !admin
    │      ├─ set_join_code
    │      └─ @join_code.update(join_code_params)
    │             └─ validates :usage_limit
    │
    └─ #destroy
           ├─ ensure_admin ─▶ 403 if !admin
           ├─ set_join_code
           └─ @join_code.reset
                  │
                  ├─ generate_code
                  │      └─ SecureRandom.base58(CODE_LENGTH)
                  │
                  ├─ usage_count = 0
                  │
                  └─ save!
```

### データフロー図

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

セッション情報 ───▶ Account::JoinCodesController#show ───▶ show.html.erb
(Current.account)          │                                   │
                           └─▶ @join_code取得                  ├── 招待URL
                                                               ├── QRコード
                                                               └── 使用状況

usage_limit ───────▶ #update ─────────────────────────────▶ リダイレクト
(フォーム入力)             │                                   (show画面)
                           └─▶ account_join_codes UPDATE

DELETEリクエスト ───▶ #destroy ────────────────────────────▶ リダイレクト
                           │                                   (show画面)
                           └─▶ @join_code.reset
                                   │
                                   └─▶ account_join_codes UPDATE
                                       (code, usage_count)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| JoinCodesController | `app/controllers/account/join_codes_controller.rb` | コントローラー | 参加コード管理操作 |
| Account::JoinCode | `app/models/account/join_code.rb` | モデル | 参加コードデータ管理 |
| Account | `app/models/account.rb` | モデル | has_one :join_code |
| show.html.erb | `app/views/account/join_codes/show.html.erb` | ビュー | 参加コード表示画面 |
| edit.html.erb | `app/views/account/join_codes/edit.html.erb` | ビュー | 制限編集画面 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（7行目） |
