# 機能設計書 72-タグ削除

## 概要

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

### 本機能の処理概要

タグ削除機能は、CRM システムで使用されなくなったタグを削除する管理者専用機能である。タグを削除すると、そのタグと各エンティティ（取引先、リード、連絡先など）との紐付け（Tagging）も同時に削除される。ただし、フィールドグループに関連付けられているタグは削除できない保護機能が実装されている。

**業務上の目的・背景**：業務運用の中で不要になったタグや誤って作成されたタグを整理し、タグリストの可読性とメンテナンス性を維持する必要がある。また、タグの乱立を防ぎ、データ分類の品質を保つことが求められる。この機能により、管理者はタグの整理・統制を行うことができる。

**機能の利用シーン**：
- 使用されなくなったタグを削除する場合
- 誤って作成したタグを削除する場合
- タグの統合後に不要になった古いタグを削除する場合
- システムのタグ数を整理する定期メンテナンス時

**主要な処理内容**：
1. 削除確認ダイアログの表示（confirmアクション）
2. 削除対象タグの存在確認
3. フィールドグループとの関連チェック（削除可否判定）
4. タグおよび関連Taggingレコードの削除
5. 削除結果のレスポンス返却

**関連システム・外部連携**：本機能は外部システムとの連携はなく、Fat Free CRM 内部のデータベースのみを操作する。ActsAsTaggableOn gem を拡張したTag モデルを使用している。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 42 | タグ管理画面 | 主画面 | タグ一覧からの削除ボタン押下、確認ダイアログ、削除実行 |

## 機能種別

CRUD操作（Delete）

## 入力仕様

### 入力パラメータ

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

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @tag | Tag | 削除されたタグオブジェクト（削除前の状態） |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. confirmアクション呼び出し（削除確認）
   └─ タグIDによる対象タグの取得
   └─ 削除確認ダイアログの表示
2. destroyアクション呼び出し
   └─ タグIDによる対象タグの取得（load_resource）
   └─ before_destroyコールバック実行
      └─ no_associated_field_groups チェック
   └─ タグの削除（tag.destroy）
      └─ 関連Taggingの自動削除（dependent: destroy）
3. レスポンス返却
   └─ respond_with による適切な形式での応答
```

### フローチャート

```mermaid
flowchart TD
    A[削除ボタン押下] --> B[confirmアクション]
    B --> C[確認ダイアログ表示]
    C --> D{削除確認?}
    D -->|キャンセル| E[一覧に戻る]
    D -->|確認| F[destroyアクション]
    F --> G[タグ取得]
    G --> H{タグ存在?}
    H -->|No| I[404エラー]
    H -->|Yes| J{FieldGroup関連?}
    J -->|Yes| K[削除失敗]
    J -->|No| L[タグ削除]
    L --> M[Tagging自動削除]
    M --> N[一覧更新]
    K --> O[エラーメッセージ表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-72-01 | 管理者権限必須 | タグ削除は管理者ユーザーのみ実行可能 | 常時 |
| BR-72-02 | フィールドグループ関連保護 | フィールドグループに関連付けられたタグは削除不可 | タグにtag_idを持つFieldGroupが存在する場合 |
| BR-72-03 | Tagging連動削除 | タグ削除時に関連するTaggingレコードも自動削除 | タグ削除成功時 |
| BR-72-04 | 削除確認必須 | 削除前に確認ダイアログを表示 | 削除ボタン押下時 |

### 計算ロジック

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

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| タグ取得 | tags | SELECT | IDによるタグ検索 |
| 関連チェック | field_groups | SELECT | tag_idによるFieldGroup検索 |
| タグ削除 | tags | DELETE | 対象タグの削除 |
| Tagging削除 | taggings | DELETE | 関連Taggingの連動削除 |

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

#### tags テーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | WHERE id = :id | 対象タグを削除 |

#### taggings テーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | WHERE tag_id = :id | ActsAsTaggableOnによる連動削除 |

#### field_groups テーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | tag_id | WHERE tag_id = :id | 削除可否判定用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | NotFound | 指定IDのタグが存在しない | エラーページ表示 |
| 403 | Forbidden | 管理者権限がない | ログインページへリダイレクト |
| - | DeleteFailed | FieldGroupに関連付けられている | 削除失敗メッセージ表示 |

### リトライ仕様

- リトライは不要
- FieldGroup関連による削除失敗の場合は、先にFieldGroupとの関連を解除する必要がある

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

ActiveRecordのデフォルトトランザクションを使用。タグとTaggingの削除は同一トランザクション内で実行され、失敗時は全体がロールバックされる。

## パフォーマンス要件

- レスポンス時間：1秒以内（AJAX応答）
- Tagging件数が多い場合でもバッチ削除により効率的に処理

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

- 管理者認証必須（before_action :require_admin_user）
- CSRF トークン検証（Rails標準）
- 削除確認ダイアログによる誤操作防止

## 備考

- ActsAsTaggableOn gem の Tag クラスを継承したカスタム Tag モデルを使用
- before_destroy コールバックで削除可否を判定
- dependent: :destroy により関連Taggingは自動削除される

---

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

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

### 推奨読解順序

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

Tag モデルの削除制御ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | tag.rb | `app/models/polymorphic/tag.rb` | 削除前コールバック、FieldGroupとの関連チェック |

**読解のコツ**: `before_destroy` コールバックが `false` を返すと削除がキャンセルされる。`no_associated_field_groups` メソッドは、関連するFieldGroupが存在しない場合に `true` を返す。

**主要処理フロー**:
- **9行目**: `before_destroy :no_associated_field_groups` - 削除前にFieldGroupとの関連をチェック
- **12-14行目**: `no_associated_field_groups` メソッド - `FieldGroup.where(tag_id: id).none?` で関連がないことを確認

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

削除処理のコントローラーアクションを確認する。

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

**主要処理フロー**:
- **11行目**: `load_resource` - CanCanCan による自動リソースロード
- **55-59行目**: `destroy` アクション - タグの削除処理
- **63-64行目**: `confirm` アクション - 削除確認ダイアログ表示

#### Step 3: 管理者コントローラー基底クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | application_controller.rb | `app/controllers/admin/application_controller.rb` | 管理者権限チェックの実装 |

**主要処理フロー**:
- **9行目**: `before_action :require_admin_user` - 全アクションで管理者権限をチェック

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

```
Admin::TagsController
    │
    ├─ Admin::ApplicationController
    │      └─ require_admin_user（管理者権限チェック）
    │
    ├─ load_resource（CanCanCan）
    │      └─ Tag.find(params[:id])
    │
    ├─ confirm アクション
    │      └─ 確認ダイアログ表示
    │
    └─ destroy アクション
           └─ @tag.destroy
                  ├─ before_destroy :no_associated_field_groups
                  │      └─ FieldGroup.where(tag_id: id).none?
                  │
                  └─ ActsAsTaggableOn::Tag#destroy
                         └─ Tagging.destroy_all（関連削除）
```

### データフロー図

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

タグID(URL) ───────▶ TagsController#confirm ──▶ 確認ダイアログ(HTML)
                          │
                          ▼
削除確認 ─────────▶ TagsController#destroy ──▶ 削除結果(HTML/JS)
                          │
                          ▼
                     Tag#destroy
                          │
                          ├─ no_associated_field_groups
                          │      │
                          │      ▼
                          │  field_groups テーブル確認
                          │
                          ▼
                     tags テーブル DELETE
                          │
                          ▼
                     taggings テーブル DELETE（連動）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| tag.rb | `app/models/polymorphic/tag.rb` | モデル | Tagモデル定義、削除制御 |
| tagging.rb | `app/models/polymorphic/tagging.rb` | モデル | Taggingモデル定義 |
| tags_controller.rb | `app/controllers/admin/tags_controller.rb` | コントローラー | タグCRUD処理 |
| application_controller.rb | `app/controllers/admin/application_controller.rb` | コントローラー | 管理者基底コントローラー |
| field_group.rb | `app/models/fields/field_group.rb` | モデル | FieldGroupモデル（タグとの関連） |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（200-204行目） |
