全テーブル共通:
- タイムスタンプは
timestamptz(UTC保存)
- 主キーは
serial(auto increment)
users
| カラム | 型 | 備考 |
|---|
| id | serial | 主キー |
| email | varchar | 一意制約 |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
auth_codes
| カラム | 型 | 備考 |
|---|
| id | serial | 主キー |
| email | 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 制約(重複通知防止)
- ペット論理削除後は新規通知を生成しない
- 既読管理はアプリ内通知用(プッシュ・メールは送信のみ)
pet_shares
| カラム | 型 | 備考 |
|---|
| id | serial | 主キー |
| pet_id | integer | FK → pets.id |
| user_id | integer | FK → users.id(共有先ユーザー) |
| permissions | jsonb | リソース×CRUD権限 |
| invited_by | integer | FK → users.id(招待者) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
(pet_id, user_id) に UNIQUE 制約
- ペットオーナー自身を共有先にすることはできない
- 1ペットあたりの共有上限: 10人
- 共有解除時は物理削除(関連する notification_settings も削除)
share_invitations
| カラム | 型 | 備考 |
|---|
| id | serial | 主キー |
| pet_id | integer | FK → pets.id |
| inviter_id | integer | FK → users.id |
| invite_type | varchar | email / code |
| email | varchar | 招待先メールアドレス(nullable、email タイプ時のみ) |
| code | varchar | 招待コード(nullable、code タイプ時のみ、UNIQUE) |
| token | varchar | メール招待リンク用トークン(nullable、email タイプ時のみ) |
| permissions | jsonb | 付与する権限(プリセット展開後の実体) |
| notification_preset | varchar | 通知プリセットキー(all / important_only / none) |
| status | varchar | pending / accepted / expired / revoked |
| expires_at | timestamptz | 有効期限(7日) |
| created_at | timestamptz | 作成日時 |
- 招待コード形式: 英数字8文字(nanoid生成)
- 期限切れの
pending 招待は1日1回のバッチで expired に更新
admin_roles
| カラム | 型 | 備考 |
|---|
| id | serial | 主キー |
| name | varchar | ロール名(一意制約) |
| description | varchar | 説明 |
| permissions | jsonb | 権限セット |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- デフォルトロール(super_admin / operator / viewer)はシードデータとして用意
permissions の構造: { "users": ["list","view","suspend","delete"], "masterData": [...], "dashboard": [...], "announcements": [...] }
users テーブル追加カラム(FR-012)
| カラム | 型 | 備考 |
|---|
| role | varchar | user / admin(default: user) |
| admin_role_id | integer | FK → admin_roles.id(nullable、role='admin' 時のみ) |
| suspended_at | timestamptz | 停止日時(nullable) |
| suspension_reason | text | 停止理由(nullable) |
| deleted_at | timestamptz | 論理削除日時(nullable) |
| last_login_at | timestamptz | 最終ログイン日時(nullable) |
マスタテーブル共通の追加カラム(FR-013)
対象: cat_breeds, vaccine_types, symptom_categories
| カラム | 型 | 備考 |
|---|
| deleted_at | timestamptz | 論理削除日時(nullable) |
| display_order | integer | 表示順(nullable、null の場合は name 順) |
food_types
| カラム | 型 | 備考 |
|---|
| id | serial | 主キー |
| name | varchar | フード種類名(一意制約) |
| display_order | integer | 表示順(nullable) |
| deleted_at | timestamptz | 論理削除日時(nullable) |
| created_at | timestamptz | 作成日時 |
| updated_at | timestamptz | 更新日時 |
- FR-013(マスタデータ管理)で管理画面からの追加・編集を提供
- シードデータ: ドライフード, ウェットフード(缶詰), ウェットフード(パウチ), セミモイストフード, おやつ・トリーツ, サプリメント, 療法食, 手作り食, ちゅーる系
analytics_events
| カラム | 型 | 備考 |
|---|
| id | serial | 主キー |
| user_id | integer | FK → users.id |
| event_name | varchar | イベント名(例: weight.created) |
| properties | jsonb | 追加データ(nullable) |
| created_at | timestamptz | 発生日時 |
(user_id, event_name, created_at) にインデックス
- 各健康記録の作成時にイベントを自動記録
- 保持期間: 1年(1年経過後にバッチで物理削除)
- FR-014(ダッシュボード)の機能利用状況・コホート分析・セグメント分析の基盤データ