# 本番セットアップ手順（ピンポイント）

このドキュメントは **Supabase（DB）** と **Vercel（ホスティング・環境変数）** と **Gemini（AI・サーバー専用キー）** をつなぐための最短手順です。順番どおりに進めてください。

---

## 前提

- Google AI Studio または Google Cloud で **Gemini API キー** を取得できること（Gemini 機能を使う場合。**有料階層での運用**が必須。`GEMINI_PAID_PLAN_CONFIRMED` 参照）
- Supabase アカウントがあること
- Vercel にこのリポジトリ（またはフォルダ）をデプロイ済み、またはこれからデプロイできること

---

## 変更をすぐ本番に反映する（デプロイ）

| やり方 | 手順 |
|--------|------|
| **Git が Vercel と連携済み** | 本番用ブランチ（多くは `main`）へ **push** するだけ。ダッシュボードでビルドが走り、完了すると本番 URL が更新されます。 |
| **この PC から CLI で出す** | リポジトリ直下で **`npm install`** のあと **`npm run deploy`**。先に **`npx vercel login`** 済みで、フォルダが Vercel プロジェクトと **リンク**（初回は `vercel link` か `vercel deploy` の対話）されている必要があります。 |
| **プレビュー URL だけ欲しい** | **`npm run deploy:preview`**（本番ドメインではなくプレビュー用 URL が付きます）。 |

環境変数を変えた直後は、**Save したうえで** **Redeploy** または上記 **`npm run deploy`** まで行うとビルドに新しい値が載ります。

---

## service_role キー（`SUPABASE_SERVICE_ROLE_KEY`）の差し替え場所一覧

**Supabase でキーをローテーションしたあと**、次の **該当する行だけ** 新しい値に直します（ソースコードや `.env.example` には実キーを書きません）。

| 場所 | どこを開くか | 設定する名前 | 備考 |
|------|----------------|--------------|------|
| **① このPC（ローカル）** | リポジトリ直下の **`.env.local`** を編集 | `SUPABASE_SERVICE_ROLE_KEY` | `.gitignore` 対象。**右辺**を新キーに差し替え。 |
| **② このPC（ローカル）** | 同上 **`.env.local`** | `SUPABASE_URL` | `api/mental-health*.js` 用。**`VITE_` なし**。Project URL と同じでよい。 |
| **③ 本番・プレビュー（Vercel）** | [Vercel](https://vercel.com) → プロジェクト → **Settings** → **Environment Variables** | `SUPABASE_SERVICE_ROLE_KEY` | **Value** 列を新キーに上書き。Production / Preview など**使っている環境すべて**。 |
| **④ Vercel** | 同上 | `SUPABASE_URL` | **`VITE_` なし**の URL。メンタルヘルス API 用に設定している場合のみ更新。 |
| **⑤ 一時的（CLI）** | PowerShell 等でコマンド実行時のみ | `SUPABASE_SERVICE_ROLE_KEY` | 例: `$env:SUPABASE_SERVICE_ROLE_KEY="…"`（`.env.local` を読まない実行向け） |

**家族通知・ディスパッチ API**（`notify-family` / `family-notification-dispatch`）も **`SUPABASE_SERVICE_ROLE_KEY`** と **`SUPABASE_URL`（または `VITE_SUPABASE_URL`）** を参照します。キーは上表と同じ変数名で統一してください。

**書き換えないもの**

- **`.env.example`** … あくまで雛形（実キー禁止）
- **`src/`・`api/` 内のソース** … キーは埋め込まない（`process.env` で読むだけ）

**差し替え後の作業**

- **Vercel** では **Save** のあと **Redeploy**（再デプロイ）  
- **ローカル**では **ターミナル／エディタを開き直す**、または **`vercel dev` を再起動**

---

## 1. Supabase でプロジェクトを作成

1. [Supabase Dashboard](https://supabase.com/dashboard) で **New project** を作成します。
2. データベースのパスワードを控えます（後で直接はほぼ不要ですが、バックアップ用に保存推奨）。

---

## 2. SQL を本番 DB に流す

1. Supabase ダッシュボードで対象プロジェクトを開きます。
2. 左メニュー **SQL Editor** を開きます。
3. **New query** を選び、リポジトリ内の次のファイルの **全文** をコピーして貼り付けます。  
   `supabase/migrations/20260419120000_init.sql`
4. **Run** を実行します。エラーがなければテーブル・RLS・ストレージバケット・デモ施設データが作成されます。

### 2b. init 以降のマイグレーション（機能追加）

`init.sql` のあと、Git の **`supabase/migrations/`** にある **時系列の番号付き SQL** を、未適用のものから順に SQL Editor で実行するか、`supabase db push` で適用します。

| ファイル（例） | 概要 |
|----------------|------|
| `20260424_220000_face_auth.sql` | 顔認証・face_logs 等 |
| `20260424_mental_health.sql` | メンタルヘルス |
| `20260426120000_tenant_features.sql` | テナント機能フラグ |
| `20260429120000_med_image_ai_staff_log.sql` | AI 画像分析ログ |
| `20260429140000_consent_audit_ai.sql` | 同意・監査 |
| `20260503120000_image_change_detection.sql` | **画像変化検知**テーブル・RLS |
| `20260505120000_get_previous_image_record_rpc.sql` | **前回画像取得 RPC** |
| `20260510120000_family_notification_optimization.sql` | **家族通知ログ** `family_notification_logs`・RLS・索引（閲覧パターン最適化の遅延通知） |

**試験用ダミーデータ**はマイグレーションに**含めません**。必要なときだけ SQL Editor で **[`scripts/sql/dummy-image-change-test-data.sql`](../scripts/sql/dummy-image-change-test-data.sql)** を実行します（手順・削除・テスト段階は **[`dummy-data-creation-guide.md`](./dummy-data-creation-guide.md)**）。家族通知の SQL 参照用全文は **[`docs/sql/family_notification_optimization.sql`](./sql/family_notification_optimization.sql)** も併せてください。

### 実行後の確認（任意）

- **Table Editor** に `tenants` / `residents` / `profiles` などが見えること
- **Storage** に `record-photos` バケットがあること
- 画像変化検知を使う場合: `image_change_detections` / `image_analysis_log` が存在し、Database → Functions に **`get_previous_image_record`** があること
- 家族通知を使う場合: **`family_notification_logs`** テーブルと関連 RLS が存在すること

---

## 3. Supabase の API キーと URL を控える

1. **Project Settings**（歯車）→ **API** を開きます。
2. 次をコピーします（Vercel に貼るため）。
   - **Project URL** → `https://xxxx.supabase.co` 形式  
   - ブラウザ用キー: **Publishable**（`sb_publishable_…`）または **Legacy の anon public**（`eyJ...` の JWT）

> **Secret**（`sb_secret_…`）と **service_role**（JWT）はフロントや Git に入れないでください。ブラウザからは **Publishable または anon** のみ使用します。  
> **補足:** `api/mental-health.js` / `api/mental-health-batch.js` や CLI が **シークレット / service_role** を参照する場合は、Vercel（または `vercel dev`）に **`SUPABASE_URL`** と **`SUPABASE_SERVICE_ROLE_KEY`**（Legacy JWT またはダッシュボードの **Secret** と同列のサーバー用キー）を **`VITE_` なし**で設定します。キーをローテーションしたら **差し替え、再デプロイ**してください。

---

## 4. Authentication を有効にする

1. 左メニュー **Authentication** → **Providers** を開きます。
2. **Email** プロバイダを有効にします（メール確認の要否は運用に合わせて設定）。

---

## 5. Vercel に環境変数を入れる

1. [Vercel Dashboard](https://vercel.com) でこのプロジェクトを開きます。
2. **Settings** → **Environment Variables** を開きます。
3. 少なくとも次の **必須 3 項目** を追加し、必要に応じて **任意 2 項目** を追加します（名前は **完全一致** で）。

| Name | Value | 適用先 |
|------|--------|--------|
| `VITE_SUPABASE_URL` | Supabase の Project URL | Production, Preview, Development すべて推奨 |
| `VITE_SUPABASE_ANON_KEY` | **Publishable**（`sb_publishable_…`）または Legacy の **anon public**（JWT） | 同上。**`sb_secret_` や service_role JWT を入れない**（ブラウザで Forbidden になる） |
| `GEMINI_API_KEY` | Google の Gemini API キー | 同上（**サーバー専用**。`VITE_` は付けない） |
| `GEMINI_PAID_PLAN_CONFIRMED` | `true` または `1` | Gemini を使う場合は必須（**無料プラン運用禁止**のサーバー側ガード） |
| `SUPABASE_URL`（任意） | Project URL（`VITE_` なし） | メンタルヘルス API / バッチ・**画像変化検知 API**・**家族通知 API** 等で service_role を使う場合 |
| `SUPABASE_SERVICE_ROLE_KEY`（任意） | service_role シークレット | **上記を使う場合のみ**。画像変化検知では RPC・署名付き URL 解決に使用。**`notify-family` / `family-notification-dispatch`** にも必要。**キー更新後は差し替え→再デプロイ** |
| `CRON_SECRET`（推奨） | ランダムな長い文字列 | Vercel Cron が呼ぶ **`/api/mental-health-batch`**・**`/api/precursor-alerts-batch`**・**`/api/family-notification-dispatch`** の不正利用防止。**Authorization: Bearer（値は環境変数と同一）** |

4. **Save** 後、**再デプロイ**が必要です。  
   - **Deployments** から最新デプロイの **⋯** → **Redeploy**  
   - または Git に空コミットを push して再ビルド

> `VITE_` で始まる変数だけがブラウザに埋め込まれます。`GEMINI_API_KEY`・`SUPABASE_SERVICE_ROLE_KEY` は **`api/` やサーバー**からのみ参照され、クライアントには出ません。

### Vercel Cron（日次バッチ）

`vercel.json` で次がスケジュールされます（UTC）。

| パス | 時刻（UTC） | 内容 |
|------|----------------|------|
| `/api/mental-health-batch` | `0 21 * * *` | 利用者ごとに記録を集約し、Gemini（`/api/mental-health`）でリスク参考情報を更新 |
| `/api/precursor-alerts-batch` | `15 21 * * *` | `daily_records` 過去90日からルール検知し、`team_messages` に「予兆アラート」（Gemini 不使用） |
| `/api/family-notification-dispatch` | `30 21 * * *` | **`family_notification_logs`** の予定時刻到来分を処理し **`contact_messages`** へ挿入（Gemini 不使用）。**Vercel Hobby では 1 日 1 回までの Cron しか持てない**ため、当初案の 10 分毎は **Pro プランまたは外部 Cron** に切り替えるまで日次運用 |

- **`CRON_SECRET`** を設定している場合、Cron の Authorization と一致させる（本番では設定推奨）。
- 仕様: [`feature-precursor-alerts.md`](./feature-precursor-alerts.md) · 家族通知: [`feature-family-notification.md`](./feature-family-notification.md)

**画像変化検知を本番で使う場合（追加メモ）**

- **`/api/save-staff-action`** は、サーバー上で **`VITE_SUPABASE_ANON_KEY`** と職員の **Bearer access_token** を組み合わせ、RLS のまま `image_change_detections` を更新します。Vercel に **`VITE_SUPABASE_ANON_KEY`** が無いと 503 になります。
- ブラウザから **`/api/*`** を呼ぶため、ローカル検証は **`npm run dev` だけでは足りない**ことがあります。**`npx vercel dev`**（または `npm run dev:vercel`）またはデプロイ済み URL で試してください。
- 仕様の正: [`feature-image-change-detection.md`](./feature-image-change-detection.md) · 試験手順: [`dummy-data-creation-guide.md`](./dummy-data-creation-guide.md)

---

## 6. Gemini API キーの取得（参考）

1. [Google AI Studio](https://aistudio.google.com/) などで API キーを作成します。
2. そのキーを Vercel の `GEMINI_API_KEY` に設定します（上記）。

モデル名は既定で `gemini-2.0-flash` です。利用プランやリージョンで失敗する場合は、`api/gemini.js` の既定モデル文字列を `gemini-1.5-flash` などに変更するか、将来クライアントから `model` を渡す実装に拡張できます。

---

## 7. 動作確認チェックリスト

デプロイ済み URL（本番例: `https://tsunagarucho.jp`）で確認します。

1. **ホーム**が開く  
2. **ログイン**画面で Supabase にユーザーを作成したうえでログインできる（Auth 設定後）  
3. **職員記録**で記録を保存でき、Supabase の **Table Editor** → `daily_records` に行が増える  
4. **Gemini で申し送り案** を押すと、申し送り欄に文章が入る（`GEMINI_API_KEY` 設定済み・本番または `vercel dev`）  
5. （任意）**職員記録で写真付き保存**後、同一利用者に前回画像付き記録がある場合、**画像変化検知**の API・パネルが動く（`SUPABASE_SERVICE_ROLE_KEY`・関連マイグレ済み・Storage に実画像）  
6. （任意）**予兆アラート**：Cron 実行後、`team_messages` に `[予兆アラート]` が増えるか（閾値を満たすテストデータがある場合）
7. （任意）**家族通知**：記録保存から `family_notification_logs` が増え、`family-notification-dispatch` 実行後に `contact_messages` が増えるか（[`feature-family-notification.md`](./feature-family-notification.md)）
8. **ログイン画面の言語切替**：`https://（本番）/login.html` で地球アイコンから英語等へ切替え、文言が変わること（[`feature-login-i18n.md`](./feature-login-i18n.md)）

### ローカルで Gemini API を試す

- `npm run dev` だけでは `/api/gemini` が無いことがあります。  
- プロジェクトルートで次を実行すると、Vite と API をまとめて起動できます。

```bash
npx vercel dev
```

---

## 8. よくある詰まり

| 現象 | 対処 |
|------|------|
| ログイン時に **Forbidden use of secret API key in browser** と出る | **`VITE_SUPABASE_ANON_KEY`** を **Publishable** または **Legacy anon（JWT）** に直す。**`sb_secret_`（シークレット）** と **service_role（JWT）** は **`SUPABASE_SERVICE_ROLE_KEY`**（`VITE_` なし）にだけ。Vercel の **Production / Preview** 両方を確認し、**再デプロイ**。 |
| ログインできない | Email プロバイダ有効化・メール確認設定・RLS まわりを確認 |
| 記録が保存されない | `VITE_SUPABASE_*` がデプロイに反映されているか再デプロイ |
| Gemini が 503 | Vercel に `GEMINI_API_KEY` が無い、または再デプロイ前 |
| Gemini が 502 | モデル名や API キー権限、Google 側の利用制限を確認 |
| 画像変化検知が 503 / 失敗 | Vercel に `SUPABASE_SERVICE_ROLE_KEY` と `SUPABASE_URL`（または `VITE_SUPABASE_URL`）、`VITE_SUPABASE_ANON_KEY` が揃っているか。`npm run dev` 単体では `/api` が無い → **`vercel dev`** または本番 URL で試す |
| OpenCV が読み込めない | CDN（`docs.opencv.org`）への到達・端末のメモリ。回線制限でブロックされていないか |
| メンタル／予兆の Cron が 401 | **`CRON_SECRET`** を Vercel に入れた場合、Cron の Bearer と一致しているか確認 |
| 予兆アラートが飛ばない | 過去90日・閾値・同一コード **36時間以内の重複抑止** を確認。`daily_records` に食事・気分・体重が入っているか |
| **`vercel deploy` が Cron で失敗**（Hobby limit 等） | **`vercel.json`** の `crons[].schedule` が **1 日 1 回以下**か確認。短間隔が必要なら **Pro** または **外部スケジューラ**で `/api/...` を叩く |
| ログインで**言語を変えても日本語のまま** | `public/locales` の **`login`** キーと `login.html` の **`data-i18n`**、`login.js` の **`i18n:locale`** 再適用を確認（[`feature-login-i18n.md`](./feature-login-i18n.md)） |
| 家族通知が飛ばない | マイグレ適用・`SUPABASE_SERVICE_ROLE_KEY`・職員 JWT 経由の `notify-family`・Cron の **`CRON_SECRET`**・日次ディスパッチの待ち時間を確認 |

---

## 9. 家族ユーザーと利用者の紐づけ

家族ロールでサインアップしたユーザーは、`profiles.resident_id` を **デモ利用者の UUID** などに手動で設定する必要がある場合があります。Supabase **SQL Editor** で更新するか、Table Editor で `profiles` を編集します（運用ルールに合わせてください）。

---

## 10. 契約施設向け（表示文言・QR・文書）

実企業・契約施設で運用するときは、次を揃えると安全です。

| 項目 | 内容 |
|------|------|
| `public/config/tenants.v1.json` | テナントID（`tenants.slug` と一致）ごとに `brand_name`・`public_notice_ja`・`ai_disclaimer_ja` を定義。デプロイ後は `/config/tenants.v1.json` で配信されます。 |
| QR | 本番 URL が決まったら `qr-tenant.html`（ルート直下）で `?tenant=` 付きURLのQRを発行。 |
| 手順書 | `docs/operator-onboarding-ja.html`（運営者）· `docs/facility-playbook-ja.html`（現場）· `docs/terms-enterprise-ja.html`（利用上の注意のひな形）。 |
| 索引 | **[`DOCUMENTATION_INDEX.md`](./DOCUMENTATION_INDEX.md)** … 仕様・手順・`public/docs` の法務資料への対応表 |

HTTP セキュリティヘッダは `vercel.json` で設定しています。

以上です。
