# 機能設計書 7-パーツカテゴリ表示

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおけるパーツカテゴリ表示機能の設計を記載する。パーツカテゴリの階層構造を表示・ナビゲートする機能を提供する。

### 本機能の処理概要

InvenTreeのパーツカテゴリ階層構造を表示し、ユーザーがカテゴリ間をナビゲートできる機能である。トップレベルカテゴリから下位カテゴリへのドリルダウン、親カテゴリへの遷移が可能。

**業務上の目的・背景**：在庫管理において、パーツは通常カテゴリ階層で整理される（例：電子部品 > 抵抗器 > SMD抵抗）。この階層構造を直感的にナビゲートできることで、目的のパーツを効率的に見つけることができる。

**機能の利用シーン**：パーツ検索時のカテゴリブラウズ、特定カテゴリ配下のパーツ一覧確認、カテゴリ構造の確認、新規パーツ作成時のカテゴリ選択などで利用される。

**主要な処理内容**：
1. カテゴリ情報の表示（名前、説明、パーツ数）
2. サブカテゴリ一覧の表示（ページネーション対応）
3. カテゴリ内パーツ一覧の表示（タブ切り替え）
4. 親カテゴリへの遷移
5. カテゴリの編集（権限あり時）
6. 新規カテゴリ・パーツの作成

**関連システム・外部連携**：InvenTree REST API（part/category/エンドポイント）

**権限による制御**：partロールのview権限が必要。編集にはchange権限、作成にはadd権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ホーム画面 | 遷移元画面 | パーツタイル押下時にパーツカテゴリ画面へ遷移 |
| 2 | ドロワーメニュー | 遷移元画面 | パーツメニュー押下時にパーツカテゴリ画面へ遷移 |
| 20 | 部品カテゴリ画面 | 主画面 | パーツカテゴリの階層構造表示・ナビゲート |
| 22 | 部品詳細画面 | 遷移先画面 | パーツ選択時にパーツ詳細画面へ遷移 |

## 機能種別

データ参照 / 階層ナビゲーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| category | InvenTreePartCategory? | No | 表示対象のカテゴリ（nullでトップレベル） | - |
| parent | int/String | No | 親カテゴリID（サブカテゴリ一覧用、"null"でトップレベル） | 整数または"null" |
| cascade | bool | No | サブカテゴリを含むか（デフォルト: false） | true/false |

### 入力データソース

- 画面遷移時に渡されるカテゴリオブジェクト
- サブカテゴリ選択による遷移

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| category | InvenTreePartCategory? | 現在表示中のカテゴリ |
| subcategories | List<InvenTreePartCategory> | サブカテゴリ一覧 |
| parts | List<InvenTreePart> | カテゴリ内パーツ一覧 |

### 出力先

- UI（2タブ構成：詳細タブ、パーツタブ）

## 処理フロー

### 処理シーケンス

```
1. カテゴリ画面表示
   └─ カテゴリ情報のリロード（nullでない場合）

2. タブ構成
   └─ 詳細タブ：カテゴリ情報 + サブカテゴリ一覧
   └─ パーツタブ：カテゴリ内パーツ一覧

3. 詳細タブ表示
   └─ カテゴリ説明カード
   └─ 親カテゴリへのリンク（トップレベル以外）
   └─ サブカテゴリ一覧（PaginatedPartCategoryList）

4. パーツタブ表示
   └─ カテゴリ内パーツ一覧（PaginatedPartList）

5. ユーザーアクション
   └─ サブカテゴリタップ → 該当カテゴリ画面へ遷移
   └─ 親カテゴリタップ → 親カテゴリ画面へ遷移
   └─ パーツタップ → パーツ詳細画面へ遷移
   └─ 編集ボタン → カテゴリ編集ダイアログ
   └─ 追加ボタン → 新規パーツ/カテゴリ作成
```

### フローチャート

```mermaid
flowchart TD
    A[カテゴリ画面表示] --> B{category != null?}
    B -->|Yes| C[カテゴリリロード]
    B -->|No| D[トップレベル表示]
    C --> E{リロード成功?}
    E -->|No| F[前画面に戻る]
    E -->|Yes| G[タブ構成]
    D --> G
    G --> H[詳細タブ]
    G --> I[パーツタブ]
    H --> J[カテゴリ情報表示]
    J --> K[サブカテゴリ一覧]
    I --> L[パーツ一覧]
    K --> M{ユーザー操作}
    M -->|サブカテゴリ| N[カテゴリ画面遷移]
    M -->|親カテゴリ| O[親カテゴリ画面遷移]
    L --> P{ユーザー操作}
    P -->|パーツ| Q[パーツ詳細遷移]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | トップレベル表示 | category=nullの場合、「トップレベルカテゴリ」として表示 | カテゴリなし時 |
| BR-02 | サブカテゴリフィルタ | parent=nullでAPIv174未満のみnullフィルタ | サブカテゴリ取得時 |
| BR-03 | パーツカウント表示 | part_count（またはparts）でパーツ数表示 | カテゴリ表示時 |
| BR-04 | パス表示 | pathstringでカテゴリのフルパスを表示 | サブカテゴリ一覧時 |

### 計算ロジック

**親パス表示ロジック**:
```
pathstring.split("/")
  → 最後の要素を除去
  → "/"で結合
  → 空の場合は「トップレベルカテゴリ」
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧取得 | - | - | サーバーAPIからのみ取得（ローカルDB操作なし） |

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

ローカルデータベース操作なし。サーバーAPIからのデータ取得のみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | リロード失敗 | カテゴリが削除されている等 | 前画面に戻る |
| 401/403 | 認証/権限エラー | partロールなし | エラーメッセージ表示 |
| 404 | 未検出エラー | カテゴリが存在しない | 前画面に戻る |

### リトライ仕様

- プルリフレッシュによる手動リトライ

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

- 読み取り専用（トランザクションなし）

## パフォーマンス要件

- サブカテゴリ・パーツ一覧はページネーション対応
- サムネイル画像はキャッシュ利用

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

- partロールのview権限が必要
- 編集ボタンはcanEditの場合のみ表示
- 作成ボタンはcanCreateの場合のみ表示

## 備考

- 2タブ構成：詳細タブ（サブカテゴリ）、パーツタブ
- アクションボタン：新規パーツ作成、新規カテゴリ作成
- カスタムアイコン対応（category.customIcon）

---

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

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

### 推奨読解順序

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

まず、パーツカテゴリモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | part.dart | `lib/inventree/part.dart` | InvenTreePartCategoryクラス（20-82行目） |

**読解のコツ**:
- **27行目**: URL定義（"part/category/"）
- **56行目**: `pathstring` - カテゴリのフルパス
- **58-72行目**: `parentPathString` - 親パスの計算
- **76-78行目**: `partcount` - パーツ数（API互換性対応）

#### Step 2: カテゴリ表示ウィジェットを理解する

カテゴリ表示画面の全体構造を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | category_display.dart | `lib/widget/part/category_display.dart` | CategoryDisplayWidgetクラス（17-258行目） |

**主要処理フロー**:
- **100-115行目**: `request`メソッド - カテゴリリロード
- **117-175行目**: `getCategoryDescriptionCard` - カテゴリ情報カード
- **177-186行目**: `getTabIcons`/`getTabs` - 2タブ構成
- **188-208行目**: `detailTiles` - 詳細タブ構築
- **210-217行目**: `partsTiles` - パーツタブ構築

#### Step 3: アクションボタンを理解する

新規作成アクションを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | category_display.dart | `lib/widget/part/category_display.dart` | actionButtonsメソッド（54-80行目） |
| 3-2 | category_display.dart | `lib/widget/part/category_display.dart` | _newCategoryメソッド（219-239行目） |
| 3-3 | category_display.dart | `lib/widget/part/category_display.dart` | _newPartメソッド（241-257行目） |

**主要処理フロー**:
- **57-65行目**: 新規パーツ作成ボタン（canCreate時）
- **67-78行目**: 新規カテゴリ作成ボタン（canCreate時）
- **219-239行目**: カテゴリ作成フォーム呼び出し
- **241-257行目**: パーツ作成フォーム呼び出し

#### Step 4: サブカテゴリ一覧を理解する

サブカテゴリ一覧ウィジェットを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | category_list.dart | `lib/widget/part/category_list.dart` | PaginatedPartCategoryListクラス（33-114行目） |

**主要処理フロー**:
- **52-63行目**: `filterOptions` - cascadeフィルタ
- **65-83行目**: `orderingOptions` - ソートオプション
- **85-98行目**: `requestPage` - API呼び出し
- **100-113行目**: `buildItem` - カテゴリListTile構築

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

```
CategoryDisplayWidget
    │
    ├─ request(context)
    │      └─ category.reload() [category != null時]
    │
    ├─ getTabs()
    │      ├─ detailTiles()
    │      │      ├─ getCategoryDescriptionCard()
    │      │      └─ PaginatedPartCategoryList(parent: category.pk)
    │      │
    │      └─ partsTiles()
    │             └─ PaginatedPartList(category: category.pk)
    │
    ├─ actionButtons()
    │      ├─ _newPart()
    │      │      └─ InvenTreePart().createForm()
    │      │
    │      └─ _newCategory()
    │             └─ InvenTreePartCategory().createForm()
    │
    └─ appBarActions()
           └─ _editCategoryDialog()
                  └─ category.editForm()
```

### データフロー図

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

InvenTreePartCategory ───▶ CategoryDisplayWidget ───▶ UI表示
    │                           │                       │
    ├─ pk                      ├─ reload()              ├─ 詳細タブ
    ├─ name                    ├─ getCategoryCard()     │    ├─ カテゴリ情報
    ├─ pathstring              └─ getSubcategories()    │    └─ サブカテゴリ
    └─ parentId                                         │
                                                        └─ パーツタブ
                                                             └─ パーツ一覧
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| category_display.dart | `lib/widget/part/category_display.dart` | ソース | カテゴリ表示画面ウィジェット |
| category_list.dart | `lib/widget/part/category_list.dart` | ソース | サブカテゴリ一覧ウィジェット |
| part.dart | `lib/inventree/part.dart` | ソース | InvenTreePartCategoryモデル |
| part_list.dart | `lib/widget/part/part_list.dart` | ソース | パーツタブのパーツ一覧 |
| refreshable_state.dart | `lib/widget/refreshable_state.dart` | ソース | 基底State（タブ対応） |
| link_icon.dart | `lib/widget/link_icon.dart` | ソース | リンクアイコン、LargeText |
| progress.dart | `lib/widget/progress.dart` | ソース | ローディングオーバーレイ |
