# 機能設計書 30-アセット削除

## 概要

本ドキュメントは、LEGACY CMSにおけるアセット削除機能の設計仕様を定義する。

### 本機能の処理概要

アセット削除機能は、不要になったアセット（ファイル）をシステムから削除するための機能である。削除前に確認ダイアログを表示し、ユーザーの明示的な確認後に削除を実行する。データベースからのレコード削除と、サーバー上の実ファイルの削除の両方が行われる。

**業務上の目的・背景**：不要になったアセットファイルを整理し、サーバーのディスク容量を節約するために削除機能が必要である。実ファイルも削除することで、孤立ファイルの発生を防ぐ。

**機能の利用シーン**：アセット管理画面で対象アセットの「Delete」操作を実行すると、Ajaxダイアログで削除確認が表示される。「Delete」ボタンをクリックすると削除が実行され、完了メッセージが表示される。

**主要な処理内容**：
1. 削除確認ダイアログの表示
2. 確認後、データベースからアセットレコードを削除
3. サーバー上の実ファイルを削除

**関連システム・外部連携**：特になし

**権限による制御**：「fassets」権限と「fassetdelete」権限の両方を持つロールのみがアクセス可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 55 | アセット管理画面 | 遷移元画面 | アセット削除ダイアログへの遷移 |

## 機能種別

CRUD操作（Delete）/ 確認ダイアログ / ファイル削除

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | int | Yes | 削除対象アセットID | 数値 |
| confirm | string | No | 削除確認フラグ | '1'で確認済み |

### 入力データソース

- URLパラメータ（GETリクエスト）
- Ajaxダイアログからの呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 確認メッセージ | string | 「Are you sure you want to delete this asset?」 |
| 成功メッセージ | string | 「Asset Deleted」 |

### 出力先

- 画面表示（Ajaxダイアログ内）
- データベース（DELETE操作）
- ファイルシステム（ファイル削除）

## 処理フロー

### 処理シーケンス

```
1. 削除要求受付
   └─ ACL権限チェック（fassets, fassetdelete）

2. 確認フラグチェック
   ├─ confirm != '1' の場合
   │     └─ 確認ダイアログ表示
   └─ confirm == '1' かつ id設定ありの場合
         ├─ アセット情報取得
         ├─ 実ファイルパス生成
         ├─ 実ファイル削除（unlink）
         ├─ assetsテーブルからDELETE
         └─ 成功メッセージ表示
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{権限チェック}
    B -->|権限なし| C[権限エラー]
    B -->|権限あり| D{confirm = '1' かつ id設定あり?}
    D -->|No| E[確認ダイアログ表示]
    E --> F{ユーザー操作}
    F -->|Delete| G[confirm=1で再リクエスト]
    F -->|Cancel| H[ダイアログ閉じる]
    G --> D
    D -->|Yes| I[アセット情報取得]
    I --> J[ファイルパス生成]
    J --> K[実ファイル削除]
    K --> L[DBレコード削除]
    L --> M[成功メッセージ表示]
    M --> N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-30-01 | 削除確認必須 | 削除実行前に必ず確認ダイアログを表示 | 常時 |
| BR-30-02 | 実ファイル削除 | データベースレコードだけでなく実ファイルも削除 | 常時 |
| BR-30-03 | 物理削除 | 論理削除ではなく物理削除を実行 | 常時 |

### 計算ロジック

- 実ファイルパス: `$registry->assets->assets->syspath` + `asset_file`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| アセット情報取得 | assets | SELECT | 削除対象アセット取得 |
| アセット削除 | assets | DELETE | アセットレコード削除 |

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

#### assets

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | asset_id, asset_file | WHERE asset_id = ? LIMIT 1 | 削除対象取得 |
| DELETE | - | WHERE asset_id = ? | アセットレコード削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | fassets/fassetdelete権限なし | 権限エラー画面へ転送 |

### リトライ仕様

特になし

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

ファイル削除とDB削除が連続して実行されるが、明示的なトランザクション制御は実装されていない。ファイル削除後にDB削除が失敗した場合、ファイルは既に削除されており復旧できない点に注意が必要。

## パフォーマンス要件

- Ajaxダイアログでの表示のため、レスポンスは軽量であること

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

- 管理画面へのアクセスはACLによる権限チェック必須（fassets + fassetdelete）
- CSRF対策として確認フラグによる2段階処理
- 削除は物理削除のため、復旧不可であることをユーザーに明示

## 備考

- 論理削除ではなく物理削除のため、削除後のデータ復旧は不可
- サムネイルキャッシュは削除されない（キャッシュの孤立発生の可能性あり）
- アセットを参照しているコンテンツ（記事等）がある場合でも削除可能（リンク切れ発生の可能性あり）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | assetsテーブル | データベース | asset_id, asset_file カラム |
| 1-2 | assets.ini | 設定ファイル | syspathの設定 |

**読解のコツ**: asset_fileはサーバー上のファイル名（実ファイル）を格納している。削除時はsyspath + asset_fileで完全パスを構成する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Admin_AssetsController.php | `application/modules/admin/controllers/AssetsController.php` | deleteAction |

**主要処理フロー（deleteAction）**:
1. **952行目**: 権限チェック（fassets, fassetdelete）
2. **954-955行目**: レイアウト・ビュー無効化（Ajax用）
3. **957-958行目**: パラメータ取得（confirm, id）
4. **960行目**: 確認フラグとアセットIDの存在チェック
5. **963行目**: レジストリ取得
6. **966-969行目**: アセット情報取得SELECT
7. **972行目**: クエリ実行
8. **974行目**: アセット情報取得
9. **976行目**: 実ファイルパス生成
10. **979行目**: 実ファイル削除（unlink）
11. **982行目**: データベースからDELETE
12. **984-989行目**: 成功メッセージHTML出力
13. **993-1000行目**: 確認ダイアログHTML出力（confirm != '1'の場合）

#### Step 3: 呼び出し元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.phtml | `application/modules/admin/views/scripts/assets/index.phtml` | 削除リンクの実装 |

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

```
index.phtml
    │
    └─ getDialog() [JavaScript]
           │
           └─ Admin_AssetsController::deleteAction()
                  │
                  ├─ [confirm != '1'] 確認ダイアログ表示
                  │
                  └─ [confirm == '1']
                         ├─ Zend_Db_Select - アセット情報取得
                         ├─ unlink() - 実ファイル削除
                         └─ Zend_Db_Adapter::delete() - DBレコード削除
```

### データフロー図

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

URLパラメータ               deleteAction()
  id              ───▶
  confirm                   [confirm != '1']
                            │
                            └───▶ 確認ダイアログHTML

URLパラメータ               deleteAction()
  id              ───▶      [confirm == '1']
  confirm='1'               │
                            ├─ SELECT assets      ◀───   assetsテーブル
                            │
                            ├─ unlink()           ───▶   ファイルシステム
                            │                            (ファイル削除)
                            │
                            ├─ DELETE assets      ───▶   assetsテーブル
                            │                            (レコード削除)
                            │
                            └───▶ 成功メッセージHTML
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AssetsController.php | `application/modules/admin/controllers/AssetsController.php` | コントローラー | アセット削除処理 |
| Admin.php | `library/CMS/Controller/Action/Admin.php` | 親クラス | 認証・ACL基盤処理 |
| index.phtml | `application/modules/admin/views/scripts/assets/index.phtml` | ビュー | 削除リンク（呼び出し元） |
| common.js | `public/_scripts/admin/common.js` | JavaScript | getDialog()関数 |
| assets.ini | `application/configs/assets.ini` | 設定 | アセット保存パス設定 |
