# 機能設計書 13-取引検索・フィルタ

## 概要

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

### 本機能の処理概要

取引検索・フィルタ機能は、日付、金額、カテゴリ、支払先、メモなどの条件を指定して取引を絞り込み表示する機能である。複数の条件を組み合わせた高度な検索が可能であり、保存済みフィルタによる再利用もサポートする。

**業務上の目的・背景**：数百〜数千件の取引から特定の条件に合致するものを効率的に見つけ出すニーズがある。月次の支出確認、特定の支払先との取引履歴確認、特定カテゴリの支出分析など、様々な分析シーンで必要となる。本機能により、ユーザーは必要な情報に素早くアクセスできる。

**機能の利用シーン**：
- 特定の期間の支出を確認したい場合
- 特定のカテゴリ（例：食費）の取引を一覧したい場合
- 特定の支払先（例：Amazon）への支払い履歴を確認したい場合
- 未消込の取引を確認したい場合
- 特定金額以上の支出を確認したい場合

**主要な処理内容**：
1. フィルタ条件をUIで選択・入力
2. 条件を RuleConditionEntity 形式に変換
3. 条件の妥当性を検証（rule-validate）
4. AQLクエリに条件を適用して取引を取得
5. 結果を画面に表示
6. 保存済みフィルタとして保存・呼び出し

**関連システム・外部連携**：本機能は内部完結型であり、外部システムとの直接連携はない。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | カテゴリ画面（モバイル） | 補助機能 | カテゴリでフィルタされた取引の表示 |
| 12 | 口座一覧画面（デスクトップ） | 補助機能 | 取引の検索・フィルタリング処理 |
| 14 | 口座詳細画面（モバイル） | 補助機能 | モバイルでの取引フィルタリング |

## 機能種別

データ検索 / フィルタリング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| field | string | Yes | フィルタ対象フィールド | date/account/payee/notes/category/amount/cleared/reconciled/transfer |
| op | string | Yes | 比較演算子 | フィールドタイプに応じた有効な演算子 |
| value | any | Yes | フィルタ値 | フィールドタイプに応じた型 |
| options | object | No | 追加オプション（日付のmonth/year、金額のinflow/outflow等） | - |

### フィルタフィールド一覧

| フィールド | タイプ | 有効な演算子 | 説明 |
|-----------|-------|-------------|------|
| date | date | is, isapprox, isbetween, gt, gte, lt, lte | 取引日 |
| account | id | is, isNot, oneOf, notOneOf, contains, doesNotContain, matches | 口座 |
| payee | id | is, isNot, oneOf, notOneOf, contains, doesNotContain, matches | 支払先 |
| notes | string | is, isNot, contains, doesNotContain, matches, hasTags | メモ |
| category | id | is, isNot, oneOf, notOneOf, contains, doesNotContain, matches | カテゴリ |
| amount | number | is, isapprox, isbetween, gt, gte, lt, lte | 金額 |
| cleared | boolean | is | 消込状態 |
| reconciled | boolean | is | 照合状態 |
| transfer | boolean | is | 振替取引か |

### 入力データソース

- 画面入力（フィルタメニュー）
- 保存済みフィルタ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| transactions | TransactionEntity[] | フィルタ条件に合致する取引一覧 |
| count | number | 合致した取引数 |

### 出力先

- 画面表示（取引テーブル）

## 処理フロー

### 処理シーケンス

```
1. フィルタボタンクリック
   └─ FilterButtonコンポーネントがポップオーバーを表示

2. フィールド選択
   └─ 日付、口座、支払先、カテゴリ等から選択

3. 演算子選択
   └─ フィールドタイプに応じた有効な演算子を表示

4. 値入力
   └─ GenericInputコンポーネントで適切な入力UIを表示

5. 条件検証
   └─ send('rule-validate')で条件の妥当性を確認

6. フィルタ適用
   └─ onApplyコールバックで条件を親コンポーネントに伝達

7. クエリ実行
   └─ AQLクエリにフィルタ条件を適用して取引を取得

8. 結果表示
   └─ フィルタ結果を取引テーブルに表示
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[フィルタボタンクリック]
    B --> C[フィールドメニュー表示]
    C --> D[フィールド選択]
    D --> E[演算子選択]
    E --> F[値入力]
    F --> G[Applyボタンクリック]
    G --> H{条件検証}
    H -->|エラー| I[エラーメッセージ表示]
    H -->|OK| J[フィルタ適用]
    I --> F
    J --> K[AQLクエリ実行]
    K --> L[結果表示]
    L --> M{追加フィルタ?}
    M -->|Yes| B
    M -->|No| N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | フィールド別演算子制限 | 各フィールドタイプに応じた有効な演算子のみ選択可能 | 全フィルタ |
| BR-02 | ブール型フィールド | cleared、reconciled、transferはis演算子のみ | ブール型フィールド |
| BR-03 | 日付サブフィールド | 日付は「日付」「月」「年」のサブフィールドを選択可能 | 日付フィルタ |
| BR-04 | 金額サブフィールド | 金額は「金額」「収入」「支出」のサブフィールドを選択可能 | 金額フィルタ |
| BR-05 | 保存済みフィルタ | 保存済みフィルタ選択時は既存のフィルタをクリア | 保存済みフィルタ適用時 |

### 計算ロジック

**日付フォーマット変換**（月フィルタの場合）:
```typescript
// ユーザー入力: "January 2024" → 保存形式: "2024-01"
const date = parseDate(value, getMonthYearFormat(dateFormat), new Date());
cond.value = formatDate(date, 'yyyy-MM');
```

**金額オプション設定**:
```typescript
// サブフィールドに応じたオプション設定
options = subfieldToOptions(field, subfield);
// { inflow: true } or { outflow: true } or {}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フィルタ取引取得 | transactions | SELECT | フィルタ条件に合致する取引を取得 |
| 保存済みフィルタ取得 | transaction_filters | SELECT | 保存済みフィルタ一覧を取得 |

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

#### transactions

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 全項目 | WHERE句にフィルタ条件を適用 | AQL経由 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| conditionErrors | 条件エラー | 無効な条件値が入力された場合 | getFieldError関数でエラーメッセージを取得しalert表示 |

### リトライ仕様

エラー発生時、ユーザーが値を修正して再度Applyボタンをクリックする。

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

フィルタリング処理は読み取り専用であり、トランザクション管理は不要。

## パフォーマンス要件

- 複数条件の組み合わせでも即座に結果を表示すること
- 大量の取引データに対しても高速に検索できること（インデックスの活用）

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

- 特別なセキュリティ要件なし
- フィルタ条件は予算ファイル内でのみ有効

## 備考

- キーボードショートカット: `f`キーでフィルタメニューを開く
- 複数のフィルタ条件はAND条件で組み合わされる

---

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

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

### 推奨読解順序

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

フィルタ条件のデータ構造を理解する。

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

**読解のコツ**:
- **17-31行目**: FieldValueTypesでフィールドごとの値の型を定義
- **33-54行目**: BaseConditionEntityの構造（field、op、value、options）
- **56-114行目**: フィールドごとに許可される演算子の定義

#### Step 2: フィルタUIコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | FiltersMenu.tsx | `packages/desktop-client/src/components/filters/FiltersMenu.tsx` | FilterButton、ConfigureFieldコンポーネントの実装 |

**主要処理フロー**:
1. **63-73行目**: filterFieldsの定義（date、account、payee等）
2. **83-324行目**: ConfigureFieldコンポーネント - フィルタ条件編集UI
3. **333-543行目**: FilterButtonコンポーネント - フィルタボタンとポップオーバー
4. **393-441行目**: onValidateAndApply関数 - 条件検証とフィルタ適用

#### Step 3: フィルタロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | rules.ts | `packages/loot-core/src/shared/rules.ts` | フィールドタイプ、演算子、バリデーションロジック |

**主要処理フロー**:
- FIELD_TYPES: フィールドとそのタイプのマッピング
- getValidOps: フィールドに対して有効な演算子を取得
- mapField: フィールド名を表示用にマッピング
- unparse: 条件をクエリ形式に変換

#### Step 4: 入力コンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | GenericInput.tsx | `packages/desktop-client/src/components/util/GenericInput.tsx` | 汎用入力コンポーネント |

**主要処理フロー**:
- フィールドタイプに応じた適切な入力UIの自動選択
- 日付ピッカー、金額入力、セレクトボックス等

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

```
FilterButton (UI)
    │
    ├─ ConfigureField (条件入力UI)
    │      │
    │      ├─ FieldSelect (フィールド選択)
    │      ├─ OpSelect/OpButton (演算子選択)
    │      └─ GenericInput (値入力)
    │
    ├─ send('rule-validate') (条件検証)
    │
    └─ onApply callback
           │
           └─ 親コンポーネント
                  │
                  └─ AQLクエリ実行 → 取引表示
```

### データフロー図

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

フィールド選択 ────┐
                   │
演算子選択 ────────┼──▶ RuleConditionEntity ──▶ rule-validate
                   │           │
値入力 ────────────┘           │
                               ├──▶ onApply callback
                               │
                               └──▶ AQLクエリ生成 ──▶ 取引一覧
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| rule.ts | `packages/loot-core/src/types/models/rule.ts` | 型定義 | フィルタ条件の型 |
| FiltersMenu.tsx | `packages/desktop-client/src/components/filters/FiltersMenu.tsx` | ソース | フィルタUI |
| FiltersButton.tsx | `packages/desktop-client/src/components/filters/FiltersButton.tsx` | ソース | フィルタボタン |
| OpButton.tsx | `packages/desktop-client/src/components/filters/OpButton.tsx` | ソース | 演算子ボタン |
| GenericInput.tsx | `packages/desktop-client/src/components/util/GenericInput.tsx` | ソース | 汎用入力 |
| updateFilterReducer.ts | `packages/desktop-client/src/components/filters/updateFilterReducer.ts` | ソース | フィルタ状態管理 |
| subfieldFromFilter.ts | `packages/desktop-client/src/components/filters/subfieldFromFilter.ts` | ソース | サブフィールド抽出 |
| subfieldToOptions.ts | `packages/desktop-client/src/components/filters/subfieldToOptions.ts` | ソース | サブフィールドオプション変換 |
| rules.ts | `packages/loot-core/src/shared/rules.ts` | ソース | ルール・フィルタロジック |
| app.ts | `packages/loot-core/src/server/filters/app.ts` | ソース | フィルタAPIハンドラ |
