# 機能設計書 14-取引ルール

## 概要

本ドキュメントは、Actualアプリケーションにおける取引ルール機能について、その処理内容、入出力仕様、および実装詳細を記述した機能設計書である。

### 本機能の処理概要

取引ルール機能は、条件に基づいて取引を自動的にカテゴリ分けしたり、フィールドを設定したりするルール機能である。ルールは条件（Conditions）とアクション（Actions）で構成され、条件に合致する取引に対してアクションを自動適用する。

**業務上の目的・背景**：同じ支払先への支出は多くの場合同じカテゴリに分類される。手動でのカテゴリ設定は手間がかかるため、ルールによる自動分類が有用である。銀行連携やインポートで取得した取引を自動的に正しいカテゴリに分類することで、予算管理の効率が大幅に向上する。

**機能の利用シーン**：
- 特定の支払先（例：スーパーマーケットA）の取引を自動的に「食費」カテゴリに分類
- 特定のパターン（例：「Uber」を含む）の取引を「交通費」に分類
- 銀行からインポートした取引のインポート支払先名を正規の支払先に自動変換
- 特定条件の取引を自動的にスケジュールにリンク

**主要な処理内容**：
1. ルールの作成（条件とアクションの設定）
2. ルールの検証（rule-validate）
3. 取引に対するルールの適用（rules-run）
4. ルールの更新・削除
5. 支払先名変更ルールの自動生成

**関連システム・外部連携**：銀行同期機能と連携し、取得した取引に対してルールを自動適用する。

**権限による制御**：特別な権限制御はなく、予算ファイルを開いているユーザーであれば利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | 口座一覧画面（デスクトップ） | API連携 | ルールに基づく取引の自動カテゴリ分け |
| 19 | 支払先管理画面（デスクトップ） | 遷移先機能 | 支払先に関連するルールの表示・管理 |
| 22 | ルール管理画面（デスクトップ） | 主機能 | 取引自動分類ルールの一覧表示・管理 |
| 23 | ルール管理画面（モバイル） | 主機能 | モバイルでのルール一覧表示 |
| 24 | ルール編集画面（モバイル） | 主機能 | モバイルでのルール詳細編集 |

## 機能種別

CRUD操作 / 自動処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string | No（新規時） | ルールID（UUID） | - |
| stage | 'pre' \| null \| 'post' | No | ルール適用ステージ | - |
| conditionsOp | 'or' \| 'and' | Yes | 条件の結合演算子 | - |
| conditions | RuleConditionEntity[] | Yes | 条件リスト | 最低1件必要 |
| actions | RuleActionEntity[] | Yes | アクションリスト | 最低1件必要 |

### 条件タイプ（RuleConditionEntity）

| フィールド | タイプ | 有効な演算子 |
|-----------|-------|-------------|
| account | id | is, isNot, oneOf, notOneOf, contains, doesNotContain, matches, onBudget, offBudget |
| category | id | is, isNot, oneOf, notOneOf, contains, doesNotContain, matches |
| amount | number | is, isapprox, isbetween, gt, gte, lt, lte |
| date | date/RecurConfig | is, isapprox, isbetween, gt, gte, lt, lte |
| notes | string | is, isNot, contains, doesNotContain, matches, hasTags |
| payee | id | is, isNot, oneOf, notOneOf, contains, doesNotContain, matches |
| imported_payee | string | is, isNot, oneOf, notOneOf, contains, doesNotContain, matches |
| cleared | boolean | is |
| reconciled | boolean | is |

### アクションタイプ（RuleActionEntity）

| アクションタイプ | 説明 | 必要なフィールド |
|-----------------|------|-----------------|
| set | フィールドに値を設定 | field, value |
| set-split-amount | 分割金額を設定 | value, options.method |
| link-schedule | スケジュールにリンク | value（スケジュールID） |
| prepend-notes | メモの前に追加 | value |
| append-notes | メモの後に追加 | value |
| delete-transaction | 取引を削除 | - |

### 入力データソース

- 画面入力（ルール編集フォーム）
- API（外部システムからの呼び出し）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | ルールID |
| stage | string | 適用ステージ |
| conditionsOp | string | 条件結合演算子 |
| conditions | array | 条件リスト |
| actions | array | アクションリスト |

### 出力先

- データベース（rulesテーブル）

## 処理フロー

### 処理シーケンス

```
1. ルール作成開始
   └─ ユーザーがルール編集画面で「新規作成」を選択

2. 条件設定
   └─ フィールド、演算子、値を設定
   └─ 複数条件の場合、AND/ORを選択

3. アクション設定
   └─ アクションタイプ、対象フィールド、値を設定

4. ルール検証
   └─ send('rule-validate')で条件とアクションを検証

5. ルール保存
   └─ send('rule-add')または send('rule-update')

6. ルール適用
   └─ 取引インポート/追加時に自動適用
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ルール編集画面]
    B --> C[条件追加]
    C --> D{複数条件?}
    D -->|Yes| E[AND/OR選択]
    D -->|No| F[アクション追加]
    E --> C
    C --> F
    F --> G{検証}
    G -->|エラー| H[エラー表示]
    G -->|OK| I[保存]
    H --> B
    I --> J[ルール一覧更新]
    J --> K[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ステージ順序 | pre → null → post の順でルールを適用 | ルール実行時 |
| BR-02 | 条件結合 | conditionsOp='and'は全条件合致、'or'は1条件以上合致 | ルール評価時 |
| BR-03 | 支払先学習 | 取引のカテゴリ変更時、自動でルールを更新 | learnCategories=true |
| BR-04 | ルールランキング | より具体的なルールが優先される | ルール実行順序 |
| BR-05 | delete-transactionアクション | このアクションは慎重に使用（取引が削除される） | ルール作成時 |

### 計算ロジック

**ルール優先度（rankRules）**:
```typescript
// より具体的な条件を持つルールが優先
// 例：特定の支払先 > 含む文字列 > 金額範囲
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ルール作成 | rules | INSERT | 新規ルールを追加 |
| ルール更新 | rules | UPDATE | 既存ルールを更新 |
| ルール削除 | rules | UPDATE(tombstone) | ルールを論理削除 |
| ルール取得 | rules | SELECT | ルール一覧を取得 |

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

#### rules

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | stage, conditionsOp, conditions, actions | 入力値 | JSONシリアライズ |
| UPDATE | 同上 | 更新値 | - |
| SELECT | 全項目 | tombstone = 0 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| conditionErrors | 条件エラー | 無効な条件が指定された場合 | エラーメッセージを表示 |
| actionErrors | アクションエラー | 無効なアクションが指定された場合 | エラーメッセージを表示 |

### リトライ仕様

エラー発生時、ユーザーが条件/アクションを修正して再保存する。

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

- ルールの追加・更新・削除はundoable（元に戻す対応）
- batchMessagesでバッチ処理

## パフォーマンス要件

- ルール数が多くても取引適用時のパフォーマンスを維持
- ルールインデクサーによる効率的なマッチング

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

- delete-transactionアクションは慎重に使用する必要がある
- ルールは予算ファイル内でのみ有効

## 備考

- API経由でのルール操作: getRules, createRule, updateRule, deleteRule, getPayeeRules
- 支払先名変更ルール: addRulePayeeRename関数で自動生成

---

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

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

### 推奨読解順序

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

ルールの型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | rule.ts | `packages/loot-core/src/types/models/rule.ts` | RuleEntity、RuleConditionEntity、RuleActionEntityの型定義 |

**読解のコツ**:
- **3-13行目**: NewRuleEntity、RuleEntityの基本構造
- **17-31行目**: フィールドごとの値の型定義
- **116-163行目**: 各種アクションタイプの定義

#### Step 2: ルールAPIハンドラを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | app.ts | `packages/loot-core/src/server/rules/app.ts` | ルールAPIのハンドラ実装 |

**主要処理フロー**:
1. **17-64行目**: validateRule関数 - ルールの検証ロジック
2. **87-96行目**: ハンドラの登録（rule-validate、rule-add等）
3. **105-115行目**: addRule関数 - ルール追加
4. **117-127行目**: updateRule関数 - ルール更新
5. **183-185行目**: getRules関数 - ルール一覧取得（ランキング付き）

#### Step 3: ルール実行ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | transaction-rules.ts | `packages/loot-core/src/server/transactions/transaction-rules.ts` | ルール実行の詳細実装 |

**主要処理フロー**:
- runRules: 取引に対してルールを実行
- applyActions: アクションを適用
- updateCategoryRules: カテゴリ学習

#### Step 4: ルール編集UIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | RuleEditor.tsx | `packages/desktop-client/src/components/rules/RuleEditor.tsx` | ルール編集UIコンポーネント |

**主要処理フロー**:
- FieldSelect: フィールド選択コンポーネント
- OpSelect: 演算子選択コンポーネント
- GenericInput: 値入力コンポーネント

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

```
UI (RuleEditor.tsx)
    │
    ├─ send('rule-validate')
    │      └─ app.ts: ruleValidate
    │             └─ validateRule (Condition/Action検証)
    │
    ├─ send('rule-add')
    │      └─ app.ts: addRule
    │             └─ rules.insertRule
    │
    ├─ send('rule-update')
    │      └─ app.ts: updateRule
    │             └─ rules.updateRule
    │
    └─ send('rule-delete')
           └─ app.ts: deleteRule
                  └─ rules.deleteRule
```

### データフロー図

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

conditions[] ─────┐
                  │
                  ├──▶ validateRule ──▶ {conditionErrors, actionErrors}
                  │
actions[] ────────┘

                  ┌──▶ insertRule ──▶ rules テーブル
RuleEntity ───────┤
                  └──▶ updateRule ──▶ rules テーブル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| rule.ts | `packages/loot-core/src/types/models/rule.ts` | 型定義 | ルールデータ型 |
| app.ts | `packages/loot-core/src/server/rules/app.ts` | ソース | ルールAPIハンドラ |
| rule.ts | `packages/loot-core/src/server/rules/rule.ts` | ソース | ルールクラス |
| condition.ts | `packages/loot-core/src/server/rules/condition.ts` | ソース | 条件クラス |
| action.ts | `packages/loot-core/src/server/rules/action.ts` | ソース | アクションクラス |
| index.ts | `packages/loot-core/src/server/rules/index.ts` | ソース | ルールユーティリティ |
| transaction-rules.ts | `packages/loot-core/src/server/transactions/transaction-rules.ts` | ソース | 取引へのルール適用 |
| RuleEditor.tsx | `packages/desktop-client/src/components/rules/RuleEditor.tsx` | ソース | ルール編集UI |
| RulesList.tsx | `packages/desktop-client/src/components/rules/RulesList.tsx` | ソース | ルール一覧UI |
| methods.ts | `packages/api/methods.ts` | ソース | 外部API（getRules等） |
