# 画面設計書 29-タグ管理画面

## 概要

本ドキュメントは、Actual Budgetアプリケーションにおけるタグ管理画面の設計仕様を定義するものである。

### 本画面の処理概要

取引に付与するタグの一覧表示・作成・編集・削除を行う管理画面である。タグには名前、色、説明を設定でき、取引の分類やフィルタリングに活用できる。また、既存の取引から未登録のタグを検出して自動登録する機能も提供する。

**業務上の目的・背景**：カテゴリとは別に、取引に対して柔軟なラベル付けを行いたいニーズに応える機能である。例えば「旅行」「税控除対象」「確認済み」などのタグを取引に付与することで、カテゴリの枠を超えた分類・分析が可能になる。タグには色を設定できるため、視覚的な識別も容易である。

**画面へのアクセス方法**：サイドバーの「Tags」メニュー、またはコマンドバーから `/tags` ルートに遷移することでアクセスする。デスクトップ・モバイル両対応の共通画面。

**主要な操作・処理内容**：
1. タグ一覧の表示（フィルタリング対応）
2. 新規タグの作成（名前、色、説明の設定）
3. 既存タグの編集（インライン編集）
4. タグの一括削除（複数選択対応）
5. 既存取引からの未登録タグ検出・自動登録

**画面遷移**：
- 遷移元：サイドバー、コマンドバー
- 遷移先：なし（すべてインラインまたはモーダルで処理）

**権限による表示制御**：特別な権限制御は設けられていない。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 63 | タグ管理 | 主機能 | 取引タグの一覧表示・作成・編集・削除 |

## 画面種別

一覧

## URL/ルーティング

`/tags`

- デスクトップ・モバイル両対応（レスポンシブ）
- 同一のコンポーネント（`ManageTagsPage` → `ManageTags`）を使用

## 入出力項目

| 項目名 | 項目ID | データ型 | 入力/出力 | 必須 | 説明 |
|--------|--------|----------|-----------|------|------|
| 検索フィルタ | filter | string | 入力 | 任意 | タグ名での検索フィルタ |
| 選択タグ | selectedItems | Set<string> | 入力 | 任意 | 削除対象として選択されたタグのID集合 |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| ヘッダータイトル | string | "Tags" と表示 |
| ガイダンステキスト | string | "User defined tags with color and description." |
| 新規追加ボタン | button | 新規タグ作成行を表示 |
| 既存タグ検出ボタン | button | 取引から未登録タグを検出 |
| 検索フィールド | input | タグ検索用入力フィールド |
| タグヘッダー | component | タグ一覧のカラムヘッダー |
| タグ一覧 | list | タグ名、色、説明を含むタグ行 |
| 削除ボタン | button | 選択したタグの一括削除 |
| 空状態メッセージ | text | タグが存在しない場合のメッセージ |

## イベント仕様

### 1-画面初期表示

画面表示時にタグ一覧をReduxストアから取得する。

**処理フロー**:
1. `useTags()` フックでタグ一覧を取得
2. `filteredTags` でフィルタ適用（初期状態はフィルタなし）
3. `useSelected` で選択状態を管理

### 2-タグ検索

検索フィールドへの入力でタグをフィルタリングする。

**処理フロー**:
1. `onChange` イベントで `filter` ステートを更新
2. タグ名との正規化部分一致でフィルタリング
3. `filteredTags` を再計算

### 3-新規タグ作成

「Add New」ボタン押下時にタグ作成行を表示する。

**処理フロー**:
1. `create` ステートを `true` に設定
2. `TagCreationRow` コンポーネントを表示
3. タグ名、色、説明を入力
4. 保存時に `tags-add` API を呼び出し
5. 成功時に `create` ステートを `false` に設定、一覧を更新

### 4-既存タグ検出

「Find Existing Tags」ボタン押下時に取引から未登録タグを検出する。

**処理フロー**:
1. `findTags()` アクションをディスパッチ
2. サーバー側で取引のノートフィールドからハッシュタグ形式のタグを検出
3. 未登録のタグを自動的に作成
4. 一覧を更新

### 5-タグ一括削除

選択されたタグを一括削除する。

**処理フロー**:
1. `onDeleteSelected` を呼び出し
2. `deleteAllTags([...selectedInst.items])` アクションをディスパッチ
3. 選択状態をクリア

### 6-タグ編集

タグ行でインライン編集を行う。

**処理フロー**:
1. タグ行のフィールドを編集
2. フォーカスアウト時またはEnter押下時に保存
3. `tags-update` API を呼び出し

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 新規作成 | tags | INSERT | タグの新規登録 |
| 編集保存 | tags | UPDATE | タグの更新 |
| 削除 | tags | DELETE | タグの削除 |
| 一括削除 | tags | DELETE | 複数タグの削除 |

### テーブル別更新項目詳細

#### tags

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | UUID自動生成 | 一意識別子 |
| INSERT | tag | タグ名 | 必須 |
| INSERT | color | 色コード | 任意 |
| INSERT | description | 説明 | 任意 |
| UPDATE | tag | 編集後のタグ名 | WHERE id = :id |
| UPDATE | color | 編集後の色 | WHERE id = :id |
| UPDATE | description | 編集後の説明 | WHERE id = :id |
| DELETE | - | WHERE id = :id | 指定IDのタグを削除 |
| DELETE | - | WHERE id IN (:ids) | 複数IDのタグを削除 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG-001 | ガイダンス | "User defined tags with color and description." | 常時表示 |
| MSG-002 | 空状態 | "No Tags" | タグが存在しない場合 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| タグ重複 | エラー通知を表示（同名タグは作成不可） |

## 備考

- タグはハッシュタグ形式（#タグ名）で取引のノートに記載することで自動検出可能
- 色はカラーピッカーで選択可能
- タグの削除は取引からタグ情報を削除しない（タグ定義のみ削除）

---

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

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

### 推奨読解順序

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

タグデータの型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models/index.d.ts | `packages/loot-core/src/types/models/index.d.ts` | TagEntity型の定義（id, tag, color, description） |

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

ページコンポーネントの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ManageTagsPage.tsx | `packages/desktop-client/src/components/tags/ManageTagsPage.tsx` | シンプルなページラッパー |
| 2-2 | ManageTags.tsx | `packages/desktop-client/src/components/tags/ManageTags.tsx` | メインロジック |

**主要処理フロー**:
1. **28-34行目**: コンポーネント定義とステート初期化
2. **36-42行目**: filteredTags計算
3. **44行目**: useSelectedによる選択状態管理
4. **46-49行目**: onDeleteSelected関数
5. **51-141行目**: JSXレンダリング

#### Step 3: サブコンポーネントを理解する

タグ一覧と作成行の実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TagsHeader.tsx | `packages/desktop-client/src/components/tags/TagsHeader.tsx` | ヘッダー行 |
| 3-2 | TagsList.tsx | `packages/desktop-client/src/components/tags/TagsList.tsx` | タグ一覧 |
| 3-3 | TagCreationRow.tsx | `packages/desktop-client/src/components/tags/TagCreationRow.tsx` | 新規作成行 |

#### Step 4: Reduxアクションを理解する

タグ操作のReduxアクションを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | tagsSlice.ts | `packages/desktop-client/src/tags/tagsSlice.ts` | findTags, deleteAllTags等のアクション |

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

```
ManageTagsPage
    │
    └─ ManageTags
           │
           ├─ useTags()
           │      └─ Redux store からタグ一覧取得
           │
           ├─ useSelected('manage-tags')
           │      └─ 複数選択機能
           │
           ├─ TagsHeader
           │      └─ カラムヘッダー表示
           │
           ├─ TagCreationRow (create === true の場合)
           │      └─ 新規タグ入力UI
           │
           ├─ TagsList
           │      └─ 各タグ行の表示・編集
           │
           ├─ Add New ボタン
           │      └─ setCreate(true)
           │
           ├─ Find Existing Tags ボタン
           │      └─ dispatch(findTags())
           │
           └─ Delete ボタン
                  └─ dispatch(deleteAllTags())
```

### データフロー図

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

Redux Store ─────────▶ useTags() ────────────────────────▶ tags
(tags)                       │
                             ▼
filter入力 ──────────▶ getNormalisedString() ─────────────▶ filteredTags
                       + 文字列マッチング
                             │
                             ▼
                       TagsList
                             │
タグ編集 ────────────▶ tags-update API ───────────────────▶ Redux Store 更新
                             │
Add New押下 ─────────▶ TagCreationRow ───────────────────▶ tags-add API
                             │
Find Existing ───────▶ dispatch(findTags()) ─────────────▶ 未登録タグ作成
                             │
Delete押下 ──────────▶ dispatch(deleteAllTags()) ────────▶ タグ削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ManageTagsPage.tsx | `packages/desktop-client/src/components/tags/ManageTagsPage.tsx` | ソース | ページコンポーネントラッパー |
| ManageTags.tsx | `packages/desktop-client/src/components/tags/ManageTags.tsx` | ソース | タグ管理メインロジック |
| TagsHeader.tsx | `packages/desktop-client/src/components/tags/TagsHeader.tsx` | ソース | ヘッダーコンポーネント |
| TagsList.tsx | `packages/desktop-client/src/components/tags/TagsList.tsx` | ソース | タグ一覧コンポーネント |
| TagCreationRow.tsx | `packages/desktop-client/src/components/tags/TagCreationRow.tsx` | ソース | 新規作成行コンポーネント |
| tagsSlice.ts | `packages/desktop-client/src/tags/tagsSlice.ts` | ソース | Reduxアクション・リデューサー |
| useTags.ts | `packages/desktop-client/src/hooks/useTags.ts` | ソース | タグ取得フック |
| useSelected.ts | `packages/desktop-client/src/hooks/useSelected.ts` | ソース | 複数選択フック |
| Search.tsx | `packages/desktop-client/src/components/common/Search.tsx` | ソース | 検索入力コンポーネント |
| FinancesApp.tsx | `packages/desktop-client/src/components/FinancesApp.tsx` | ソース | ルーティング定義（310行目） |
