# 通知設計書 27-複数テンプレート適用結果

## 概要

本ドキュメントは、複数のカテゴリに対してゴールテンプレートを一括適用した結果をユーザーに表示する通知の仕様を定義します。

### 本通知の処理概要

複数テンプレート適用結果通知は、ユーザーが選択した複数のカテゴリに対してゴールテンプレートを一括適用し、その処理結果をフィードバックする機能です。全カテゴリへの適用ではなく、ユーザーが明示的に選択したカテゴリへの適用を行います。

**業務上の目的・背景**：予算管理において、特定のカテゴリグループや関連するカテゴリのみにテンプレートを適用したい場合があります。例えば、「固定費」に分類されるカテゴリだけ、または手動で変更した予算を元に戻したい複数のカテゴリに対して一括で処理できます。この通知により、ユーザーは選択したカテゴリへの適用結果を確認できます。

**通知の送信タイミング**：ユーザーが複数カテゴリを選択し、予算メニューから「Apply budget template to selected」アクションを実行した際に、テンプレートの一括適用処理が行われ、結果が通知として表示されます。

**通知の受信者**：適用アクションを実行したユーザー（現在の予算ファイルを操作中のユーザー）に対して通知が表示されます。

**通知内容の概要**：テンプレートの適用結果として、適用されたカテゴリ数、既に最新の状態である場合のメッセージ、またはテンプレート解釈エラーの詳細が表示されます。

**期待されるアクション**：成功時は予算が正しく設定されたことを確認し、エラーがある場合は該当カテゴリのテンプレートを修正することが期待されます。

## 通知種別

アプリ内通知（メッセージタイプまたはエラータイプ）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ユーザーアクション駆動） |
| 優先度 | 中 |
| リトライ | なし |

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

適用アクションを実行したユーザーに対して結果を表示します。

## 通知テンプレート

### アプリ内通知

| 項目 | 内容 |
|-----|------|
| 通知タイプ | message（成功時）/ sticky（エラー時） |
| 件名/タイトル | なし |
| 表示形式 | トースト通知 |

### 本文テンプレート

**成功時（適用あり）：**
```
Successfully applied templates to {カテゴリ数} categories
```

**成功時（適用なし）：**
```
Everything is up to date
```

**エラー時：**
```
There were errors interpreting some templates:

{カテゴリ名}: {エラー内容}
...
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| カテゴリ数 | 適用されたカテゴリの数 | 処理結果 | No |
| pre | エラー詳細（改行区切り） | テンプレート解析結果 | No（エラー時のみ） |
| message | メインメッセージ | 固定値/動的生成 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | apply-multiple-templatesアクション | 常時 | 複数カテゴリ選択後にテンプレート一括適用実行時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | 適用実行時は常に結果を通知 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーが複数カテゴリを選択] --> B[Apply budget template to selectedを実行]
    B --> C[applyBudgetAction dispatch]
    C --> D[budget/apply-multiple-templates API呼び出し]
    D --> E[applyMultipleCategoryTemplates実行]
    E --> F[対象カテゴリ情報取得]
    F --> G[テンプレートノートを保存]
    G --> H[対象カテゴリのテンプレート取得]
    H --> I[processTemplate実行 force=true]
    I --> J{エラーあり?}
    J -->|Yes| K[エラー詳細を含む通知生成]
    J -->|No| L{適用カテゴリあり?}
    L -->|Yes| M[成功メッセージ通知生成]
    L -->|No| N[最新状態メッセージ通知生成]
    K --> O[addNotification dispatch]
    M --> O
    N --> O
    O --> P[UIに通知表示]
    P --> Q[終了]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| categories | 対象カテゴリ情報とテンプレート定義の取得 | categoryIds配列でフィルタ |
| zero_budgets / reflect_budgets | 現在の予算値 | 上書き前の値参照 |

### テーブル別参照項目詳細

#### categories

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | カテゴリ識別 | id IN (categoryIds) |
| name | エラーメッセージ表示用 | - |
| goal_def | テンプレート定義JSON | - |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| zero_budgets | UPDATE | 選択カテゴリの予算金額を設定 |
| reflect_budgets | UPDATE | Reflect予算の場合の予算金額設定 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| テンプレート解釈エラー | CategoryTemplateContext初期化失敗 | エラー詳細を通知に表示 |
| 構文エラー | テンプレート構文が不正 | エラー行を通知に表示 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

時間帯制限なし

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

- テンプレート処理はサーバー側で安全に実行
- 予算金額の変更はUndoable（取り消し可能）

## 備考

- 選択したカテゴリのうち、テンプレートが設定されているものだけが処理対象
- force=trueで呼び出されるため、既存の予算も上書きされる
- 処理はUndoable（取り消し可能）
- カテゴリグループの一括選択と組み合わせて使用することが多い

---

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

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

### 推奨読解順序

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

Notification型とカテゴリ関連の型を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | goal-template.ts | `packages/loot-core/src/server/budget/goal-template.ts` | Notification型（17-23行目） |
| 1-2 | models/index.ts | `packages/loot-core/src/types/models/index.ts` | CategoryEntity型の定義 |

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

クライアント側からの呼び出しフローを理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | budgetSlice.ts | `packages/desktop-client/src/budget/budgetSlice.ts` | apply-multiple-templatesケース（561-570行目） |

**主要処理フロー**:
1. **561行目**: `case 'apply-multiple-templates':` でアクション分岐
2. **562-569行目**: `send('budget/apply-multiple-templates', { month, categoryIds: args.categories })` でAPIを呼び出し、結果を `addNotification` でディスパッチ

#### Step 3: サーバー側処理を理解する

複数カテゴリテンプレート適用の実装を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | goal-template.ts | `packages/loot-core/src/server/budget/goal-template.ts` | applyMultipleCategoryTemplates関数（70-91行目） |

**主要処理フロー**:
- **70行目**: `applyMultipleCategoryTemplates` 関数開始
- **77-81行目**: AQL queryで対象カテゴリ情報を取得（$oneof演算子使用）
- **82行目**: `storeNoteTemplates()` でノートからテンプレートを保存
- **83行目**: `getTemplates(c => categoryIds.includes(c.id))` で対象カテゴリのテンプレートのみ取得
- **84-89行目**: `processTemplate(month, true, categoryTemplates, categoryData)` で適用（force=true）

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

```
applyBudgetAction (budgetSlice.ts:442)
    │
    ├─ case 'apply-multiple-templates' (budgetSlice.ts:561)
    │      │
    │      └─ send('budget/apply-multiple-templates', { month, categoryIds })
    │             │
    │             └─ app.method('budget/apply-multiple-templates') (app.ts:93)
    │                    │
    │                    └─ goalActions.applyMultipleCategoryTemplates (goal-template.ts:70)
    │                           │
    │                           ├─ aqlQuery - 対象カテゴリ取得 ($oneof)
    │                           ├─ storeNoteTemplates()
    │                           ├─ getTemplates(c => categoryIds.includes(c.id))
    │                           └─ processTemplate(month, true, categoryTemplates, categoryData)
    │
    └─ addNotification (budgetSlice.ts:562)
```

### データフロー図

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

ユーザーアクション ───▶ budget/apply-multiple-templates API ───▶ applyMultipleCategoryTemplates
      │                                                               │
      │                                                               ▼
      │                                                     カテゴリ情報取得
  month引数                                                 (AQL query $oneof)
  categoryIds引数                                                     │
                                                                      ▼
                                                           getTemplates
                                                           (対象カテゴリのみ)
                                                                      │
                                                                      ▼
                                                           processTemplate
                                                           (force=true)
                                                                      │
                                                                      ▼
                                                           Notification生成
                                                                      │
                                                                      ▼
                                                                UI表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| budgetSlice.ts | `packages/desktop-client/src/budget/budgetSlice.ts` | ソース | クライアント側のアクション処理 |
| goal-template.ts | `packages/loot-core/src/server/budget/goal-template.ts` | ソース | 複数カテゴリテンプレート適用のメイン処理 |
| app.ts | `packages/loot-core/src/server/budget/app.ts` | ソース | 予算関連APIのルーティング |
| CategoryGroupMenuModal.tsx | `packages/desktop-client/src/components/modals/CategoryGroupMenuModal.tsx` | ソース | カテゴリグループメニューUI |
