- 論点1-5の決定を仕様書案に反映 - document/19_マスタードキュメント_TODO管理編.md を新規作成 - CLAUDE.md のマスタードキュメント一覧に TODO管理を追加
12 KiB
12 KiB
マスタードキュメント:TODO管理機能
作成: 2026-04-10 最終更新: 2026-04-10 対象機能: TODO管理(作業指示・優先順位管理・実績連携導線) 実装状況: 設計完了・実装前 対象 Issue:
akira/keinasystem#17
概要
繁忙期に「どれから手を付けるか」を管理するための TODO 機能。 計画(施肥・田植え・運搬など)と実績の間に位置する「作業指示」レイヤー。
機能スコープ(IN / OUT)
| IN(MVP対象) | OUT(対象外) |
|---|---|
| TODO の作成・編集・削除 | 期日通知・リマインダー |
| ステータス管理(todo / doing / done / canceled) | 複数ユーザー割り当て |
| 優先順位管理(ドラッグ&ドロップ / 矢印移動) | コメント・添付ファイル |
| 圃場単位の対象紐づけ | 工数見積・実績時間記録 |
| 計画との紐づけ(施肥・田植え・運搬) | 完全な汎用ワークフローエンジン化 |
| 計画画面からの TODO 生成 | 実績アプリ未実装領域の詳細実績入力 UI |
| 完了時の実績入力画面への導線生成 | |
| 完了済み・キャンセル済みの表示切り替え |
TODO の位置づけ
計画(年間設計情報)
↓ 生成
TODO(実際に動く作業単位)
↓ 完了
実績(完了した事実)
データモデル
Todo(本体)
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| id | bigint | ✓ | PK |
| year | integer | ✓ | 年度 |
| title | varchar(200) | ✓ | タイトル |
| description | text | 説明 | |
| status | enum | ✓ | todo / doing / done / canceled |
| priority | integer | ✓ | 小さいほど上位(1000刻み) |
| due_date | date | 期日 | |
| work_type | enum | ✓ | 作業種別(下記参照) |
| should_link_record | boolean | ✓ | 完了時に実績連携導線を有効にするか |
| completed_at | datetime | 完了日時(差し戻し後も保持) | |
| canceled_at | datetime | キャンセル日時 | |
| created_at | datetime | ✓ | |
| updated_at | datetime | ✓ |
ステータス遷移
todo→doing→done(complete/ 専用エンドポイント経由)done→todo / doing(差し戻し許可。completed_at は履歴として保持)canceledへの遷移は任意のタイミングで可
作業種別(work_type)
MVP で採用する種別:
| 値 | 意味 |
|---|---|
general |
一般(どれにも当てはまらない作業) |
fertilization |
施肥 |
rice_transplant |
田植え |
delivery |
運搬 |
levee_work |
畔塗 |
将来追加(農薬散布管理アプリ実装時):
| 値 | 意味 |
|---|---|
pesticide |
防除 |
並び順
- 基本は FILO(新規作成時は最上位へ)
- 初回作成時:最上位 TODO の
priority - 1000を割り当て - 一覧表示:
priority昇順 - 並び替え後:表示対象全体を 1000, 2000, 3000... と再採番して保存
- 完了・キャンセル済みも
priorityを保持
TodoTargetField(対象圃場)
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| 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']- 圃場グループは独立モデル化しない(
Field.group_nameを参照するのみ) - 計画に含まれる圃場の一部だけを対象にすることを許可する
TodoCrop(分類補助:作物)
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| id | bigint | ✓ | PK |
| todo | FK(Todo) | ✓ | CASCADE |
| crop | FK(plans.Crop) | ✓ | PROTECT |
| created_at | datetime | ✓ |
unique_together = ['todo', 'crop']
TodoVariety(分類補助:品種)
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| id | bigint | ✓ | PK |
| todo | FK(Todo) | ✓ | CASCADE |
| variety | FK(plans.Variety) | ✓ | PROTECT |
| created_at | datetime | ✓ |
unique_together = ['todo', 'variety']- 圃場が 0 件でも Crop / Variety だけの紐づけは許可(圃場未確定の準備作業など)
TodoPlanLink(計画との紐づけ)
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| id | bigint | ✓ | PK |
| todo | FK(Todo) | ✓ | CASCADE |
| plan_type | enum | ✓ | fertilization / rice_transplant / delivery |
| fertilization_plan | FK(fertilizer.FertilizationPlan) | ||
| rice_transplant_plan | FK(plans.RiceTransplantPlan) | ||
| delivery_plan | FK(分配計画モデル) | ||
| created_at | datetime | ✓ |
- 1 行に 1 種別のリンクのみ保持
plan_typeに応じて対応 FK だけを埋めるlevee_workは MVP では「計画リンクなしで持てる work_type」として扱う- 作付け計画(Plan)は TODO 生成元としては対象外
TodoCompletionLink(完了時の実績連携索引)
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
| id | bigint | ✓ | PK |
| todo | FK(Todo) | ✓ | |
| record_type | enum | ✓ | 実績種別 |
| work_record | FK(workrecords.WorkRecord) | 共通索引 | |
| spreading_session | FK(fertilizer.SpreadingSession) | 施肥実績 | |
| created_at | datetime | ✓ |
todoは OneToOne ではなく FK(1 TODO から複数実績への分割を許容)- 実績アプリが未実装の種別は空でよい
API 仕様
エンドポイント一覧
| メソッド | パス | 説明 |
|---|---|---|
| GET | /api/todos/ |
一覧取得 |
| POST | /api/todos/ |
作成 |
| GET | /api/todos/{id}/ |
詳細取得 |
| PATCH | /api/todos/{id}/ |
更新(status=done への変更は不可) |
| DELETE | /api/todos/{id}/ |
削除 |
| PATCH | /api/todos/reorder/ |
並び替え |
| POST | /api/todos/from-plan/ |
計画から TODO 生成 |
| POST | /api/todos/{id}/complete/ |
完了処理(実績連携導線を返す) |
重要な設計ルール
完了処理の一本化
PATCHでのstatus=done変更はバックエンドが拒否する- 完了は必ず
POST /api/todos/{id}/complete/を通る - 理由:実績連携導線の生成を確実にするため。AI 実装者がセッションをまたいで実装する際のブレを防ぐ
差し戻し時の挙動
done → todo/doingは許可TodoCompletionLinkが存在する場合は、差し戻しを許可しつつ API レスポンスに警告と各実績レコードへの直リンクを返す- 実績レコード自体の削除は行わない(各実績アプリ側の責務)
削除時の挙動
TodoCompletionLinkが存在する TODO を削除しようとした場合、警告と各実績レコードへの直リンクを返す- ユーザーが確認した上で削除を実行した場合は物理削除を許可する
TodoCompletionLinkは TODO と一緒に削除(CASCADE)- 実績レコード自体は削除しない
一覧 GET /api/todos/
主なクエリパラメータ:
| パラメータ | デフォルト | 説明 |
|---|---|---|
status |
todo,doing |
カンマ区切りで複数指定可 |
include_closed |
false |
true で完了・キャンセルも含む |
work_type |
- | 作業種別フィルター |
due |
- | overdue / today / upcoming |
year |
- | 年度フィルター |
作成 POST /api/todos/
{
"title": "西田エリアの追肥",
"description": "週内に先行実施",
"status": "todo",
"year": 2026,
"due_date": "2026-04-12",
"work_type": "fertilization",
"should_link_record": true,
"field_ids": [12, 18, 21],
"crop_ids": [1],
"variety_ids": [4],
"plan_links": [
{"plan_type": "fertilization", "plan_id": 8}
]
}
plan_links の変換:API 入力は plan_type + plan_id の組で受け、Serializer で対応 FK へ変換する。
並び替え PATCH /api/todos/reorder/
{
"items": [
{"id": 31, "priority": 1000},
{"id": 27, "priority": 2000},
{"id": 42, "priority": 3000}
]
}
計画から TODO 生成 POST /api/todos/from-plan/
{
"plan_type": "fertilization",
"plan_id": 8,
"title": "2026春肥の散布",
"field_ids": [12, 18],
"due_date": "2026-04-15",
"should_link_record": true
}
field_ids未指定時は計画内の全圃場を初期対象にするwork_typeはplan_typeから自動補完する
完了処理 POST /api/todos/{id}/complete/
status=doneにするshould_link_record=trueかつ対応実績アプリがある場合、関連画面へ遷移するための情報を返す- MVP では実績レコードの自動生成は行わず、導線情報の返却にとどめる
バリデーション
done遷移時にcompleted_atを自動設定canceled遷移時にcanceled_atを自動設定PATCHでstatus=doneを指定した場合は 400 エラーを返すfield_idsが計画外圃場を含む場合はplan_linksが 1 件以上あるときのみエラーにするshould_link_record=trueでも対応実績アプリが無い場合は保存を許可するTodoTargetField.fieldはPROTECT(過去 TODO の対象圃場履歴を保全するため)
UI 仕様
一覧画面 /todos
- デフォルト表示:todo / doing を priority 昇順で表示
- 完了済み・キャンセル済みはフィルターで表示切り替え
- 期限超過は赤系で強調、当日期限も強調表示
- ドラッグ&ドロップで並び替え(難しければ矢印ボタンで代替)
表示カラム:タイトル / ステータス / 期日 / 作業種別 / 対象圃場数 / 紐づき計画
詳細画面 /todos/{id}
表示・編集:タイトル / 説明 / ステータス / 期日 / 作業種別 / 実績連携フラグ / 対象圃場 / 分類作物・品種 / 計画リンク
下部表示:実績連携先 / 完了日時 / 更新日時
作成導線
- TODO 一覧から新規作成
- 計画詳細または一覧から TODO 生成(施肥・田植え・運搬の各計画画面)
実装ファイル構成
Backend
apps/todos/
├── models.py # Todo, TodoTargetField, TodoCrop, TodoVariety, TodoPlanLink, TodoCompletionLink
├── admin.py
├── serializers.py
├── views.py
├── urls.py
└── migrations/
keinasystem/settings.pyにapps.todosを追加keinasystem/urls.pyに/api/todos/を追加
Frontend
frontend/src/app/todos/
├── page.tsx # 一覧
├── [id]/page.tsx # 詳細
└── new/page.tsx # 作成
実装順
- モデル・admin・migration
- TODO CRUD API(一覧・詳細・作成・更新・削除)
- TODO 一覧・詳細 UI
- 並び替え API と UI
- 計画から TODO 生成(from-plan API + 各計画画面への導線)
- 完了処理 API と実績連携導線 UI
実績連携の考え方
施肥
施肥計画 → 施肥TODO → 施肥実績(SpreadingSession)の流れ。
完了時は SpreadingSession 作成画面への導線を返す。対象圃場は TodoTargetField を初期値として渡す。
田植え
田植え実績アプリは今後実装予定。MVP では:
rice_transplant種別の TODO を持てる- 完了時は「完了済みだが実績アプリ未接続」の状態も許容する
- 将来の田植え実績導入時に
TodoCompletionLinkを拡張する
実績アプリが無い作業
general など、実績アプリに紐づかない TODO は status=done のみで完了とする。
未決定(実装時に判断)
以下は MVP 着手後に実装者が判断しながら決めてよい事項。
| 事項 | 方針 |
|---|---|
| 複数計画リンクの初回 UI | 内部構造は複数可。UI はまず 1 件中心で実装し、必要なら拡張する |
| 並び替え対象の範囲 | フィルター中(todo/doing のみ)を再採番対象とするのが自然 |
| 施肥完了時に渡す初期値の粒度 | SpreadingSession 作成画面の実装時に具体的な受け渡し仕様を決める |