DBスキーマ設計
全テーブル共通:
- タイムスタンプは
timestamptz(UTC保存) - 主キーは
serial(auto increment)
users
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| varchar | 一意制約 | |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
auth_codes
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| varchar | 送信先メールアドレス | |
| code | varchar | 6桁認証コード(プレーンテキスト保存) |
| attempts | integer | 試行回数(初期値0、上限3) |
| expires_at | timestamptz | 有効期限 |
| created_at | timestamptz | 作成日時 |
- 新しいコード発行時、同一メールアドレスの既存未使用コードは無効化する
- 期限切れレコードは1日1回のバッチ処理で削除
sessions
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| user_id | integer | FK → users.id |
| token | varchar | セッショントークン(nanoid生成) |
| refresh_token | varchar | リフレッシュトークン(nanoid生成) |
| expires_at | timestamptz | セッション有効期限(7日) |
| refresh_token_expires_at | timestamptz | リフレッシュトークン有効期限(30日) |
| ip_address | varchar | 接続元IP |
| user_agent | varchar | デバイス識別用 |
| created_at | timestamptz | 作成日時 |
- リフレッシュ時に旧トークンを即無効化(ローテーション)
- 期限切れレコードは1日1回のバッチ処理で削除
cat_breeds
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| name | varchar | 品種名(一意制約) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- FR-013(マスタデータ管理)で管理画面からの追加・編集を提供予定
pets
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| user_id | integer | FK → users.id |
| name | varchar | ペット名(必須、1〜50文字) |
| breed_id | integer | FK → cat_breeds.id(nullable) |
| breed_other | varchar | 品種自由入力(nullable、breed_id未指定時のみ) |
| date_of_birth | date | 生年月日(nullable) |
| is_birthday_estimated | boolean | 推定フラグ(default false) |
| sex | varchar | male / female / unknown |
| is_neutered | boolean | 避妊/去勢済み |
| coat_color | varchar | 毛色(nullable、1〜50文字) |
| photo_url | varchar | 写真URL(nullable、アップロード機能は後続フェーズ) |
| memo | text | メモ(nullable、最大500文字) |
| deleted_at | timestamptz | 論理削除日時(nullable) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- 論理削除:
deleted_at IS NULLでアクティブなペットをフィルタ - 健康記録(体重・食事・通院等)の親エンティティ
- ペット論理削除時、関連する健康記録は保持する(ペット復元時にデータが残る)
weight_records
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| pet_id | integer | FK → pets.id(CASCADE DELETE) |
| weight_g | integer | 体重(グラム単位、1〜30000) |
| recorded_at | timestamptz | 計測日時(クライアント指定) |
| memo | text | メモ(nullable、最大200文字) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- 同一ペット・同一日時での複数レコードを許可する(一意制約なし)
- ペット削除時にカスケード削除される
recorded_at+pet_idにインデックスを作成(日付範囲検索の高速化)
meal_records
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| pet_id | integer | FK → pets.id(CASCADE DELETE) |
| food_name | varchar | フード名(必須、1〜100文字) |
| food_type | varchar | dry / wet / treat / supplement / other |
| amount | numeric | 量(正の数値) |
| amount_unit | varchar | g / ml / piece |
| meal_date | date | 食事日(必須、未来日不可) |
| meal_time | time | 食事時刻(nullable) |
| memo | text | メモ(nullable、最大500文字) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- ペット削除時にカスケード削除(物理削除)
- インデックス:
(pet_id, meal_date)で日付検索を高速化
vet_visits
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| pet_id | integer | FK → pets.id |
| visited_on | date | 受診日(必須) |
| clinic_name | varchar | 病院名(必須、1〜100文字) |
| diagnosis | text | 診察内容(nullable、最大2000文字) |
| cost | integer | 費用(nullable、円単位、0以上) |
| next_visit_date | date | 次回予定日(nullable、FR-010リマインド起点) |
| memo | text | メモ(nullable、最大500文字) |
| deleted_at | timestamptz | 論理削除日時(nullable) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- 論理削除:
deleted_at IS NULLでアクティブな記録をフィルタ - 病院名は自由入力テキスト(将来マスタ化を検討)
- 費用は日本円(税込総額)を整数で保存
next_visit_dateは FR-010(通知・リマインド)の通院リマインド起点
vaccine_types
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| name | varchar | ワクチン種類名(一意制約) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- FR-013(マスタデータ管理)で管理画面からの追加・編集を提供予定
- cat_breeds と同様のマスタテーブルパターン
vaccine_records
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| pet_id | integer | FK → pets.id(必須) |
| vaccine_type_id | integer | FK → vaccine_types.id(nullable) |
| vaccine_type_other | varchar | ワクチン種類自由入力(nullable、vaccine_type_id未指定時のみ) |
| vaccinated_on | date | 接種日(必須、未来日不可) |
| next_due_date | date | 次回予定日(nullable、vaccinated_onより後) |
| visit_id | integer | FK → vet_visits.id(nullable、通院記録との紐付け) |
| memo | text | メモ(nullable、最大500文字) |
| deleted_at | timestamptz | 論理削除日時(nullable) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- 論理削除:
deleted_at IS NULLでアクティブな記録をフィルタ vaccine_type_idとvaccine_type_otherのいずれか一方が必須visit_idは FR-006(通院履歴管理)実装後に有効化
symptom_categories
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| name | varchar | 症状カテゴリ名(一意制約) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- FR-013(マスタデータ管理)で管理画面からの追加・編集を提供予定
- 初期データ: 嘔吐, 下痢, 便秘, 食欲不振, くしゃみ, 咳, 鼻水, 目やに, 皮膚の異常, 脱毛, 元気がない, 体重減少, 過剰な毛づくろい, 排尿の異常
health_logs
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| pet_id | integer | FK → pets.id |
| symptom_category_id | integer | FK → symptom_categories.id(nullable) |
| symptom_other | varchar | 症状自由入力(nullable、symptom_category_id未指定時のみ) |
| severity | varchar | mild / moderate / severe |
| memo | text | メモ(nullable、最大1000文字) |
| observed_at | timestamptz | 症状観察日時 |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- 体調メモと症状報告を統一管理する単一テーブル
symptom_category_idとsymptom_otherのいずれも未指定の場合はカテゴリなしの体調メモとして扱う- 物理削除(末端データのため論理削除は不要)
medications
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| pet_id | integer | FK → pets.id |
| name | varchar | 薬名(必須、1〜100文字) |
| dosage_amount | decimal | 用量(必須、0より大きい値) |
| dosage_unit | varchar | 単位(必須、enum: tablet/capsule/ml/mg/g/drop/packet/piece/tube/cm/puff) |
| times_per_day | integer | 1日の投与回数(必須、1〜24) |
| frequency_note | varchar | 頻度の補足(nullable、最大100文字。例: 「朝夕食後」) |
| route | varchar | 投与経路(enum: oral/topical/eye/ear/injection/inhalation/other、default: oral) |
| start_date | date | 投薬開始日(必須) |
| end_date | date | 投薬終了日(nullable、nullの場合は継続中) |
| memo | text | メモ(nullable、最大500文字) |
| deleted_at | timestamptz | 論理削除日時(nullable) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- 投薬状態は
end_dateとdeleted_atから導出(is_activeカラムは持たない) - 投薬中:
end_date IS NULL OR end_date >= CURRENT_DATEかつdeleted_at IS NULL - 終了済み:
end_date < CURRENT_DATEかつdeleted_at IS NULL - 論理削除:
deleted_at IS NOT NULL
medication_logs
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| medication_id | integer | FK → medications.id |
| status | varchar | 投与ステータス(enum: administered/skipped/partial) |
| administered_at | timestamptz | 投与日時(必須、未来日時不可) |
| dosage_amount | decimal | 実際の用量(nullable、省略時は medications の値を参照) |
| dosage_unit | varchar | 実際の単位(nullable、省略時は medications の値を参照) |
| memo | text | メモ(nullable、最大500文字) |
| created_at | timestamptz | 作成日時 |
- medications との関連: 投薬スケジュール1件に対して複数の投薬記録
- dosage_amount / dosage_unit は両方指定するか両方省略のみ許可
- 投薬スケジュール論理削除時も記録は保持される
device_tokens
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| user_id | integer | FK → users.id |
| token | varchar | FCMデバイストークン(一意制約) |
| platform | varchar | ios / android / web |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- 同一トークンの重複登録を防ぐため
tokenに UNIQUE 制約 - ログアウト時に該当デバイスのトークンを削除
- FCMから無効トークンエラーが返った場合は自動削除
notification_settings
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| user_id | integer | FK → users.id |
| pet_id | integer | FK → pets.id |
| type | varchar | vaccine / medication / visit |
| enabled | boolean | 通知の有効/無効(default true) |
| push_enabled | boolean | プッシュ通知の有効/無効(default true) |
| email_enabled | boolean | メール通知の有効/無効(default false) |
| remind_days_before | integer[] | リマインド日数の配列(例: {7,1}) |
| send_time | time | 送信時刻(default ‘09:00’) |
| timezone | varchar | タイムゾーン(default ‘Asia/Tokyo’) |
| medication_notify_mode | varchar | every_dose / start_end_only(type=‘medication’ 時のみ使用、default ‘every_dose’) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
(user_id, pet_id, type)に UNIQUE 制約- ペット登録時に全通知タイプのデフォルト設定を自動作成
- デフォルトの
remind_days_before: vaccine={7,1}、medication={0}、visit={3,1}
notifications
| カラム | 型 | 備考 |
|---|---|---|
| id | serial | 主キー |
| user_id | integer | FK → users.id |
| pet_id | integer | FK → pets.id |
| type | varchar | vaccine / medication / visit |
| title | varchar | 通知タイトル |
| body | text | 通知本文 |
| trigger_date | date | リマインド対象の予定日 |
| remind_days_before | integer | この通知の何日前設定に対応するか |
| read_at | timestamptz | 既読日時(nullable、未読はNULL) |
| created_at | timestamptz | 作成日時 |
(user_id, pet_id, type, trigger_date, remind_days_before)に UNIQUE 制約(重複通知防止)- ペット論理削除後は新規通知を生成しない
- 既読管理はアプリ内通知用(プッシュ・メールは送信のみ)