# 通知設計書 9-未公開変更削除通知

## 概要

本ドキュメントは、Decap CMSの編集ワークフローにおいて未公開の変更を削除した場合に表示されるトースト通知の設計仕様を定義する。削除操作の成功時には成功通知、失敗時にはエラー通知が表示される。成功・失敗の両ケースで同一のi18nキーが使用されるが、通知種別（type）と自動消去時間が異なる。

### 本通知の処理概要

本通知は、Decap CMSの編集ワークフロー機能において未公開エントリの変更を削除した場合に発火するトースト通知である。`deleteUnpublishedEntry` 関数内で `backend.deleteUnpublishedEntry()` の結果に応じて、成功時は `type: 'success'`（4秒で消去）、失敗時は `type: 'error'`（8秒で消去、details付き）のトーストが表示される。両方のケースで同一のi18nキー `ui.toast.onDeleteUnpublishedChanges` が使用される。

**業務上の目的・背景**：編集ワークフローにおいて、レビュー中や下書き状態のエントリの変更を破棄する操作のフィードバックを提供する。削除が正常に完了したことの確認、または失敗した場合のエラー通知によって、ワークフロー状態の整合性を維持する。

**通知の送信タイミング**：バックエンドの `backend.deleteUnpublishedEntry(collection, slug)` のPromiseがresolve（成功）またはreject（失敗）した時点で即座に通知が発行される。

**通知の受信者**：未公開変更の削除操作を行った当該ユーザー本人。ブラウザ画面上のトースト通知として表示される。

**通知内容の概要**：i18nキー `ui.toast.onDeleteUnpublishedChanges` に基づくメッセージが表示される。英語ロケールでは `Unpublished changes deleted` という固定メッセージ。失敗時にはdetails付きで表示されるが、英語テンプレート自体には `%{details}` プレースホルダが含まれないため、detailsの表示はi18n実装に依存する。

**期待されるアクション**：成功時は特別な対応不要。失敗時はユーザーが再試行するか、管理者に連絡することが期待される。

## 通知種別

アプリ内通知（トースト通知）

react-toastify ライブラリを使用したブラウザ内トースト通知。画面右上（`top-right`）に `colored` テーマで表示される。

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（Redux dispatch → react-toastify） |
| 優先度 | 中（ワークフロー操作のフィードバック） |
| リトライ | なし |

### 送信先決定ロジック

削除操作を実行したユーザーのブラウザセッションに対して直接表示する。

## 通知テンプレート

### メール通知の場合

該当なし

### 本文テンプレート

```
Unpublished changes deleted
```

i18nキー `ui.toast.onDeleteUnpublishedChanges` の英語テンプレート。成功時・失敗時ともに同一キー。

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| details | 削除失敗時のエラー情報（失敗時のみ） | catchブロックで捕捉されたerrorオブジェクト | No（失敗時のみ） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | 未公開変更の削除操作（成功） | `deleteUnpublishedEntry` 内で `backend.deleteUnpublishedEntry()` が正常に完了 | 成功トースト通知（editorialWorkflow.ts 459-466行目） |
| 画面操作 | 未公開変更の削除操作（失敗） | `deleteUnpublishedEntry` 内で `backend.deleteUnpublishedEntry()` がrejectされた場合 | エラートースト通知（editorialWorkflow.ts 469-476行目） |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | 成功時・失敗時のどちらの場合も通知が発行される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーが未公開変更削除操作] --> B[deleteUnpublishedEntry 発火]
    B --> C[dispatch unpublishedEntryDeleteRequest]
    C --> D[backend.deleteUnpublishedEntry 呼び出し]
    D -->|成功| E[dispatch addNotification - 成功トースト type:success, 4秒]
    D -->|失敗| F[dispatch addNotification - エラートースト type:error, 8秒]
    E --> G[dispatch unpublishedEntryDeleted]
    F --> H[dispatch unpublishedEntryDeleteError]
    G --> I[Notifications コンポーネントがトースト描画]
    H --> I
    I --> J[自動消去 - 成功4秒 / エラー8秒]
    J --> K[終了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| バックエンドAPI失敗 | deleteUnpublishedEntry APIがエラーを返す | エラートースト通知（type: error, 8秒）を表示し、unpublishedEntryDeleteErrorアクションでRedux stateを更新 |
| ネットワークエラー | バックエンドへの接続が失敗 | 同上 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし

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

- 失敗時のエラーオブジェクトが `details` として通知ペイロードに含まれる。ただし英語テンプレート自体に `%{details}` プレースホルダが含まれないため、i18nの実装によっては表示されない場合がある

## 備考

- 成功時と失敗時で同一のi18nキー `ui.toast.onDeleteUnpublishedChanges` が使用される点が他の通知と異なる特徴
- 成功時: `type: 'success'`, `dismissAfter: 4000`（detailsなし）
- 失敗時: `type: 'error'`, `dismissAfter: 8000`（details: error あり）
- 英語テンプレート `Unpublished changes deleted` にはdetailsのプレースホルダがないため、失敗時のdetailsがメッセージに含まれるかはi18n変換処理の実装に依存する
- `deleteUnpublishedEntry` はpublish_modeが `editorial_workflow` の場合に使用される機能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | notifications.ts (actions) | `packages/decap-cms-core/src/actions/notifications.ts` | `NotificationMessage` の `details` が `unknown` 型であり、任意で含められることを確認 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | editorialWorkflow.ts | `packages/decap-cms-core/src/actions/editorialWorkflow.ts` | `deleteUnpublishedEntry` 関数（452-479行目）全体のフローを理解する。成功時（459-467行目）と失敗時（469-477行目）の両方に注目。 |

**主要処理フロー**:
1. **456行目**: `dispatch(unpublishedEntryDeleteRequest(collection, slug))` - 削除リクエスト状態
2. **457-458行目**: `backend.deleteUnpublishedEntry(collection, slug)` - バックエンドAPI呼び出し
3. **459-466行目**: `.then` - 成功時: `addNotification`（type: 'success', dismissAfter: 4000）、`unpublishedEntryDeleted`
4. **469-477行目**: `.catch` - 失敗時: `addNotification`（type: 'error', dismissAfter: 8000, details: error）、`unpublishedEntryDeleteError`

#### Step 3: i18nメッセージテンプレートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.js (en) | `packages/decap-cms-locales/src/en/index.js` | 281行目: `onDeleteUnpublishedChanges: 'Unpublished changes deleted'` - detailsプレースホルダなし |

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

```
deleteUnpublishedEntry (editorialWorkflow.ts:452)
    |
    +-- dispatch(unpublishedEntryDeleteRequest()) (editorialWorkflow.ts:456)
    |
    +-- backend.deleteUnpublishedEntry() (editorialWorkflow.ts:457)
            |
            +-- [成功時] .then (editorialWorkflow.ts:459)
            |       |
            |       +-- dispatch(addNotification({key:'ui.toast.onDeleteUnpublishedChanges', type:'success', dismissAfter: 4000}))
            |       +-- dispatch(unpublishedEntryDeleted())
            |
            +-- [失敗時] .catch (editorialWorkflow.ts:469)
                    |
                    +-- dispatch(addNotification({key:'ui.toast.onDeleteUnpublishedChanges', type:'error', dismissAfter: 8000, details: error}))
                    +-- dispatch(unpublishedEntryDeleteError())
```

### データフロー図

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

削除操作               -->  backend.deleteUnpublished   -->  [成功] void
(collection, slug)          Entry()                           |
                                                              v
                                                         addNotification()
                                                         (type:'success', 4秒)

                                                         [失敗] Error オブジェクト
                                                              |
                                                              v
                                                         addNotification()
                                                         (type:'error', 8秒, details)

                                                              |
                                                              v
                                                         Redux store → toast UI
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| editorialWorkflow.ts | `packages/decap-cms-core/src/actions/editorialWorkflow.ts` | ソース | `deleteUnpublishedEntry` 関数が成功/失敗時にトースト通知を発行 |
| notifications.ts (actions) | `packages/decap-cms-core/src/actions/notifications.ts` | ソース | 通知アクション作成関数 |
| notifications.ts (reducers) | `packages/decap-cms-core/src/reducers/notifications.ts` | ソース | 通知リデューサー |
| Notifications.tsx | `packages/decap-cms-core/src/components/UI/Notifications.tsx` | ソース | 通知UIコンポーネント |
| index.js (en) | `packages/decap-cms-locales/src/en/index.js` | i18nリソース | 英語ロケール定義 |
