# レシピクリップボード 自動栄養計算

# サービス概要

クックパッドなどのレシピサイトからテキストをコピペするだけで、材料を自動抽出し栄養価を計算。家族の食事制限（カロリー、塩分、アレルゲンなど）に基づいた献立の可否判定を30秒で完成させるツール。クリップボード監視により「貼り付けるだけ」という手軽さが実現でき、日々の食事管理の負担を劇的に軽減する。

# MVP のスコープ

## MUST(必須・これが無いとサービスが成立しない)

- クリップボード監視機能：ユーザーがテキストをコピーすると自動検出
- テキストからの材料抽出：正規表現＋簡易NLP で材料名と分量を抽出
- 栄養価データベース：日本食品標準成分表をベースにした栄養価マスタ（カロリー、タンパク質、脂質、炭水化物、塩分など）
- 家族プロファイル管理：食事制限条件（カロリー上限、塩分上限、アレルゲン）を登録
- 献立判定ロジック：抽出した栄養価が制限条件を満たすか判定し、可否を表示

## SHOULD(あれば良いが MVP では入れない)

- 複数レシピの組み合わせ提案（献立セット提案）
- 栄養価グラフ表示（日次・週次の栄養摂取推移）
- レシピの保存・お気に入り機能
- SNS シェア機能

## WON'T(今回は作らない)

- 音声入力によるレシピ読み込み：音声認識の精度確保に時間がかかり、MVP では不要。テキスト入力で十分。
- 複雑な献立自動生成AI：栄養バランスの最適化には機械学習が必要で、個人開発では実装コスト高。判定機能に留める。
- モバイルアプリ（iOS/Android ネイティブ）：Web版で十分動作し、開発工数が2倍以上になるため。PWA で対応。
- リアルタイムコラボレーション：複数ユーザーの同時編集は認証・DB設計が複雑化し、初期段階では不要。
- 栄養士による個別コンサルティング機能：人手が必要で、スケーラビリティが失われるため。

# 削るべき機能と理由

1. **栄養価の自動更新機能（外部API連携）**
   - 削る理由：日本食品標準成分表は年1回程度の更新で十分。静的CSVで運用し、手動更新で対応可能。API化すると外部依存が増し、保守負担が増加。

2. **複数言語対応（英語・中国語など）**
   - 削る理由：初期ユーザーは日本の主婦層に限定。言語対応は多言語化時に段階的に進める方が効率的。

3. **高度な自然言語処理による材料抽出の精度向上**
   - 削る理由：正規表現＋簡易ルールで80%の精度が得られれば MVP として十分。残り20%は手動修正で対応。深層学習は後段階で検討。

# 画面一覧と遷移

- **ログイン画面**：メールアドレス・パスワードでログイン。初回は新規登録フォーム表示。
- **ホーム画面**：最新の献立判定結果を表示。「新しいレシピを入力」ボタンで入力画面へ。
- **レシピ入力画面**：テキストエリアにレシピをペースト。自動で材料抽出＆栄養計算。
- **献立判定結果画面**：抽出した材料、計算された栄養価、家族プロファイルごとの可否判定を表示。
- **家族プロファイル管理画面**：食事制限条件（名前、カロリー上限、塩分上限、アレルゲン）を登録・編集。
- **履歴画面**：過去に入力したレシピと判定結果を一覧表示。

```mermaid
flowchart LR
    A["ログイン画面"] --> B["ホーム画面"]
    B --> C["レシピ入力画面"]
    C --> D["献立判定結果画面"]
    D --> E["履歴画面"]
    D --> F["家族プロファイル管理"]
    F --> B
    E --> B
```

# データモデル

```prisma
// ユーザーテーブル
model User {
  id            String   @id @default(cuid())
  email         String   @unique
  passwordHash  String
  name          String
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt
  
  profiles      FamilyProfile[]
  recipes       Recipe[]
}

// 家族プロファイル（食事制限条件）
model FamilyProfile {
  id                String   @id @default(cuid())
  userId            String
  user              User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  
  name              String   // 家族メンバー名
  calorieLimit      Int      // カロリー上限（kcal）
  saltLimit         Float    // 塩分上限（g）
  allergens         String   // アレルゲン（カンマ区切り）
  
  createdAt         DateTime @default(now())
  updatedAt         DateTime @updatedAt
  
  @@index([userId])
}

// レシピテーブル
model Recipe {
  id                String   @id @default(cuid())
  userId            String
  user              User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  
  title             String   // レシピタイトル
  rawText           String   @db.Text // 元のテキスト
  
  createdAt         DateTime @default(now())
  updatedAt         DateTime @updatedAt
  
  ingredients       Ingredient[]
  nutritionData     NutritionData?
  judgements        Judgement[]
  
  @@index([userId])
}

// 材料テーブル
model Ingredient {
  id                String   @id @default(cuid())
  recipeId          String
  recipe            Recipe   @relation(fields: [recipeId], references: [id], onDelete: Cascade)
  
  name              String   // 材料名
  quantity          Float    // 分量
  unit              String   // 単位（g, 個, 杯など）
  
  createdAt         DateTime @default(now())
  
  @@index([recipeId])
}

// 栄養価データベース（マスタ）
model FoodNutrition {
  id                String   @id @default(cuid())
  foodName          String   @unique
  
  caloriePerUnit    Float    // 100gあたりのカロリー（kcal）
  proteinPerUnit    Float    // 100gあたりのタンパク質（g）
  fatPerUnit        Float    // 100gあたりの脂質（g）
  carbsPerUnit      Float    // 100gあたりの炭水化物（g）
  saltPerUnit       Float    // 100gあたりの塩分（g）
  
  createdAt         DateTime @default(now())
  updatedAt         DateTime @updatedAt
}

// レシピの栄養価集計
model NutritionData {
  id                String   @id @default(cuid())
  recipeId          String   @unique
  recipe            Recipe   @relation(fields: [recipeId], references: [id], onDelete: Cascade)
  
  totalCalorie      Float    // 総カロリー（kcal）
  totalProtein      Float    // 総タンパク質（g）
  totalFat          Float    // 総脂質（g）
  totalCarbs        Float    // 総炭水化物（g）
  totalSalt         Float    // 総塩分（g）
  
  createdAt         DateTime @default(now())
  updatedAt         DateTime @updatedAt
}

// 献立判定結果
model Judgement {
  id                String   @id @default(cuid())
  recipeId          String
  recipe            Recipe   @relation(fields: [recipeId], references: [id], onDelete: Cascade)
  profileId         String
  
  isOk              Boolean  // 制限条件を満たすか
  reason            String   // 判定理由（カロリー超過など）
  
  createdAt         DateTime @default(now())
  
  @@index([recipeId])
  @@index([profileId])
}
```

# 主要 API エンドポイント

| メソッド | パス | 目的 | 認証 |
|---------|------|------|------|
| POST | `/api/auth/register` | ユーザー新規登録 | 不要 |
| POST | `/api/auth/login` | ログイン | 不要 |
| POST | `/api/auth/logout` | ログアウト | 必要 |
| GET | `/api/profiles` | 家族プロファイル一覧取得 | 必要 |
| POST | `/api/profiles` | 家族プロファイル作成 | 必要 |
| PUT | `/api/profiles/:id` | 家族プロファイル更新 | 必要 |
| DELETE | `/api/profiles/:id` | 家族プロファイル削除 | 必要 |
| POST | `/api/recipes/analyze` | レシピテキスト解析（材料抽出＆栄養計算） | 必要 |
| GET | `/api/recipes` | レシピ履歴一覧取得 | 必要 |
| GET | `/api/recipes/:id` | レシピ詳細取得 | 必要 |
| DELETE | `/api/recipes/:id` | レシピ削除 | 必要 |
| GET | `/api/nutrition/foods` | 栄養価マスタ検索 | 必要 |

# 技術スタック推奨

- **フロントエンド**: Next.js 14 (App Router) + TypeScript + TailwindCSS
  - 理由：SSR対応で SEO に強く、API ルートも同一プロジェクトで管理可能。個人開発で学習コストが低い。
  
- **バックエンド**: Next.js API Routes + Node.js
  - 理由：フロントエンドと同一言語で、デプロイ構成がシンプル。小規模サービスではオーバーヘッドが少ない。
  
- **DB**: PostgreSQL（Supabase 推奨）
  - 理由：Prisma ORM の相性が良く、無料枠で十分。リレーショナルデータに適している。
  
- **ホスティング**: Vercel
  - 理由：Next.js の公式ホスティング。デプロイが自動化され、個人開発者向けに無料枠が充実。
  
- **外部 API**: なし（初期段階）
  - 理由：栄養価データは静的 CSV で管理し、外部依存を最小化。後段階で USDA API などを検討。

# 外部サービス・API と想定コスト

| サービス | 用途 | 想定月額 |
|---------|------|---------|
| Supabase | PostgreSQL ホスティング | 無料（初期段階） |
| Vercel | フロントエンド＆API ホスティング | 無料（初期段階） |
| SendGrid | メール送信（パスワードリセットなど） | 無料（月100通まで） |
| **合計** | | **無料** |

※ ユーザー数が増加した場合、Supabase は月 $25〜、Vercel は月 $20〜 の有料プランへの移行を検討。

# Claude Code 向け実装プロンプト

```
以下の仕様に基づいて、Next.js 14 (App Router) + TypeScript + Prisma + PostgreSQL で「レシピクリップボード 自動栄養計算」を実装してください。

【ステップ1】プロジェクト初期化
- `npx create-next-app@latest recipe-clipboard --typescript --tailwind` で Next.js プロジェクトを作成
- Prisma をインストール：`npm install @prisma/client` と `npm install -D prisma`
- `.env.local` に Supabase の DATABASE_URL を設定

【ステップ2】Prisma スキーマ定義
- `prisma/schema.prisma` に上記「データモデル」セクションのスキーマを全て記述
- `npx prisma migrate dev --name init` で初期マイグレーション実行
- `npx prisma db seed` で栄養価マスタ（FoodNutrition）に日本食品標準成分表の主要100品目を CSV から INSERT

【ステップ3】認証機能実装
- `app/api/auth/register` と `app/api/auth/login` エンドポイントを実装
- bcrypt でパスワードをハッシュ化
- JWT トークンを httpOnly Cookie に保存
- `lib/auth.ts` に認証ミドルウェアを実装し、API ルートで認証チェック

【ステップ4】材料抽出ロジック実装
- `lib/recipeParser.ts` に正規表現ベースの材料抽出関数を実装
  - 入力：レシピテキスト（例：「玉ねぎ 1個」「塩 小さじ1」）
  - 出力：`{ name: string, quantity: number, unit: string }[]`
- 単位の正規化（「個」→「個」、「小さじ1」→「5g」相当など）を実装

【ステップ5】栄養価計算ロジック実装
- `lib/nutritionCalculator.ts` に栄養価計算関数を実装
  - 入力：抽出した材料配列 + FoodNutrition マスタ
  - 出力：`{ totalCalorie, totalProtein, totalFat, totalCarbs, totalSalt }`
- 材料名とマスタの食品名をファジーマ