1. 全体アーキテクチャと役割
| 役割 | 技術スタック | やること |
|---|---|---|
| アプリ (Front) | Flutter | ユーザーUI。Cloud Functions を叩く。Firestore/Storage は直接読み書きする。 |
| 門番 (Back) | Cloud Functions | Gemini APIの隠蔽。レートリミット管理。JSON整形。 |
| DB (Limit) | Firestore | レートリミットの回数カウント用(管理者が読み書き)。 |
| AI | Gemini API | プロンプトを受け取り、JSONを返す。 |
2. 【最重要】プロジェクト接続先の管理
ここが今回の一番のハマりポイントでした。「フロントとバックエンドは、別々の設定を見ている」 という点です。
❌ よくある事故(ねじれ現象)
ターミナルで firebase use だけしてデプロイすると…
- バックエンドは「開発環境」にデプロイされたのに、
- アプリは「本番環境」を見に行こうとしてエラーになる(またはその逆)。
✅ 正しい切り替え手順(2ステップ必須)
環境(Dev / Prodなど)を変えるときは、必ず両方やります。
| 対象 | 見ている場所 | 切り替えコマンド |
|---|---|---|
| Cloud Functions (サーバー側) | .firebaserc(CLIの設定) | firebase use <プロジェクトID>↓ firebase deploy |
| Flutterアプリ (スマホ側) | lib/firebase_options.dart(コード内の設定) | flutterfire configure(対話形式でプロジェクト選択) |
3. Gemini API の実装ポイント
- JSONで返す: プロンプトで指示するだけでなく、
responseMimeType: 'application/json'を設定すると確実。 - パース: 返ってきた文字列を
JSON.parse(text)してオブジェクトにしてからフロントに返す。 - ログ: クラウドのログには
severityやmessageが付くが、returnするデータ自体は綺麗なので気にしなくてOK。
4. レートリミット(Firestore)の実装
Cloudflare D1 ではなく Firestore を採用しました。Google内部通信なので高速で、無料枠も大きいです。
- ライブラリ: バックエンド側では
firebase-adminを使う(npm install firebase-admin)。 - 認証:
initializeApp()(引数なし)でOK。サーバーの特権(Admin)で動くのでAPIキー不要。 - ロジック:「Lazy Reset(遅延リセット)」方式を採用。
- Redisのように勝手に消えないので、「アクセスされた瞬間に
resetAtを過ぎていたらカウントをリセットする」というコードを書く。
- Redisのように勝手に消えないので、「アクセスされた瞬間に
- データ作成: 事前にコンソールで作る必要なし。コードが
set()した瞬間にドキュメントは自動生成される。
5. セキュリティの考え方
- Gemini APIキー: 「無制限のクレジットカード」と同じ。絶対にフロント(アプリ)には置かない。Functionsに隠す。
- Firestore / Storage: アプリから直接叩いてOK。
- なぜ? → アプリが持っているキーは「住所」だけで、「鍵(権限)」はサーバー側の Security Rules と Firebase Auth で管理されているから。
- App Check: アプリが「本物である」ことを証明する仕組み。導入済み(
keytoolでSHA-256登録、pub add)。
6. 開発時の便利コマンド集
# 1. サーバー側のプロジェクト切り替え
firebase use <プロジェクトID>
# 2. 関数をデプロイ
firebase deploy --only functions
# 3. アプリ側のプロジェクト設定を更新(これが重要!)
flutterfire configure
# 4. パッケージ追加(必要になったら)
# サーバー側
cd functions && npm install <パッケージ名>
# アプリ側
flutter pub add <パッケージ名>

コメント