diff --git a/改善案/TODO管理機能仕様書案.md b/改善案/TODO管理機能仕様書案.md new file mode 100644 index 0000000..e190b20 --- /dev/null +++ b/改善案/TODO管理機能仕様書案.md @@ -0,0 +1,650 @@ +# TODO管理機能仕様書案 + +> 作成日: 2026-04-09 +> 対象プロジェクト: `keinasystem` +> 対象 Issue: `akira/keinasystem#17` +> 位置づけ: 実装前ドラフト + +--- + +## 1. 概要 + +繁忙期の作業を「どれから手を付けるか」の観点で整理するため、Redmine チケットライクな TODO 管理機能を追加する。 + +本機能は単なるメモではなく、以下の中間レイヤーとして位置付ける。 + +- 計画 +- TODO +- 実績 + +将来的には、作付け計画を除く各種計画について、`計画 -> TODO -> 実績` の流れに挟める構造を目指す。 +ただし MVP では、まず TODO 管理の基本機能、対象圃場の管理、計画との紐づけ、完了時の実績連携導線を整備する。 + +--- + +## 2. 背景 + +現状は施肥計画、田植え計画、運搬計画などの個別機能はあるが、「今日やること」「今週先に処理すべきこと」を横断的に管理する仕組みがない。 + +そのため、繁忙期には以下の問題が起こりやすい。 + +- 作業の優先順位が頭の中や紙メモに依存する +- 計画の一部だけを先に実行したい場合に管理しづらい +- 実績入力までの間に「作業待ち」「着手中」の状態を置けない +- 将来追加される作業系機能を共通の入口で扱えない + +TODO 管理を導入し、計画単位ではなく「実際に動く作業単位」で優先順位と進行状態を管理できるようにする。 + +--- + +## 3. 目的 + +### 3.1 目指す状態 + +- 未着手・進行中の作業を優先順で一覧できる +- TODO は計画に紐づくものと、独立したものの両方を扱える +- 計画に紐づく TODO では、計画全体ではなく一部圃場だけを対象にできる +- 完了時に、必要なものは実績系アプリへ連携できる +- 将来増える作業系アプリでも同じ TODO 基盤を使える + +### 3.2 今回の対象 + +- Django 新規アプリ `apps/todos` +- Next.js 画面 `frontend/src/app/todos` +- REST API `/api/todos/` +- 計画画面からの TODO 生成導線 + +### 3.3 今回やらないこと + +- 期日通知、リマインダー、メール通知 +- 複数ユーザー割り当て +- コメント、添付ファイル +- 工数見積、実績時間記録 +- 完全な汎用ワークフローエンジン化 + +--- + +## 4. 基本方針 + +### 4.1 TODO の位置づけ + +TODO は「作業指示」兼「実行待ちキュー」として扱う。 + +- 計画は年間またはまとまり単位の設計情報 +- TODO は実際に動く単位の作業 +- 実績は実際に完了した事実 + +### 4.2 計画との関係 + +- 1 計画に対して複数 TODO を紐づけられる +- 1 TODO は複数計画を参照できる +- ただし TODO の実際の対象圃場は TODO 側で明示管理する +- 計画に含まれる圃場の一部だけを TODO 対象にすることを許可する + +### 4.3 実績との関係 + +- TODO 完了時に、実績アプリを持つ作業は実績生成の入口にする +- ただし、すべての TODO が実績アプリを持つとは限らない +- 計画なし TODO、実績なし TODO も許容する + +### 4.4 圃場グループの扱い + +圃場グループは独立モデル化しない。 +既存の `Field.group_name` を参照用の属性として扱うにとどめ、TODO の正式な対象管理は圃場単位で保持する。 + +理由: + +- 現状のデータモデルに独立したグループモデルが存在しない +- TODO 完了後に履歴の再現性を保つには、最終的に対象圃場を確定保持した方が安全 + +--- + +## 5. 機能スコープ + +### 5.1 IN + +- TODO の作成、編集、削除 +- ステータス管理 +- 優先順位管理 +- 圃場単位の対象紐づけ +- 作物、品種の補助的な分類紐づけ +- 計画との紐づけ +- 計画画面から TODO を生成 +- 完了済み、キャンセル済みの表示切り替え +- 期日の強調表示 +- 並び替え API + +### 5.2 OUT + +- 通知 +- 担当者管理 +- 承認フロー +- 複数段階ステータス +- 実績アプリ未実装領域の詳細実績入力 UI + +--- + +## 6. 用語整理 + +| 用語 | 意味 | +|---|---| +| TODO | 実際に着手・進行・完了する作業単位 | +| 計画リンク | TODO が参照する施肥計画、田植え計画など | +| 対象圃場 | その TODO で実際に作業対象となる圃場 | +| 実績連携 | TODO 完了時に各実績アプリへ情報を渡すこと | + +--- + +## 7. データモデル方針 + +## 7.1 Todo + +TODO 本体。 + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| title | varchar(200) | ✓ | タイトル | +| description | text | | 説明 | +| status | enum | ✓ | `todo / doing / done / canceled` | +| priority | integer | ✓ | 小さいほど上位 | +| due_date | date | | 期日 | +| work_type | enum | ✓ | 作業種別 | +| reflect_to_record | boolean | ✓ | 完了時に実績連携するか | +| completed_at | datetime | | 完了日時 | +| canceled_at | datetime | | キャンセル日時 | +| created_at | datetime | ✓ | | +| updated_at | datetime | ✓ | | + +### 7.1.1 ステータス + +- `todo`: 未着手 +- `doing`: 進行中 +- `done`: 完了 +- `canceled`: キャンセル + +### 7.1.2 並び順 + +- 基本は FILO とする +- 新規作成時は最上位へ入る +- ユーザーが並び替えた後は `priority` を保存する +- 完了、キャンセル済みも `priority` は保持する +- 一覧のデフォルト表示は `todo / doing` のみを `priority` 昇順で表示する + +### 7.1.3 作業種別 + +作業種別は「計画に対応するもの」と「計画に対応しないもの」の両方を含める。 + +初期案: + +- `general`: 一般 +- `fertilization`: 施肥 +- `rice_transplant`: 田植え +- `delivery`: 運搬 +- `levee_work`: 畔塗 +- `pesticide`: 防除 +- `other_recorded`: 計画非紐づき実績系 + +補足: + +- 実装時点で将来の全計画種別を確定できない場合は、MVP では現行アプリに対応する種別を先行定義する +- `general` はどれにも当てはまらない作業用に必須 + +## 7.2 TodoTargetField + +TODO が実際に対象とする圃場。 + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| todo | FK(Todo) | ✓ | CASCADE | +| field | FK(fields.Field) | ✓ | PROTECT | +| field_name_snapshot | varchar(100) | ✓ | 保存時点の圃場名 | +| group_name_snapshot | varchar(50) | | 保存時点の group_name | +| created_at | datetime | ✓ | | + +- `unique_together = ['todo', 'field']` + +方針: + +- TODO の対象管理は最終的に圃場単位で保持する +- グループ、作物、品種から一括選択する UI は許可する +- ただし保存時は対象圃場へ展開して保持する + +## 7.3 TodoCrop / TodoVariety + +TODO の分類補助用。 + +| モデル | 役割 | +|---|---| +| TodoCrop | 作物ベースの目印、絞り込み、表示補助 | +| TodoVariety | 品種ベースの目印、絞り込み、表示補助 | + +注意: + +- 対象圃場の実体は `TodoTargetField` を正とする +- `Crop` や `Variety` だけ紐づいていて圃場が 0 件の TODO は許可する +- これにより、圃場未確定の準備作業も登録できる + +## 7.4 TodoPlanLink + +TODO と既存計画との紐づけ。 + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| todo | FK(Todo) | ✓ | CASCADE | +| plan_type | enum | ✓ | 計画種別 | +| fertilization_plan | FK | | 施肥計画 | +| rice_transplant_plan | FK | | 田植え計画 | +| delivery_plan | FK | | 運搬計画 | +| levee_work_session | FK | | 畔塗は計画というより実績寄りのため要検討 | +| created_at | datetime | ✓ | | + +方針: + +- 1 行に 1 種別のリンクだけを保持する +- `plan_type` に応じて対応する FK だけを埋める +- MVP は汎用 `GenericForeignKey` を使わず、明示 FK を優先する +- 理由は API と serializer を単純に保ちやすいため + +初期対象: + +- 施肥計画 `FertilizationPlan` +- 田植え計画 `RiceTransplantPlan` +- 運搬計画 `DeliveryPlan` + +補足: + +- 作付け計画 `Plan` は「年内の計画情報」であり、TODO 生成元としては必須ではない +- 当面は Issue 回答に合わせ、`作付け計画以外のすべての計画` を TODO の対象候補とする + +## 7.5 TodoCompletionLink + +完了時の実績連携先を記録する索引。 + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| todo | OneToOne または FK | ✓ | TODO | +| record_type | enum | ✓ | 実績種別 | +| work_record | FK(workrecords.WorkRecord) | | 共通索引 | +| spreading_session | FK(fertilizer.SpreadingSession) | | 施肥実績 | +| rice_transplant_record_id | 将来 | | 田植え実績 | +| created_at | datetime | ✓ | | + +方針: + +- 完了時に何へ連携したかを TODO 側から追えるようにする +- 実績アプリが未実装の種別は空でよい +- 将来の田植え実績導入時に拡張できる形にする + +--- + +## 8. API 仕様案 + +### 8.1 一覧 + +- `GET /api/todos/` + +主な query: + +- `status=todo,doing` +- `include_closed=true|false` +- `work_type=...` +- `due=overdue|today|upcoming` +- `year=2026` + +デフォルト: + +- `include_closed=false` +- `status=todo,doing` +- `priority` 昇順 + +### 8.2 詳細取得 + +- `GET /api/todos/{id}/` + +返却内容: + +- TODO 本体 +- 対象圃場 +- 作物、品種 +- 計画リンク +- 完了連携状況 + +### 8.3 作成 + +- `POST /api/todos/` + +作成 payload 例: + +```json +{ + "title": "西田エリアの追肥", + "description": "週内に先行実施", + "status": "todo", + "due_date": "2026-04-12", + "work_type": "fertilization", + "reflect_to_record": true, + "field_ids": [12, 18, 21], + "crop_ids": [1], + "variety_ids": [4], + "plan_links": [ + {"plan_type": "fertilization", "plan_id": 8} + ] +} +``` + +### 8.4 更新 + +- `PATCH /api/todos/{id}/` + +更新可能項目: + +- タイトル +- 説明 +- ステータス +- 期日 +- 作業種別 +- 実績連携フラグ +- 対象圃場 +- 分類 +- 計画リンク + +### 8.5 削除 + +- `DELETE /api/todos/{id}/` + +ルール案: + +- 連携済み実績がある TODO は物理削除ではなく制限をかける案を優先 +- MVP ではまず `done` かつ実績連携済み TODO の削除可否を要確認とする + +### 8.6 並び替え + +- `PATCH /api/todos/reorder/` + +payload 例: + +```json +{ + "items": [ + {"id": 31, "priority": 10}, + {"id": 27, "priority": 20}, + {"id": 42, "priority": 30} + ] +} +``` + +方針: + +- 一括更新で保存する +- DnD が難しい場合も、矢印移動 UI から同 API を呼ぶ + +### 8.7 計画から TODO 生成 + +- `POST /api/todos/from-plan/` + +payload 例: + +```json +{ + "plan_type": "fertilization", + "plan_id": 8, + "title": "2026春肥の散布", + "field_ids": [12, 18], + "due_date": "2026-04-15", + "reflect_to_record": true +} +``` + +生成ルール: + +- 既存計画をリンクする +- `field_ids` 未指定時は計画内の全圃場を初期対象にする +- `work_type` は `plan_type` から自動補完する +- タイトルは自動生成可能にする + +### 8.8 完了処理 + +- `POST /api/todos/{id}/complete/` + +方針: + +- `status=done` にする専用入口を用意する +- `reflect_to_record=true` かつ対応実績アプリがある場合、関連画面へ遷移するための情報を返す +- MVP で自動実績作成まで行うか、完了導線のみ返すかは実装時に選べるようにする + +--- + +## 9. UI 仕様案 + +## 9.1 一覧画面 `/todos` + +表示内容: + +- 未着手、進行中 TODO を優先表示 +- タイトル +- ステータス +- 期日 +- 作業種別 +- 対象圃場数 +- 紐づき計画 + +操作: + +- 新規作成 +- ステータス変更 +- 並び替え +- 完了済み、キャンセル済み表示切り替え +- 絞り込み + +視覚表現: + +- 期限超過は赤系 +- 当日期限は強調 +- 進行中は目立つバッジ表示 + +## 9.2 詳細画面 `/todos/{id}` + +表示・編集項目: + +- タイトル +- 説明 +- ステータス +- 期日 +- 作業種別 +- 実績連携フラグ +- 対象圃場 +- 分類作物、分類品種 +- 計画リンク + +下部表示: + +- 実績連携先 +- 完了日時 +- 更新日時 + +## 9.3 作成導線 + +MVP では少なくとも以下の 2 導線を持つ。 + +1. TODO 一覧から新規作成 +2. 計画詳細または一覧から TODO 生成 + +## 9.4 計画画面からの導線 + +対象候補: + +- 施肥計画 +- 田植え計画 +- 運搬計画 + +ボタン例: + +- `TODOを作成` +- `この計画からTODO生成` + +初期値: + +- タイトル +- 作業種別 +- 対象圃場候補 +- `reflect_to_record` + +--- + +## 10. 実績連携の考え方 + +## 10.1 基本原則 + +- TODO は実績そのものではない +- ただし、実績入力の起点にはなる +- すべての TODO が実績へ行くわけではない + +## 10.2 施肥 + +将来像: + +1. 施肥計画を作る +2. TODO を生成する +3. TODO を実施する +4. 完了時に施肥実績へつなぐ + +考え方: + +- 従来の `施肥計画 -> 施肥実績` に対し、間に TODO が入れるようにする +- TODO 完了時は `SpreadingSession` 作成導線へつなぐ +- 対象圃場は TODO の `TodoTargetField` を初期値として渡す + +## 10.3 田植え + +田植え実績アプリは今後実装予定であるため、今回の TODO 側では以下を前提にする。 + +- `rice_transplant` 種別の TODO を持てる +- 完了時に将来の田植え実績へ接続できるよう索引設計を残す +- MVP 時点では「完了済みだが実績アプリ未接続」の状態も許容する + +## 10.4 実績アプリが無い作業 + +- `general` など、実績アプリに紐づかない TODO を許容する +- その場合は `status=done` のみで完了とする + +--- + +## 11. バリデーション方針 + +- `done` に遷移したら `completed_at` を自動設定する +- `canceled` に遷移したら `canceled_at` を自動設定する +- `todo` または `doing` に戻した場合の日時取り扱いは要件次第だが、MVP ではクリアしない案を優先 +- `plan_links` に紐づく計画の年度と TODO の利用年度が必要なら将来追加する +- `field_ids` が計画外圃場を含む場合はエラーにする +- `reflect_to_record=true` でも、対応実績アプリが無い場合は保存を許可する + +--- + +## 12. 実装方針 + +## 12.1 Backend + +- `apps/todos/models.py` +- `apps/todos/serializers.py` +- `apps/todos/views.py` +- `apps/todos/urls.py` +- `keinasystem/settings.py` へ app 追加 +- `keinasystem/urls.py` へ `/api/todos/` 追加 + +## 12.2 Frontend + +- `frontend/src/app/todos/page.tsx` +- `frontend/src/app/todos/[id]/page.tsx` +- `frontend/src/app/todos/new/page.tsx` +- 必要に応じて `_components` 配下に分離 +- ナビゲーションへ TODO 追加 + +## 12.3 実装順 + +1. モデルと API の土台 +2. TODO 一覧と CRUD +3. 並び替え +4. 計画から TODO 生成 +5. 完了時の実績連携導線 + +--- + +## 13. テスト観点 + +- TODO を新規作成できる +- 対象圃場を複数紐づけできる +- 計画の一部圃場だけを対象にできる +- 完了済み、キャンセル済みの表示切り替えができる +- 並び替え後に順番が保持される +- 計画画面から TODO を生成できる +- 実績アプリ未接続の TODO でも完了できる +- 実績連携済み TODO の挙動が壊れない + +--- + +## 14. 未確定事項 + +### 14.1 work_type enum の最終一覧 + +今回の回答で方針は見えたが、初回実装でどこまで列挙するかは確定していない。 + +候補: + +- 一般 +- 施肥 +- 田植え +- 運搬 +- 畔塗 +- 防除 +- 計画非紐づき実績系 + +### 14.2 完了時の自動生成レベル + +MVP で以下のどこまでやるかは実装前に決める。 + +- A. 完了ステータス変更のみ +- B. 実績入力画面への導線生成 +- C. TODO 情報を使った実績レコード仮生成 + +### 14.3 削除ポリシー + +実績連携後の TODO をどう扱うか。 + +案: + +- 物理削除禁止 +- 論理削除 +- 参照整合性チェック付き物理削除 + +### 14.4 年度の持ち方 + +TODO 本体に `year` を明示的に持つかは未確定。 + +持つメリット: + +- 年度フィルタが簡単 +- 実績や計画との一覧整合が取りやすい + +持たないメリット: + +- TODO を純粋な作業単位として保てる + +MVP では年度を持たせる方が実用上は扱いやすい可能性が高い。 + +--- + +## 15. 提案する MVP 決定案 + +実装着手しやすさを優先し、MVP では以下を採用することを提案する。 + +- TODO は `year` を持つ +- 対象管理は `TodoTargetField` を正とする +- `work_type` は `general / fertilization / rice_transplant / delivery / levee_work / pesticide` を初期採用する +- 計画リンクは明示 FK 方式で開始する +- 完了時はまず「実績入力画面への導線生成」を採用し、自動実績作成は後続検討とする +- 並び替えは API 先行、UI は DnD 優先、難しければ矢印移動で代替する +