# 機能設計書 76-カスタムフィールド削除

## 概要

本ドキュメントは、Fat Free CRM の管理者向けカスタムフィールド削除機能の設計を定義する。この機能により、システム管理者は不要になったカスタムフィールドをシステムから削除することができる。

### 本機能の処理概要

カスタムフィールド削除機能は、エンティティから不要なカスタムフィールドを削除する管理者専用機能である。重要な点として、フィールドレコードは削除されるが、データベースカラム自体は削除されない（データ保全のため）。孤立したカラムは別途提供されるrakeタスクで削除できる。ペアフィールドの場合は、両方のフィールドが連動して削除される。

**業務上の目的・背景**：業務要件の変更により不要になったカスタムフィールドを整理する必要がある。また、誤って作成したフィールドを削除したい場合もある。この機能により、管理画面からフィールドを削除し、フィールド一覧をクリーンに保つことができる。ただし、データの安全性を考慮し、実際のデータベースカラムは残される。

**機能の利用シーン**：
- 不要になったカスタムフィールドを削除する場合
- 誤って作成したフィールドを削除する場合
- フィールド構成の整理・棚卸しを行う場合
- 古いフィールドを廃止する場合

**主要な処理内容**：
1. 削除対象フィールドの取得
2. フィールドレコードの削除（destroyアクション）
3. ペアフィールドの場合は関連フィールドも連動削除
4. 削除結果のレスポンス返却

**関連システム・外部連携**：本機能は外部システムとの連携はなく、Fat Free CRM 内部のデータベースを操作する。データベースカラムは削除されないため、データは保持される。

**権限による制御**：この機能は管理者権限を持つユーザーのみが実行可能である。一般ユーザーは管理画面にアクセスできず、カスタムフィールドの削除は行えない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 43 | カスタムフィールド管理画面 | 主画面 | 削除ボタン押下、削除確認、削除実行 |

## 機能種別

CRUD操作（Delete）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | Integer | Yes | 削除対象フィールドのID | 存在するFieldIDであること |

### 入力データソース

- URLパラメータ（フィールドID）
- 削除確認ボタン押下（ユーザー操作）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @field | Field | 削除されたフィールドオブジェクト（削除前の状態） |

### 出力先

- 画面表示（AJAX応答によるフィールド一覧の更新）
- HTMLまたはJavaScript形式でのレスポンス

## 処理フロー

### 処理シーケンス

```
1. destroyアクション呼び出し
   └─ フィールドIDによる対象フィールドの取得（Field.find）
   └─ フィールドの削除（@field.destroy）
   └─ ペアフィールドの場合：pair の連動削除（dependent: :destroy）
2. レスポンス返却
   └─ respond_with による適切な形式での応答
```

### フローチャート

```mermaid
flowchart TD
    A[削除ボタン押下] --> B[destroyアクション]
    B --> C[Field.find]
    C --> D{フィールド存在?}
    D -->|No| E[404エラー]
    D -->|Yes| F[@field.destroy]
    F --> G{ペアフィールド?}
    G -->|Yes| H[pair.destroy（連動）]
    G -->|No| I[削除完了]
    H --> I
    I --> J[一覧更新]
    J --> K[DBカラムは残存]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-76-01 | 管理者権限必須 | カスタムフィールド削除は管理者ユーザーのみ実行可能 | 常時 |
| BR-76-02 | カラム保持 | フィールド削除後もデータベースカラムは残される | 常時 |
| BR-76-03 | ペアフィールド連動削除 | ペアフィールドは両方が連動して削除される | datepair, datetimepair の場合 |
| BR-76-04 | データ保持 | カラムが残るため、既存データは保持される | 常時 |

### 計算ロジック

特になし（単純な削除処理）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フィールド取得 | fields | SELECT | IDによるフィールド検索 |
| フィールド削除 | fields | DELETE | 対象フィールドの削除 |
| ペア削除 | fields | DELETE | pair_idで関連するフィールドの連動削除 |

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

#### fields テーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | WHERE id = :id | 対象フィールドを削除 |
| DELETE | - | WHERE pair_id = :id | ペアフィールドの連動削除（dependent: :destroy） |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | NotFound | 指定IDのフィールドが存在しない | エラーページ表示 |
| 403 | Forbidden | 管理者権限がない | ログインページへリダイレクト |

### リトライ仕様

リトライは不要

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

ActiveRecordのデフォルトトランザクションを使用。ペアフィールドの削除は dependent: :destroy により同一トランザクション内で実行される。

## パフォーマンス要件

- レスポンス時間：1秒以内（AJAX応答）
- フィールド削除のみのため高速

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

- 管理者認証必須（before_action :require_admin_user）
- CSRF トークン検証（Rails標準）
- データベースカラムは残るため、データは保護される

## 備考

- フィールドレコードは削除されるが、データベースカラムは削除されない
- 孤立したカラムを削除するためのrakeタスクが別途提供されている
- フィールド削除後にデータを復旧したい場合は、同名のフィールドを再作成する必要がある
- カラム名は自動生成されるため、完全に同じカラムを再利用することは困難

---

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

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

### 推奨読解順序

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

フィールドの削除とペアフィールドの連動削除を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | custom_field_pair.rb | `app/models/fields/custom_field_pair.rb` | has_one :pair、dependent: :destroy |

**読解のコツ**: CustomFieldPairは`has_one :pair`で終了側フィールドを参照しており、`dependent: :destroy`により開始側を削除すると終了側も自動削除される。

**主要処理フロー**:
- **custom_field_pair.rb 9行目**: `has_one :pair, dependent: :destroy` - ペアフィールドの連動削除設定

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fields_controller.rb | `app/controllers/admin/fields_controller.rb` | destroyアクションの実装 |

**主要処理フロー**:
- **75-80行目**: `destroy` アクション - フィールド取得と削除処理
- **10行目**: `load_resource except: [:create, :subform]` - 自動リソースロード

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

```
Admin::FieldsController
    │
    ├─ Admin::ApplicationController
    │      └─ require_admin_user（管理者権限チェック）
    │
    └─ destroy アクション
           ├─ Field.find(params[:id])
           │
           └─ @field.destroy
                  │
                  └─【ペアフィールドの場合】
                         └─ pair.destroy（dependent: :destroy）
```

### データフロー図

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

フィールドID(URL) ──▶ destroyアクション ──────▶ 一覧更新(HTML/JS)
                              │
                              ▼
                        Field.find
                              │
                              ▼
                        fields テーブル SELECT
                              │
                              ▼
                        @field.destroy
                              │
                              ├─ fields テーブル DELETE
                              │
                              └─【ペアの場合】
                                     │
                                     ▼
                                 pair.destroy
                                     │
                                     ▼
                                 fields テーブル DELETE（連動）

※ エンティティテーブルのカラムは削除されない
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| field.rb | `app/models/fields/field.rb` | モデル | Fieldモデル基底クラス |
| custom_field.rb | `app/models/fields/custom_field.rb` | モデル | CustomFieldモデル |
| custom_field_pair.rb | `app/models/fields/custom_field_pair.rb` | モデル | ペアフィールド、連動削除設定 |
| fields_controller.rb | `app/controllers/admin/fields_controller.rb` | コントローラー | フィールドCRUD処理 |
| application_controller.rb | `app/controllers/admin/application_controller.rb` | コントローラー | 管理者基底コントローラー |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（190-198行目） |
