# 機能設計書 56-ノート表示・編集

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおけるノート表示・編集機能の設計を記述する。

### 本機能の処理概要

パーツ、在庫アイテム、発注、受注などの各種アイテムに関連付けられたノート（メモ）をMarkdown形式で表示し、編集できる機能を提供する。

**業務上の目的・背景**：在庫管理において、パーツや在庫アイテムに関する補足情報、注意事項、作業手順などのメモを記録することは重要である。ノート機能により、データシートでは表現できない情報を自由形式で記録でき、チーム間での情報共有が促進される。Markdown形式をサポートすることで、リッチなフォーマット（見出し、リスト、リンク等）で情報を整理できる。

**機能の利用シーン**：パーツ詳細画面、在庫アイテム詳細画面、発注詳細画面、受注詳細画面などで、ノート項目をタップしてノート画面へ遷移する。ノート画面で既存のノートを閲覧し、編集ボタンから内容を編集する。

**主要な処理内容**：
1. 対象モデルのノート（notes属性）を取得・表示する
2. Markdownパーサーで整形表示する
3. 編集ボタンで編集フォームを表示する
4. 保存時にモデルのnotes属性を更新する

**関連システム・外部連携**：InvenTree REST API（各モデルのエンドポイント）との通信を行う。

**権限による制御**：認証済みユーザーのみがアクセス可能。model.canEditに基づき編集ボタンの表示/非表示を制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | 部品詳細画面 | 遷移先機能 | ノート項目押下時にノート画面へ遷移 |
| 25 | 在庫アイテム詳細画面 | 遷移先機能 | ノート項目押下時にノート画面へ遷移 |
| 27 | 購入注文詳細画面 | 遷移先機能 | ノート項目押下時にノート画面へ遷移 |
| 29 | 販売注文詳細画面 | 遷移先機能 | ノート項目押下時にノート画面へ遷移 |

## 機能種別

CRUD操作（Read / Update）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| model | InvenTreeModel | Yes | 対象モデルインスタンス | notesプロパティを持つこと |

### 入力データソース

- InvenTreeModel.notes属性（モデルから取得）
- ユーザー入力（編集時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| notes | String | ノート内容（Markdown形式） |

### 出力先

- 画面表示（Markdown形式でレンダリング）
- サーバーAPI（編集時にモデル更新）

## 処理フロー

### 処理シーケンス

```
1. 画面初期化
   └─ NotesWidget生成、modelパラメータ受け取り
2. データ取得
   └─ request()でmodel.reload()呼び出し
3. ノート表示
   └─ getBody()でMarkdownウィジェット表示
4. 編集操作（canEdit=trueの場合）
   └─ appBarActionsで編集ボタン表示
5. 編集フォーム表示
   └─ model.editForm()でAPIフォーム起動
6. 保存実行
   └─ onSuccess後にrefresh()
```

### フローチャート

```mermaid
flowchart TD
    A[ノート項目タップ] --> B[NotesWidget表示]
    B --> C[request実行]
    C --> D[model.reload]
    D --> E[getBody実行]
    E --> F[Markdownウィジェット表示]
    F --> G{canEdit?}
    G -->|Yes| H[編集ボタン表示]
    G -->|No| I[閲覧のみ]
    H --> J{編集ボタンタップ?}
    J -->|Yes| K[editForm起動]
    K --> L[ノート編集フォーム]
    L --> M{保存?}
    M -->|Yes| N[PATCH APIリクエスト]
    N --> O[refresh]
    M -->|No| P[キャンセル]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-56-01 | 権限チェック | model.canEditがtrueの場合のみ編集ボタン表示 | UI表示時 |
| BR-56-02 | Markdown表示 | ノート内容はMarkdown形式でレンダリング | 表示時 |
| BR-56-03 | マルチライン入力 | 編集フォームはマルチラインテキストフィールド | 編集時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ノート取得 | 各モデルテーブル | SELECT | モデルのnotes属性取得 |
| ノート更新 | 各モデルテーブル | UPDATE | モデルのnotes属性更新 |

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

#### 各モデル（リモートAPI）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | notes | モデル詳細取得時 | reload() |
| UPDATE | notes | ユーザー入力値 | PATCH {url}/ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 接続エラー | サーバー未接続時 | 接続ステータスを表示 |
| 403 | 権限エラー | 編集権限なし | 編集ボタンを非表示 |
| 404 | NotFound | モデルが削除済み | エラーメッセージ表示 |

### リトライ仕様

プルダウンリフレッシュによる手動リトライが可能

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

単一フィールドの更新のためトランザクション制御はサーバー側で管理

## パフォーマンス要件

- ノート表示は1秒以内
- 編集保存は2秒以内

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

- 認証トークンによるアクセス制御
- ロールベースの編集権限チェック
- HTTPS通信による通信暗号化

## 備考

flutter_markdownパッケージを使用してMarkdownレンダリングを実現。

---

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

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

### 推奨読解順序

#### Step 1: ウィジェット構造を理解する

ノート表示ウィジェットの構造を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | notes_widget.dart | `lib/widget/notes_widget.dart` | NotesWidget、_NotesStateクラス |

**読解のコツ**: NotesWidgetはシンプルな構造。modelパラメータを受け取り、notes属性を表示・編集する。

**主要処理フロー**:
- **15-22行目**: NotesWidgetクラス定義、コンストラクタ
- **27-28行目**: _NotesStateクラス定義、RefreshableState継承
- **31-33行目**: request()でmodel.reload()
- **35-36行目**: getAppBarTitle()でタイトル設定
- **67-69行目**: getBody()でMarkdownウィジェット表示

#### Step 2: 編集ボタン処理を理解する

編集ボタンの表示条件と処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | notes_widget.dart | `lib/widget/notes_widget.dart` | appBarActions()メソッド |

**主要処理フロー**:
- **38-64行目**: appBarActions()メソッド
- **42行目**: model.canEditで権限チェック
- **43-59行目**: 編集ボタンのIconButton定義
- **47-57行目**: onPressedでmodel.editForm()呼び出し

#### Step 3: 編集フォーム処理を理解する

モデルの編集フォーム呼び出しを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | model.dart | `lib/inventree/model.dart` | editForm()、notesプロパティ |

**主要処理フロー**:
- **355行目**: notesプロパティ定義
- **301-320行目**: editForm()メソッド
- **311-318行目**: launchApiForm()でPATCHリクエスト

#### Step 4: ノート取得元を理解する

各モデルのnotes属性がどこで定義されているかを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | model.dart | `lib/inventree/model.dart` | getString()、notesプロパティ |

**主要処理フロー**:
- **120-128行目**: getString()ヘルパーメソッド
- **355行目**: notes プロパティ（getString("notes")を返す）

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

```
NotesWidget (notes_widget.dart)
    │
    └─ _NotesState
           │
           ├─ request()
           │      └─ widget.model.reload()
           │             └─ InvenTreeModel.reload() (model.dart)
           │                    └─ InvenTreeAPI.get() (api.dart)
           │
           ├─ getBody()
           │      └─ Markdown(data: widget.model.notes)
           │
           └─ appBarActions()
                  │
                  └─ (canEdit=true)
                         └─ IconButton
                                └─ onPressed
                                       └─ widget.model.editForm()
                                              └─ launchApiForm()
                                                     ├─ APIフォーム表示
                                                     └─ PATCH {model.url}
                                                            └─ onSuccess
                                                                   └─ refresh()
```

### データフロー図

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

ノート項目タップ  ───▶  NotesWidget               ───▶  ノート画面
                          │
                          ├─ request()
                          │      └─ model.reload()
                          │             └─ GET {model.url}
                          │
                          ▼
API応答         ◀───  model.notes               ───▶  Markdown表示
                          │
                          ▼
編集ボタンタップ ───▶  model.editForm()           ───▶  編集フォーム
                          │
                          ├─ fields: {notes: {multiline: true}}
                          │
                          ▼
保存ボタン      ───▶  PATCH {model.url}          ───▶  ノート更新
                          │
                          ├─ body: {notes: "新しい内容"}
                          │
                          ▼
                   onSuccess
                          │
                          └─ refresh()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| notes_widget.dart | `lib/widget/notes_widget.dart` | ソース | ノート表示・編集ウィジェット |
| model.dart | `lib/inventree/model.dart` | ソース | 基底モデル（notes、editForm） |
| api_form.dart | `lib/api_form.dart` | ソース | APIフォームウィジェット |
| refreshable_state.dart | `lib/widget/refreshable_state.dart` | ソース | リフレッシュ可能な状態管理 |
| flutter_markdown | 外部パッケージ | ライブラリ | Markdownレンダリング |
