# 製品仕様書 — 減塩コーチ（SaltCoach）

バージョン: 1.0.0  
最終更新: 2026-04-21  
作成者: プロダクトチーム

---

## 1. 製品概要

### 1.1 プロダクトビジョン

「高血圧の人が、写真1枚で食事管理を完結できる世界をつくる」

### 1.2 対応プラットフォーム

| プラットフォーム | バージョン | 対応状況 |
|---------------|-----------|---------|
| iOS | 16.0以上 | Phase 1よりサポート |
| Android | 10.0（API 29）以上 | Phase 1よりサポート |
| Web（PWA） | モダンブラウザ | Phase 2よりサポート |

### 1.3 言語対応

- Phase 1: 日本語のみ
- Phase 3: 英語・タイ語・ベトナム語を追加

---

## 2. 機能要件

### 2.1 機能一覧

| ID | 機能名 | 概要 | 優先度 | フェーズ |
|----|--------|------|--------|---------|
| F-01 | 食事写真撮影・解析 | カメラ撮影またはギャラリー選択で塩分推定 | Must | Phase 1 |
| F-02 | 塩分量結果表示 | 推定塩分量・カロリー・主要成分の表示 | Must | Phase 1 |
| F-03 | 食事記録一覧 | 日付別の食事記録カレンダービュー | Must | Phase 1 |
| F-04 | 血圧記録入力 | 朝晩の収縮期・拡張期・脈拍の手動入力 | Must | Phase 1 |
| F-05 | 塩分摂取グラフ | 日次・週次・月次の塩分摂取推移グラフ | Must | Phase 1 |
| F-06 | 目標設定 | 1日の塩分摂取目標値（デフォルト6g/日）の設定 | Must | Phase 1 |
| F-07 | プッシュ通知 | 食後撮影リマインダー・目標超過アラート | Should | Phase 1 |
| F-08 | 血圧×食事相関分析 | 塩分摂取量と翌日血圧の相関スコア表示 | Must | Phase 2 |
| F-09 | AIコーチングメッセージ | パーソナライズされた減塩アドバイスの配信 | Must | Phase 2 |
| F-10 | 医師向け報告書生成 | 過去1か月分のサマリーPDF自動生成 | Must | Phase 2 |
| F-11 | 食品データベース検索 | 食品名から塩分・栄養素を検索する補助機能 | Should | Phase 2 |
| F-12 | ウェアラブル連携 | Apple Health / Google Fit との血圧データ同期 | Could | Phase 2 |
| F-13 | 医療機関向けダッシュボード | 複数患者の一括管理・データ閲覧 | Must | Phase 3 |
| F-14 | EMR連携 | 電子カルテシステムへのデータエクスポート | Could | Phase 3 |

---

### 2.2 機能詳細

#### F-01 食事写真撮影・解析

**概要**  
ユーザーがカメラで食事を撮影（またはギャラリーから選択）すると、AIが料理の種類・量・調理法を解析し、塩分量（g）・カロリー（kcal）・タンパク質・脂質・炭水化物を推定して表示する。

**処理フロー**

```
[ユーザー操作]
  │
  ├─ カメラ起動（アプリ内カメラ）
  │     └─ 撮影 → 画像プレビュー確認 → 送信
  │
  └─ ギャラリー選択 → 画像選択 → 送信
         │
         ▼
[クライアント処理]
  画像圧縮（最大1280px、JPEG品質80%）
  → Base64エンコード or マルチパートフォーム送信
         │
         ▼
[API Server（FastAPI）]
  画像受信 → バリデーション（ファイルサイズ上限10MB）
  → AI推論リクエスト（Vision API）
         │
         ▼
[AI推論サービス]
  物体検出（YOLO v8ベース） → 料理種別分類 → 量推定
  → 塩分・栄養データベース照合 → 結果返却
         │
         ▼
[レスポンス表示]
  塩分量（g）・カロリー・主要成分
  推定精度インジケーター（高/中/低）
  手動修正フォーム（料理名・量の補正）
```

**制約**
- 1枚の画像に含まれる料理は最大8品目まで識別
- 推定精度目標: 塩分量±15%（国内主要料理カテゴリ対象）
- 処理時間目標: 3秒以内（95パーセンタイル）
- 無料プランは1日3回まで、プレミアムプランは無制限

#### F-08 血圧×食事相関分析

**概要**  
過去30日以上のデータが蓄積されたユーザーに対して、当日の塩分摂取量と翌日の収縮期血圧の相関係数を算出し、個人特性に合わせた感度スコアを提供する。

**算出ロジック（概略）**
- 入力: 過去N日間の（塩分摂取量g, 翌日最高血圧mmHg）ペア
- ピアソン相関係数rを算出（|r| > 0.3を「相関あり」と判定）
- 「塩分感受性スコア」として0〜100で表示（r×100の絶対値）
- 週次でモデル再計算（バックグラウンドジョブ）

#### F-10 医師向け報告書生成

**概要**  
プレミアムユーザーが「報告書を生成」ボタンを押すと、過去30日間の以下のデータを含むPDFを自動生成する。

**報告書の構成**
1. 表紙（患者情報・報告期間）
2. 血圧推移グラフ（朝晩・折れ線グラフ）
3. 塩分摂取量推移グラフ（棒グラフ）
4. 血圧×塩分の散布図と相関係数
5. 目標達成日数（塩分6g/日以下の日数）
6. 食事写真サムネイル一覧（直近7日間）
7. AIによる総評コメント（200字以内）

---

## 3. 非機能要件

### 3.1 パフォーマンス要件

| 項目 | 目標値 | 計測方法 |
|------|--------|---------|
| 画像解析レスポンス時間 | 中央値2秒以内、P95=5秒以内 | APIログ計測 |
| アプリ起動時間（コールド） | 3秒以内 | Firebase Performance |
| 画面遷移時間 | 300ms以内 | フレームレート計測 |
| API可用性 | 99.5%以上（月次） | Uptime監視 |
| データ同期遅延 | 30秒以内 | バックグラウンド同期ログ |

### 3.2 セキュリティ要件

| 要件 | 対応内容 |
|------|---------|
| 通信暗号化 | TLS 1.3以上、証明書ピンニング実施 |
| データ保管 | 食事写真・血圧データは暗号化（AES-256）してクラウド保存 |
| 認証 | Firebase Authentication（メール/Google/Apple Sign-In） |
| 個人情報 | 個人情報保護法・医療情報ガイドライン準拠 |
| 食事画像 | サーバー上での保管期間は最大2年、ユーザーが削除可能 |
| GDPR対応 | Phase 3（海外展開時）に対応 |

### 3.3 スケーラビリティ要件

- MAU 10万人時にインフラ増強なしで対応可能な設計
- AIモデルの推論はコンテナ化し、負荷に応じてオートスケール
- 同時接続ユーザー数: 最大5,000（Phase 1目標）

### 3.4 アクセシビリティ要件

- 文字サイズ: 最小16px、ダイナミックタイプ対応（iOS）
- カラーコントラスト比: 4.5:1以上（WCAG AA準拠）
- VoiceOver / TalkBack 対応（主要画面）

---

## 4. 画面一覧

| ID | 画面名 | 概要 | フェーズ |
|----|--------|------|---------|
| S-01 | スプラッシュ / オンボーディング | アプリ初回起動・機能紹介・権限許可 | Phase 1 |
| S-02 | ユーザー登録 / ログイン | メール・Google・Apple Sign-In | Phase 1 |
| S-03 | プロフィール設定 | 年齢・性別・高血圧薬服用状況・目標塩分量 | Phase 1 |
| S-04 | ホーム（ダッシュボード） | 本日の塩分摂取量・血圧・コーチングメッセージ | Phase 1 |
| S-05 | 食事撮影 | カメラビュー・撮影ボタン | Phase 1 |
| S-06 | 解析結果 | 塩分量・栄養素・料理名・修正フォーム | Phase 1 |
| S-07 | 食事記録一覧 | カレンダービュー・日別リスト | Phase 1 |
| S-08 | 食事詳細 | 解析結果詳細・写真・メモ | Phase 1 |
| S-09 | 血圧入力 | 収縮期・拡張期・脈拍・測定時刻 | Phase 1 |
| S-10 | 血圧記録一覧 | 折れ線グラフ・リスト | Phase 1 |
| S-11 | 塩分トレンド | 週次・月次グラフ・目標達成状況 | Phase 1 |
| S-12 | 設定 | 通知設定・目標値・アカウント管理 | Phase 1 |
| S-13 | 相関分析 | 血圧×塩分散布図・感受性スコア | Phase 2 |
| S-14 | AIコーチング | 今日のアドバイス・過去のコーチング履歴 | Phase 2 |
| S-15 | 報告書生成 | レポート設定・プレビュー・PDF出力 | Phase 2 |
| S-16 | 食品検索 | 食品名検索・塩分量参照 | Phase 2 |
| S-17 | プレミアム案内 | 機能比較・決済フロー | Phase 1 |
| S-18 | 医療機関ダッシュボード | 患者一覧・個別データビュー（法人プラン） | Phase 3 |

---

## 5. 技術スタック

### 5.1 フロントエンド（モバイル）

| 区分 | 選定技術 | 理由 |
|------|---------|------|
| フレームワーク | React Native（Expo SDK 52） | iOS/Android同時開発、開発速度優先 |
| 言語 | TypeScript 5.x | 型安全性、保守性 |
| 状態管理 | Zustand | 軽量、シンプルなAPI |
| 通信 | TanStack Query v5 | キャッシュ管理、ローディング状態管理 |
| グラフ | Victory Native XL | React Nativeとの親和性が高い |
| ナビゲーション | Expo Router v4 | ファイルベースルーティング |
| 認証 | Firebase Auth SDK | マルチプロバイダ対応 |
| カメラ | expo-camera | ネイティブカメラ統合 |
| ローカルDB | SQLite（expo-sqlite） | オフライン対応 |

### 5.2 バックエンド

| 区分 | 選定技術 | 理由 |
|------|---------|------|
| フレームワーク | FastAPI（Python 3.12） | AI/MLとの親和性、高パフォーマンス |
| ORM | SQLAlchemy 2.0 + Alembic | 型安全なDB操作、マイグレーション管理 |
| データベース | PostgreSQL 16 | リレーショナルデータ、JSONBサポート |
| キャッシュ | Redis 7 | セッション管理、APIキャッシュ |
| タスクキュー | Celery + Redis | 非同期処理（相関分析バッチ等） |
| ストレージ | Cloudflare R2 | 食事画像保存、CDN配信 |
| 認証検証 | Firebase Admin SDK | JWTトークン検証 |
| PDF生成 | WeasyPrint | 報告書PDF生成 |

### 5.3 AI/ML

| 区分 | 選定技術 | 理由 |
|------|---------|------|
| 画像解析 | Google Cloud Vision API + 独自ファインチューン | 物体検出の精度と開発速度のバランス |
| 塩分推定モデル | PyTorch（YOLO v8ベース） | 独自学習データで精度向上 |
| コーチングLLM | Claude claude-sonnet-4-6 API | 自然な日本語コーチングメッセージ生成 |
| 食品データベース | 日本食品標準成分表2020年版（八訂）+ 外食チェーンDB | 国内料理の網羅性 |
| MLOps | MLflow + Weights & Biases | 実験管理・モデルバージョニング |

### 5.4 インフラ

| 区分 | 選定技術 | 理由 |
|------|---------|------|
| クラウド | Google Cloud Platform | AI/ML系サービスとの親和性 |
| コンテナ | Cloud Run（APIサーバー）+ GKE（AI推論） | オートスケール対応 |
| CI/CD | GitHub Actions | 自動テスト・デプロイ |
| 監視 | Cloud Monitoring + Sentry | インフラ監視・エラートラッキング |
| IaC | Terraform | インフラのコード管理 |
| CDN | Cloudflare | グローバル配信・DDoS対策 |

---

## 6. API設計

### 6.1 API基本仕様

- プロトコル: HTTPS REST API
- 認証方式: Firebase JWT Bearer Token
- ベースURL: `https://api.saltcoach.app/v1`
- レスポンス形式: JSON（UTF-8）
- レート制限: 無料プラン 60req/分、プレミアム 300req/分

### 6.2 主要エンドポイント一覧

#### 認証

```
POST   /auth/verify          # JWTトークン検証・ユーザー初期化
DELETE /auth/account         # アカウント削除
```

#### 食事記録

```
POST   /meals                # 食事写真のアップロードと解析依頼
GET    /meals                # 食事記録一覧（クエリ: from, to, limit, offset）
GET    /meals/{meal_id}      # 食事記録詳細
PATCH  /meals/{meal_id}      # 食事記録の手動修正（料理名・塩分量）
DELETE /meals/{meal_id}      # 食事記録の削除
```

#### 血圧記録

```
POST   /blood-pressure       # 血圧記録の登録
GET    /blood-pressure       # 血圧記録一覧（クエリ: from, to）
PATCH  /blood-pressure/{id}  # 血圧記録の修正
DELETE /blood-pressure/{id}  # 血圧記録の削除
```

#### 分析・コーチング

```
GET    /analytics/summary          # 期間集計サマリー（塩分・血圧）
GET    /analytics/correlation      # 血圧×塩分相関分析結果
GET    /coaching/today             # 本日のコーチングメッセージ取得
GET    /coaching/history           # コーチング履歴一覧
```

#### 報告書

```
POST   /reports                    # 報告書生成リクエスト（非同期）
GET    /reports/{report_id}        # 生成状況確認・PDFダウンロードURL取得
```

#### ユーザー設定

```
GET    /profile                    # プロフィール取得
PUT    /profile                    # プロフィール更新
GET    /settings                   # 設定取得
PUT    /settings                   # 設定更新（目標値・通知設定等）
```

### 6.3 主要リクエスト/レスポンス例

#### POST /meals — 食事写真解析

**リクエスト**（multipart/form-data）
```
image: <バイナリ画像データ>
meal_type: "breakfast" | "lunch" | "dinner" | "snack"
eaten_at: "2026-04-21T08:30:00+09:00"
memo: "外食ランチ"  # optional
```

**レスポンス** 200 OK
```json
{
  "meal_id": "m_01HVXXXXXXXXXX",
  "eaten_at": "2026-04-21T08:30:00+09:00",
  "meal_type": "lunch",
  "image_url": "https://cdn.saltcoach.app/meals/m_01HVXXXXXXXXXX.jpg",
  "analysis": {
    "confidence": "high",
    "items": [
      {
        "name": "ラーメン（醤油）",
        "quantity_g": 550,
        "salt_g": 5.8,
        "calories_kcal": 480,
        "protein_g": 22,
        "fat_g": 14,
        "carb_g": 68
      },
      {
        "name": "餃子（3個）",
        "quantity_g": 90,
        "salt_g": 0.9,
        "calories_kcal": 175,
        "protein_g": 8,
        "fat_g": 9,
        "carb_g": 16
      }
    ],
    "total_salt_g": 6.7,
    "total_calories_kcal": 655
  },
  "daily_total_salt_g": 9.2,
  "daily_goal_salt_g": 6.0,
  "daily_goal_exceeded": true
}
```

---

## 7. データモデル（主要テーブル）

```sql
-- ユーザー
CREATE TABLE users (
    id          VARCHAR(28) PRIMARY KEY,  -- Firebase UID
    email       VARCHAR(255) NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    plan        VARCHAR(20) NOT NULL DEFAULT 'free',  -- 'free' | 'premium' | 'clinic'
    profile     JSONB NOT NULL DEFAULT '{}'
);

-- 食事記録
CREATE TABLE meals (
    id          VARCHAR(26) PRIMARY KEY,  -- ULID
    user_id     VARCHAR(28) NOT NULL REFERENCES users(id),
    eaten_at    TIMESTAMPTZ NOT NULL,
    meal_type   VARCHAR(20) NOT NULL,     -- 'breakfast' | 'lunch' | 'dinner' | 'snack'
    image_url   TEXT,
    analysis    JSONB NOT NULL,           -- 解析結果全体
    total_salt_g  NUMERIC(5,2),
    total_kcal    INTEGER,
    memo        TEXT,
    is_manual   BOOLEAN NOT NULL DEFAULT FALSE,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- 血圧記録
CREATE TABLE blood_pressure_records (
    id            VARCHAR(26) PRIMARY KEY,
    user_id       VARCHAR(28) NOT NULL REFERENCES users(id),
    measured_at   TIMESTAMPTZ NOT NULL,
    systolic      SMALLINT NOT NULL,    -- 収縮期血圧 (mmHg)
    diastolic     SMALLINT NOT NULL,   -- 拡張期血圧 (mmHg)
    pulse         SMALLINT,            -- 脈拍
    timing        VARCHAR(10),         -- 'morning' | 'evening'
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- コーチングメッセージ
CREATE TABLE coaching_messages (
    id          VARCHAR(26) PRIMARY KEY,
    user_id     VARCHAR(28) NOT NULL REFERENCES users(id),
    message     TEXT NOT NULL,
    category    VARCHAR(50),           -- 'warning' | 'encouragement' | 'tip'
    delivered_at TIMESTAMPTZ NOT NULL,
    read_at     TIMESTAMPTZ
);
```

---

## 8. テスト方針

| テスト種別 | ツール | カバレッジ目標 |
|-----------|--------|-------------|
| ユニットテスト（バックエンド） | pytest | 80%以上 |
| ユニットテスト（フロントエンド） | Jest + React Native Testing Library | 70%以上 |
| E2Eテスト | Detox（モバイル） | 主要フロー100% |
| AI推論テスト | 専用テストデータセット（500枚） | 塩分推定精度±15%以内 |
| 負荷テスト | Locust | 同時5,000接続でP95<5秒 |
| セキュリティテスト | OWASP ZAP | 四半期1回実施 |
