食事記録仕様 (FR-005)
| 項目 | 内容 |
|---|---|
| 対象FR | FR-005(食事記録) |
| 優先度 | 中 |
| ステータス | 詳細化済み |
概要
ユーザーは登録済みペットの食事内容を記録できる。フード名・種類・量・日時を構造化して保存し、日々の食事管理に活用する。食事記録はペットの健康記録の一部であり、ペット削除時にカスケード削除される。
入力フィールド
| フィールド | 型 | 必須 | バリデーション |
|---|---|---|---|
| foodName | varchar | ○ | 1〜100文字、前後の空白はトリム |
| foodType | varchar | ○ | dry / wet / treat / supplement / other |
| amount | numeric | ○ | 正の数値(0より大きい) |
| amountUnit | varchar | ○ | g / ml / piece |
| mealDate | date | ○ | 未来日不可 |
| mealTime | time | - | HH:MM 形式 |
| memo | text | - | 最大500文字 |
フード種類 (foodType)
| 値 | 説明 |
|---|---|
dry | ドライフード(カリカリ) |
wet | ウェットフード(缶詰・パウチ等) |
treat | おやつ |
supplement | サプリメント |
other | その他 |
量の単位 (amountUnit)
| 値 | 説明 |
|---|---|
g | グラム |
ml | ミリリットル |
piece | 個・粒 |
APIエンドポイント
全エンドポイントで認証必須(__Host-session Cookie)。
:petId は自分が所有するペットのIDであること。
| メソッド | パス | 概要 |
|---|---|---|
| POST | /api/pets/:petId/meals | 食事記録の登録 |
| GET | /api/pets/:petId/meals | 食事記録の一覧取得 |
| GET | /api/pets/:petId/meals/:mealId | 食事記録の詳細取得 |
| PATCH | /api/pets/:petId/meals/:mealId | 食事記録の更新 |
| DELETE | /api/pets/:petId/meals/:mealId | 食事記録の削除(物理削除) |
POST /api/pets/:petId/meals — 食事記録の登録
リクエストボディに入力フィールドを指定して食事記録を登録する。
- 成功時:
201 Created、作成された食事記録を返す - ペットが存在しない / 他ユーザーのペット:
404 Not Found
{ "data": { "id": 1, "petId": 1, "foodName": "ロイヤルカナン インドア", "foodType": "dry", "amount": 30, "amountUnit": "g", "mealDate": "2026-02-18", "mealTime": "08:30", "memo": null, "createdAt": "2026-02-18T10:00:00Z", "updatedAt": "2026-02-18T10:00:00Z" }}GET /api/pets/:petId/meals — 食事記録の一覧取得
指定ペットの食事記録を日付の降順で返す。
- 成功時:
200 OK - 記録なし: 空配列を返す(エラーではない)
- ペットが存在しない / 他ユーザーのペット:
404 Not Found
クエリパラメータ:
| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
| limit | integer | 20 | 取得件数(1〜100) |
| offset | integer | 0 | スキップ件数 |
| dateFrom | date | - | 開始日(この日以降) |
| dateTo | date | - | 終了日(この日以前) |
{ "data": [ { "id": 2, "petId": 1, "foodName": "チュール まぐろ味", "foodType": "treat", "amount": 1, "amountUnit": "piece", "mealDate": "2026-02-18", "mealTime": "15:00", "memo": null, "createdAt": "2026-02-18T16:00:00Z", "updatedAt": "2026-02-18T16:00:00Z" }, { "id": 1, "petId": 1, "foodName": "ロイヤルカナン インドア", "foodType": "dry", "amount": 30, "amountUnit": "g", "mealDate": "2026-02-18", "mealTime": "08:30", "memo": null, "createdAt": "2026-02-18T10:00:00Z", "updatedAt": "2026-02-18T10:00:00Z" } ]}GET /api/pets/:petId/meals/:mealId — 食事記録の詳細取得
指定IDの食事記録を返す。
- 成功時:
200 OK - 存在しない / 他ユーザーのペットの記録:
404 Not Found
PATCH /api/pets/:petId/meals/:mealId — 食事記録の更新
指定したフィールドのみ部分更新する。リクエストボディに含まれないフィールドは変更しない。
- 成功時:
200 OK、更新後の食事記録を返す - 存在しない / 他ユーザーのペットの記録:
404 Not Found
DELETE /api/pets/:petId/meals/:mealId — 食事記録の削除
物理削除する。
- 成功時:
204 No Content - 存在しない / 他ユーザーのペットの記録:
404 Not Found
認可ルール
- 全エンドポイントで認証必須
- 自分が所有するペットの食事記録のみ操作可能
- 他ユーザーのペットIDを指定した場合は
404を返し、存在の有無を漏らさない - 論理削除済みペットの食事記録へのアクセスは
404を返す
エッジケース
mealTime未指定の記録 → 日付のみで記録される(一覧のソートはmealTimeが null のものを後ろに表示)- 同一ペット・同一日時に複数の食事記録 → 許可する(朝食でドライフードとウェットフードを別々に記録するケースに対応)
- ペットの論理削除後 → 食事記録には直接アクセスできない(ペットが
404を返すため) - ペットの物理削除(カスケード削除)→ 関連する食事記録もすべて削除される
amountに極端に大きい値 → アプリケーション側で上限を設定(TBD、例: 99999.9 以下)dateFromがdateToより後 → 空配列を返す(エラーではない)
拡張予定(現時点ではスコープ外)
- フードマスタテーブル(よく使うフードの登録・選択)
- カロリー計算・1日の摂取量集計
- 食事記録のCSVエクスポート
- 家族共有時の共有ペットの食事記録へのアクセス(FR-011で対応)
検証方法
- 食事記録の登録 → 一覧取得 → 詳細取得の一連フローが完了すること
- 必須フィールド(foodName, foodType, amount, amountUnit, mealDate)未指定時にバリデーションエラーが返ること
- 無効な
foodType/amountUnit指定時にバリデーションエラーが返ること amountに0以下の値を指定した場合にバリデーションエラーが返ること- 未来日の
mealDateが拒否されること - 他ユーザーのペットの食事記録へのアクセスが
404を返すこと - PATCH で指定したフィールドのみが更新され、他フィールドが変更されないこと
- DELETE 後に一覧・詳細から表示されなくなること
- 日付範囲フィルタ(dateFrom, dateTo)が正しく機能すること
- ページネーション(limit, offset)が正しく機能すること
- 論理削除済みペットの食事記録にアクセスした場合に
404が返ること - 未認証状態で全エンドポイントが
401を返すこと