通知・リマインド仕様 (FR-010)
| 項目 | 内容 |
|---|---|
| 対象FR | FR-010(通知・リマインド) |
| 優先度 | 中 |
| ステータス | 詳細化済み |
| フェーズ | Phase 3 |
概要
システムはワクチン接種時期・投薬スケジュール・通院予定について、ユーザーが設定したタイミングで通知を送信する。通知はプッシュ通知・アプリ内通知・メール通知の3チャネルで配信され、ユーザーはペット×通知タイプ単位で通知設定をカスタマイズできる。
前提条件(依存FR)
本仕様は以下のFRが提供するデータを通知の元情報として利用する。各FRの仕様策定時に、下記フィールドが含まれることを前提とする。
| 依存FR | 必要なデータ | 用途 |
|---|---|---|
| FR-006(通院履歴) | 次回通院予定日 | 通院リマインドのトリガー日 |
| FR-007(ワクチン履歴) | 次回接種予定日 | ワクチンリマインドのトリガー日 |
| FR-009(投薬管理) | 投薬スケジュール(開始日・終了日・頻度) | 投薬リマインドのトリガー |
注記: FR-006/007/009 の仕様は詳細化済み。各仕様で定義されたフィールド(
nextVisitDate,nextDueDate,startDate/endDate/timesPerDay)と整合済み。
通知タイプ
| タイプ | トリガー | デフォルトリマインド日数 |
|---|---|---|
vaccine | ワクチン次回接種予定日 | 7日前、1日前 |
medication | 投薬スケジュール | 開始日当日(モードにより毎回) |
visit | 次回通院予定日 | 3日前、1日前 |
配信チャネル
| チャネル | 説明 | 必要な登録情報 |
|---|---|---|
| プッシュ通知 | FCM経由でモバイル/PWAに送信 | デバイストークン |
| アプリ内通知 | 通知一覧画面で表示(既読/未読管理) | なし(認証のみ) |
| メール通知 | 登録メールアドレスに送信 | なし(アカウントのメール使用) |
- ユーザーはチャネルごとに ON/OFF を設定できる
- アプリ内通知は常に生成される(OFF にできない)。プッシュ・メールは任意
通知設定
設定の粒度
ペット×通知タイプの組み合わせごとに設定する。
例: 「そうにゃ」のワクチン通知 → 7日前・1日前にプッシュ+メール、「みけ」の投薬通知 → 毎回プッシュのみ
設定項目
| 項目 | 型 | 説明 |
|---|---|---|
| enabled | boolean | この通知タイプの有効/無効(default: true) |
| pushEnabled | boolean | プッシュ通知の有効/無効(default: true) |
| emailEnabled | boolean | メール通知の有効/無効(default: false) |
| remindDaysBefore | integer[] | リマインド日数の配列(例: [7, 1])。通知タイプごとにデフォルトあり |
| sendTime | time | 通知送信時刻(default: ‘09:00’) |
| timezone | varchar | タイムゾーン(default: ‘Asia/Tokyo’) |
投薬通知の追加設定
| 項目 | 型 | 説明 |
|---|---|---|
| medicationNotifyMode | varchar | every_dose: スケジュール通りに毎回通知 / start_end_only: 投薬開始日・終了日のみ通知(default: ‘every_dose’) |
デフォルト値の生成タイミング
- ペット登録時に全通知タイプのデフォルト設定レコードを自動作成する
- ユーザーが明示的に設定を変更するまではデフォルト値が適用される
通知スケジューリング
バッチ処理
- 1日1回のバッチジョブで翌日分までの通知対象を抽出しキューに積む
- バッチ実行時刻: 毎日 00:00 UTC(各ユーザーの
send_time+timezoneに従い配信時刻を決定) - 投薬の
every_doseモードはスケジュール日に毎日生成する
通知生成フロー
1. バッチジョブ起動2. 通知設定が有効なユーザー×ペット×タイプを走査3. 各タイプの元データ(次回予定日/投薬スケジュール)を参照4. remind_days_before に一致する日付の通知を生成5. アプリ内通知レコードを作成(notifications テーブル)6. 各チャネル(プッシュ/メール)の配信をキューに登録7. send_time に従い配信を実行重複防止
- 同一ユーザー・同一ペット・同一タイプ・同一トリガー日・同一 remindDaysBefore の通知は1回のみ生成する
- バッチ処理の冪等性を保証するため、生成済み通知を
notificationsテーブルで確認してからキューに積む
デバイストークン管理
- クライアント(Flutter/PWA)がFCMトークンを取得した時点で
/api/devicesに登録する - トークンの更新時は既存トークンを差し替える(同一デバイスの重複登録を防ぐ)
- ログアウト時に該当デバイスのトークンを削除する
- プッシュ送信時にFCMから無効トークンのエラーが返った場合は該当レコードを削除する
APIエンドポイント
全エンドポイントで認証必須(__Host-session Cookie)。
デバイストークン
| メソッド | パス | 概要 |
|---|---|---|
| POST | /api/devices | デバイストークン登録 |
| DELETE | /api/devices/:deviceId | デバイストークン削除 |
通知設定
| メソッド | パス | 概要 |
|---|---|---|
| GET | /api/pets/:petId/notification-settings | ペットの通知設定一覧取得 |
| PATCH | /api/pets/:petId/notification-settings/:type | 通知設定を更新 |
アプリ内通知
| メソッド | パス | 概要 |
|---|---|---|
| GET | /api/notifications | 通知一覧取得(ページネーション) |
| GET | /api/notifications/unread-count | 未読件数取得 |
| PATCH | /api/notifications/:notificationId/read | 既読にする |
| POST | /api/notifications/read-all | 全件既読にする |
POST /api/devices — デバイストークン登録
// リクエスト{ "token": "fcm-token-string", "platform": "ios"}| フィールド | 型 | 必須 | バリデーション |
|---|---|---|---|
| token | varchar | ○ | 空文字不可 |
| platform | varchar | ○ | ios / android / web |
- 成功時:
201 Created - 同一トークンが既に存在する場合:
200 OK(更新扱い)
{ "data": { "id": 1, "platform": "ios", "createdAt": "2026-02-18T10:00:00Z" }}DELETE /api/devices/:deviceId — デバイストークン削除
- 成功時:
204 No Content - 存在しない / 他ユーザーのデバイス:
404 Not Found
GET /api/pets/:petId/notification-settings — 通知設定一覧
ペットに紐づく全通知タイプの設定を返す。
- 成功時:
200 OK
{ "data": [ { "type": "vaccine", "enabled": true, "pushEnabled": true, "emailEnabled": false, "remindDaysBefore": [7, 1], "sendTime": "09:00", "timezone": "Asia/Tokyo" }, { "type": "medication", "enabled": true, "pushEnabled": true, "emailEnabled": false, "remindDaysBefore": [0], "sendTime": "09:00", "timezone": "Asia/Tokyo", "medicationNotifyMode": "every_dose" }, { "type": "visit", "enabled": true, "pushEnabled": true, "emailEnabled": false, "remindDaysBefore": [3, 1], "sendTime": "09:00", "timezone": "Asia/Tokyo" } ]}PATCH /api/pets/:petId/notification-settings/:type — 通知設定更新
指定したフィールドのみ部分更新する。:type は vaccine / medication / visit。
// リクエスト例{ "pushEnabled": false, "emailEnabled": true, "remindDaysBefore": [14, 7, 1]}- 成功時:
200 OK、更新後の設定を返す - 存在しないペット / 他ユーザーのペット:
404 Not Found - 不正な
:type:422 Unprocessable Entity remindDaysBeforeのバリデーション: 0以上の整数の配列、最大5要素
GET /api/notifications — 通知一覧
ログインユーザーの通知一覧をページネーションで返す。新しい順にソート。
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| cursor | integer | - | - | 前回レスポンスの最後の通知ID |
| limit | integer | - | 20 | 取得件数(最大50) |
- 成功時:
200 OK
{ "data": [ { "id": 42, "petId": 1, "petName": "そうにゃ", "type": "vaccine", "title": "ワクチン接種のリマインド", "body": "そうにゃの3種混合ワクチン接種予定日が7日後です", "readAt": null, "createdAt": "2026-03-01T00:00:00Z" } ], "nextCursor": 41}GET /api/notifications/unread-count — 未読件数
{ "data": { "count": 3 }}PATCH /api/notifications/:notificationId/read — 既読にする
- 成功時:
200 OK - 既に既読:
200 OK(冪等) - 存在しない / 他ユーザーの通知:
404 Not Found
POST /api/notifications/read-all — 全件既読
ログインユーザーの未読通知を全て既読にする。
- 成功時:
200 OK
{ "data": { "updatedCount": 5 }}認可ルール
- 全エンドポイントで認証必須
- デバイストークン: 自分のトークンのみ操作可能
- 通知設定: 自分が登録したペットのみ操作可能(他ユーザーのペットIDは
404) - 通知一覧: 自分宛の通知のみ表示(他ユーザーの通知IDを指定した場合は
404) - Phase 3 では通知はペットオーナーのみに送信する(家族共有メンバーへの通知は FR-011 対応時に拡張)
エッジケース
- ペット削除(論理削除)後 → 該当ペットの未送信通知はキャンセルされる。通知設定は保持するが新規通知は生成しない
- デバイストークンが無効になった場合 → FCMエラー時にトークンを自動削除し、プッシュ送信をスキップ
- 元データ(予定日)が変更された場合 → 次回バッチ処理で新しい日付に基づく通知を生成する。生成済みの未来日通知があれば削除して再生成
remindDaysBeforeに[0]を指定した場合 → 予定日当日に通知- 全チャネルが OFF の設定 → アプリ内通知は常に生成される(
enabled: trueの場合) - 通知設定の
enabled: false→ アプリ内通知を含む全通知を停止 - ワクチン・通院の予定日が過去日に設定された場合 → リマインド通知は生成しない
- 投薬の終了日が過去の場合 → 通知を生成しない
- メール送信失敗時 → リトライせず、アプリ内通知とプッシュ通知には影響しない
通知テンプレート
| タイプ | タイトル | 本文例 |
|---|---|---|
| vaccine | ワクチン接種のリマインド | {pet_name}の{vaccine_name}接種予定日が{days}日後です |
| medication | 投薬のリマインド | {pet_name}の{medication_name}の投薬予定があります |
| visit | 通院のリマインド | {pet_name}の通院予定日が{days}日後です |
- テンプレートのローカライズは Phase 3 では日本語のみ
拡張予定(現時点ではスコープ外)
- 家族共有メンバーへの通知配信(FR-011 対応時)
- 通知テンプレートのカスタマイズ
- 多言語対応
- 管理画面からのお知らせ配信(FR-012 対応時)
- リアルタイム配信(WebSocket / SSE)
- 通知のスヌーズ・再通知機能
検証方法
- ワクチン予定日を設定 →
remind_days_beforeに一致する日にアプリ内通知が生成されること - 投薬スケジュール設定 →
every_doseモードで毎回通知、start_end_onlyで開始/終了日のみ通知されること - 通院予定日を設定 → リマインド通知が生成されること
- 通知設定の
enabled: falseで通知が生成されないこと - プッシュ通知 OFF 時にプッシュが送信されず、アプリ内通知は生成されること
- デバイストークン登録 → プッシュ通知が受信できること
- デバイストークン削除後にプッシュ通知が送信されないこと
- 通知一覧のページネーションが正しく動作すること
- 既読/全件既読操作が正しく反映されること
- 他ユーザーのペット・通知へのアクセスが
404を返すこと - ペット論理削除後に新規通知が生成されないこと
- 予定日変更時に通知が再生成されること
- 同一条件の通知が重複生成されないこと
send_timeとtimezoneに従った時刻に配信されること