# 機能設計書 15-カテゴリ作成・編集・削除

## 概要

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

### 本機能の処理概要

カテゴリ作成・編集・削除機能は、支出・収入を分類するためのカテゴリを管理する機能である。カテゴリは必ずカテゴリグループに属し、予算管理の基本単位として使用される。

**業務上の目的・背景**：支出を適切に分類することで、どこにお金を使っているかを可視化できる。食費、交通費、娯楽費などのカテゴリを作成し、各取引をカテゴリに分類することで、予算計画と実績の比較が可能になる。本機能により、ユーザーは自身の生活スタイルに合った分類体系を構築できる。

**機能の利用シーン**：
- 新しい支出カテゴリ（例：サブスクリプション）を追加したい場合
- カテゴリ名を変更したい場合（例：「交通費」→「通勤費」）
- 使用しなくなったカテゴリを削除したい場合
- カテゴリの所属グループを変更したい場合

**主要な処理内容**：
1. カテゴリの新規作成（名前、所属グループ、収入/支出フラグを設定）
2. カテゴリ名の編集
3. カテゴリの削除（必要に応じて別カテゴリへの移行）
4. カテゴリの移動（グループ間移動、順序変更）
5. カテゴリマッピングテーブルによる削除カテゴリの追跡

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

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | 予算画面（デスクトップ） | 補助機能 | 予算カテゴリの追加・編集・削除処理 |
| 11 | カテゴリ画面（モバイル） | 主機能 | モバイルでのカテゴリ別取引一覧表示 |

## 機能種別

CRUD操作

## 入力仕様

### 入力パラメータ

#### カテゴリ作成

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | カテゴリ名 | 空文字不可、グループ内で一意 |
| groupId | string | Yes | 所属グループID | 存在するグループID |
| isIncome | boolean | No | 収入カテゴリフラグ | デフォルト: false |
| hidden | boolean | No | 非表示フラグ | デフォルト: false |

#### カテゴリ更新

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string | Yes | カテゴリID | 存在するカテゴリID |
| name | string | Yes | カテゴリ名 | 空文字不可 |
| is_income | boolean | Yes | 収入カテゴリフラグ | - |
| group | string | Yes | 所属グループID | - |

#### カテゴリ削除

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | string | Yes | 削除対象カテゴリID | 存在するカテゴリID |
| transferId | string | No | 移行先カテゴリID | 存在するカテゴリID |

### 入力データソース

- 画面入力（予算画面、カテゴリ管理）
- API（外部システムからの呼び出し）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | カテゴリID（UUID） |
| name | string | カテゴリ名 |
| is_income | boolean | 収入カテゴリフラグ |
| group | string | 所属グループID |
| goal_def | string | ゴール定義（オプション） |
| sort_order | number | 表示順序 |
| hidden | boolean | 非表示フラグ |

### 出力先

- データベース（categoriesテーブル、category_mappingテーブル）

## 処理フロー

### 処理シーケンス

```
【カテゴリ作成】
1. カテゴリ名入力
2. 所属グループ選択
3. バリデーション（名前の一意性チェック）
4. sort_order計算（グループ内の先頭に挿入）
5. categoriesテーブルにINSERT
6. category_mappingテーブルにINSERT（自己参照）

【カテゴリ削除】
1. 削除対象カテゴリ選択
2. 移行要否チェック（must-category-transfer）
3. 移行先カテゴリ選択（必要な場合）
4. 予算値の移行（必要な場合）
5. category_mappingの更新
6. categoriesテーブルでtombstone=1に更新
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{操作種別}
    B -->|作成| C[カテゴリ名入力]
    B -->|更新| D[カテゴリ選択]
    B -->|削除| E[削除対象選択]

    C --> F[グループ選択]
    F --> G{名前重複チェック}
    G -->|重複| H[エラー表示]
    G -->|OK| I[sort_order計算]
    I --> J[INSERT実行]
    J --> K[mapping INSERT]

    D --> L[名前変更]
    L --> M{名前重複チェック}
    M -->|重複| H
    M -->|OK| N[UPDATE実行]

    E --> O{移行要否?}
    O -->|要| P[移行先選択]
    O -->|不要| R[DELETE実行]
    P --> Q[予算移行]
    Q --> R

    H --> Z[終了]
    K --> Z
    N --> Z
    R --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | グループ内名前一意 | 同一グループ内でカテゴリ名は一意でなければならない | 作成・更新時 |
| BR-02 | 必須フィールド | name、cat_group（groupId）は必須 | 作成時 |
| BR-03 | 削除時移行 | 取引や予算値がある場合、削除時に移行先の指定が推奨される | 削除時 |
| BR-04 | 同タイプ移行 | 移行先カテゴリは同じis_incomeタイプでなければならない | 削除時 |
| BR-05 | ソート順序 | 新規作成時はグループ内の先頭に配置（最小のsort_order） | 作成時 |

### 計算ロジック

**sort_order計算**（新規作成時）:
```typescript
// グループ内の既存カテゴリを取得し、先頭に挿入するためのsort_orderを計算
const categories = await all(`SELECT id, sort_order FROM categories WHERE cat_group = ? AND tombstone = 0`, [groupId]);
const { updates, sort_order } = shoveSortOrders(categories, categories[0]?.id || null);
// updatesの各カテゴリのsort_orderを更新後、新規カテゴリにsort_orderを設定
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| カテゴリ作成 | categories | INSERT | 新規カテゴリを追加 |
| カテゴリ作成 | category_mapping | INSERT | マッピングエントリを追加（自己参照） |
| カテゴリ更新 | categories | UPDATE | カテゴリ情報を更新 |
| カテゴリ削除 | categories | UPDATE(tombstone) | カテゴリを論理削除 |
| カテゴリ削除 | category_mapping | UPDATE | transferIdを更新 |

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

#### categories

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name, cat_group, is_income, hidden, sort_order | 入力値、計算値 | - |
| UPDATE | name, is_income, cat_group | 更新値 | - |
| UPDATE | tombstone | 1 | 削除時 |

#### category_mapping

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id, transferId | 新規ID, 同一ID | 自己参照 |
| UPDATE | transferId | 移行先カテゴリID | 削除時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| category-exists | 重複エラー | 同一グループ内に同名カテゴリが存在 | 別の名前を使用 |
| no-categories | 存在エラー | 指定されたカテゴリが存在しない | 正しいIDを指定 |
| category-type | タイプ不一致 | 移行先カテゴリのis_incomeが異なる | 同タイプのカテゴリを選択 |

### リトライ仕様

エラー発生時、ユーザーが入力を修正して再実行する。

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

- カテゴリ操作はundoable（元に戻す対応）
- batchMessagesでバッチ処理（特に削除時の移行処理）
- 削除時は予算値移行とカテゴリ削除を同一トランザクションで実行

## パフォーマンス要件

- カテゴリ一覧の取得は高速であること
- 削除時の移行処理は取引数に応じた適切な時間で完了すること

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

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

## 備考

- API経由でのカテゴリ操作: createCategory, updateCategory, deleteCategory
- hidden=trueのカテゴリは一覧表示から除外される（カテゴリ非表示機能）

---

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

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

### 推奨読解順序

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

カテゴリの型定義を理解する。

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

**読解のコツ**:
- **3-13行目**: CategoryEntityの全フィールド
- `group`: カテゴリグループへの参照（外部キー）
- `hidden`: 非表示フラグ
- `goal_def`: ゴール定義（オプション）

#### Step 2: モデルとバリデーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | models.ts | `packages/loot-core/src/server/models.ts` | categoryModelの実装 |

**主要処理フロー**:
1. **77-110行目**: categoryModelの定義
2. **78-91行目**: validate関数 - 必須フィールドチェック
3. **92-100行目**: toDb関数 - エンティティからDB形式への変換
4. **102-109行目**: fromDb関数 - DB形式からエンティティへの変換

#### Step 3: 予算APIハンドラを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | app.ts | `packages/loot-core/src/server/budget/app.ts` | カテゴリCRUD処理 |

**主要処理フロー**:
1. **278-299行目**: createCategory関数
2. **301-321行目**: updateCategory関数
3. **323-335行目**: moveCategory関数
4. **337-387行目**: deleteCategory関数
5. **451-478行目**: isCategoryTransferRequired関数

#### Step 4: データベース操作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | db/index.ts | `packages/loot-core/src/server/db/index.ts` | カテゴリDB操作 |

**主要処理フロー**:
- **435-488行目**: insertCategory関数 - ソート順序計算と挿入
- **490-500行目**: updateCategory関数
- **502-521行目**: moveCategory関数
- **523-547行目**: deleteCategory関数 - マッピング更新と論理削除

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

```
UI (予算画面)
    │
    ├─ send('category-create')
    │      └─ app.ts: createCategory
    │             └─ db.insertCategory
    │                    ├─ 重複チェック
    │                    ├─ sort_order計算
    │                    ├─ INSERT categories
    │                    └─ INSERT category_mapping
    │
    ├─ send('category-update')
    │      └─ app.ts: updateCategory
    │             └─ db.updateCategory
    │
    └─ send('category-delete')
           └─ app.ts: deleteCategory
                  ├─ タイプチェック
                  ├─ budget.doTransfer (予算移行)
                  └─ db.deleteCategory
                         ├─ UPDATE category_mapping
                         └─ UPDATE categories (tombstone)
```

### データフロー図

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

name ─────────┐
              │
groupId ──────┼──▶ createCategory ──▶ categories テーブル
              │         │                    │
isIncome ─────┘         └──────────────▶ category_mapping テーブル


id ───────────┐
              │
transferId ───┼──▶ deleteCategory ──▶ categories (tombstone=1)
              │         │                    │
              │         └──────────────▶ category_mapping (transferId)
              │                              │
              └──▶ doTransfer ─────────▶ 予算値移行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| category.ts | `packages/loot-core/src/types/models/category.ts` | 型定義 | カテゴリデータ型 |
| models.ts | `packages/loot-core/src/server/models.ts` | ソース | カテゴリモデル・バリデーション |
| app.ts | `packages/loot-core/src/server/budget/app.ts` | ソース | カテゴリAPIハンドラ |
| db/index.ts | `packages/loot-core/src/server/db/index.ts` | ソース | データベース操作 |
| methods.ts | `packages/api/methods.ts` | ソース | 外部API（createCategory等） |
| sort.ts | `packages/loot-core/src/server/db/sort.ts` | ソース | ソート順序計算ユーティリティ |
