4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AIは、コーヒーの「心」を読めるか?- FlutterとGeminiで、最強の「AI焙煎メンター」を創る話【アプリ設計全公開】

4
Last updated at Posted at 2025-06-23

はじめに

以下の文章は、生成aiに作らせたものをコピペしただけです。
構成は友人のブログページ @tama0931 のマークダウン形式出力をコピーしたものを、Google ai studioで現在開発しているセクションに「こんな感じのやつ作って」と生成させたものです。許可はちゃんと取ってます!優しい!チュキ!ここで色々語るのもうるさいので早速本題に入ります!
⇩⇩⇩

週末、趣味の手回し焙煎に没頭していた、しがない個人開発者です。
今回は、私が「自分が本当に欲しいもの」を追い求めて開発している、AI駆動型 手回し焙煎ログアプリの、設計思想とアーキテクチャの全てを、ここに記録します。

「今日の焙煎、なぜか、めちゃくちゃ上手くいったぞ…?」
「昨日の失敗、もう二度と繰り返したくない…」

そんな、手回し焙煎家が必ずぶつかる、再現不能な「感覚の壁」
その壁を、データとAIの力で打ち破り、全ての焙煎を「再現可能な科学」と「最高の楽しさ」に変える。
そんな夢のようなアプリの、**「骨格」と「神経網」**が、どう作られているのか。

この記事が、これからFlutterやFirebaseで、AIを相棒に、何かを作ろうとしている、誰か一人の「北極星」になれば、これほど嬉しいことはありません。

✅ 今回の達成内容

  • 焙煎ログのCRUD (Create, Read, Update, Delete) 基本機能の実装
  • AI (Gemini API) との連携 による、焙煎データ分析&フィードバック機能
  • リアルタイムUI更新 (StreamBuilder)
  • 洗練された入力体験 (DatePicker, モーダルフォーム)

🛠️ 技術スタック

  • フレームワーク : Flutter
  • 言語: Dart
  • データベース : Cloud Firestore (Firebase)
  • UI: Material 3
  • 開発パートナー : Gemini API 🤖
  • バージョン管理 : Git / GitHub

📋 システム設計の考え方

「記録」を「気づき」に変える、魔法のサイクル

このアプリの心臓部は、「ユーザーの体験を、可能な限りシンプルに、そしてリッチにする」という思想に基づいています。ユーザーはただ焙煎の記録を入力するだけ。すると、バックエンドでAIが働き、ユーザーに新たな「気づき」を与えてくれる。この魔法のような体験を、低コストかつ高速に実現するため、FlutterとFirebase、そしてGemini APIを中心とした、モダンなサーバーレスアーキテクチャを選択しました。


🗄️ データベース設計の考慮点

シンプルさと拡張性を両立する、Firestore設計

データベースには、ドキュメント指向で柔軟性の高いCloud Firestoreを採用しました。MVP段階では、複雑なリレーションを避け、直感的で拡張しやすい構造を最優先しています。

(注: 現状の実装では、USERSテーブルはまだなく、ROAST_LOGSをトップレベルコレクションとして扱っています。上記は将来的な拡張を見越した理想形です)

🎯 設計のポイント

  1. 非正規化の許容: まずはroastLogsコレクション一つでスタート。ユーザー認証導入後も、user_idフィールドを追加するだけで、スケーラブルなデータ管理が可能です。
  2. 時系列データの重視: ユーザーが入力するroastDateとは別に、ソート用のcreatedAtをサーバータイムスタンプで記録。これにより、データの整合性と柔軟なクエリを両立します。
  3. AIフィードバックの永続化: aiFeedbackフィールドを設けることで、一度生成したAIからの貴重なアドバイスを永続化。APIコストを削減しつつ、ユーザーがいつでも過去の「物語」を振り返れるようにします。

🔧 実装アーキテクチャ

AI連携とリアクティブUIの融合

このアプリの「魔法」を実現する、二つの重要な実装パターンについて解説します。

1. AI連携の非同期UX

ユーザーが「保存」ボタンを押してから、UIが固まることなく、裏側でFirestoreへの保存とGemini APIへのリクエストを処理する。この快適なUXを実現するために、Future.wait(あるいは、それに準ずる直列処理)と、ローディング表示を組み合わせたアーキテクチャを採用しています。

// add_roast_log_form.dart の _saveLog 関数の概念

Future<void> saveLog() async {
  // 1. ユーザーを待たせない、ローディングUIを表示
  showLoadingDialog();

  try {
    final logData = getFormDataFromUI();

    // 2. まず、AIに分析を依頼し、フィードバックを取得
    final aiFeedback = await aiService.getRoastFeedback(logData);
    
    // 3. AIのフィードバックも含めて、完全なデータをFirestoreに保存
    final finalLogData = { ...logData, 'aiFeedback': aiFeedback };
    await firestore.collection("roastLogs").add(finalLogData);

    // 4. 全てが完了したら、ローディングを閉じ、成功を伝える
    closeLoadingDialog();
    showSuccessSnackBar("AIの分析が完了しました!");
    
  } catch (error) {
    // 5. エラー時も、必ずローディングを閉じ、原因を伝える
    closeLoadingDialog();
    showErrorSnackBar(error);
  }
}

2. Firestore StreamBuilderによるリアクティブUI

データの表示には、Firestoreの**StreamBuilder**を全面的に採用。これにより、データが変更(追加、更新、削除)されると、アプリのUIが、何もしなくても自動的に、リアルタイムで再描画されるという、Flutterの最も強力な機能の一つを、最大限に活用しています。


😤 つまずいたポイントと解決策

1. 3584個のXcode警告と、「ゴースト」ファイル

問題: flutter cleanしても、pod installしても、Xcodeでビルドすると、3584個という、天文学的な数の警告が発生。
Stale file '.../cloud_firestore.framework' is located outside of the allowed root paths.
という、不気味なメッセージが、その原因でした。

解決策: これは、過去のビルドの失敗により、プロジェクト内に古い、腐敗した「幽霊」のようなキャッシュファイルが、不法に存在していたことが原因でした。
最終的に、以下の**「ゴースト・バスターズ作戦」**によって、全ての幽霊を、完全に退治しました。

# プロジェクトを、物理的に、浄化する
flutter clean
cd ios
rm -rf Podfile.lock Pods .symlinks Runner.xcworkspace
pod cache clean --all # Mac全体のキャッシュをも掃除する、最終兵器
cd ..
flutter pub get
# 最後に、アーキテクチャの壁を超える、魔法の呪文
cd ios
arch -x86_64 pod install

2. 「沈黙のカレンダー」と、非同期UIの罠

問題: DatePickerを呼び出すボタンをタップしても、エラーも出ず、何も起きないという、最も厄介な「沈黙の壁」に、何度も、何度も、ぶつかりました。

解決策: この原因は、一つではありませんでした。

  • pubspec.yamlへのintlflutter_localizationsの追加漏れ
  • main.dartでの、国際化対応設定の不足
  • 非同期処理の谷間を越えてBuildContextを使おうとしたことによる、デバッガーのハングアップ

これら、全ての「罠」を、一つずつ、デバッグログを仕掛け、原因を特定し、乗り越えることで、ついに、美しい日本語化されたカレンダーを、表示させることができました。


💡 学んだこと・Tips

Flutter × Firebase iOS開発の「お作法」

  1. podは、友達。でも、時々、反乱する。: iOSのビルドで、原因不明のエラーが出たら、まずiosフォルダ内のPodfile.lock, Pods, Runner.xcworkspaceを削除し、pod installし直すのが、最も確実な「お清め」である。
  2. M1/M2/M3 Macは、「翻訳機」を意識する: Apple Silicon搭載のMacでpod installが失敗する場合、arch -x86_64 pod installという「魔法の呪文」が、アーキテクチャの壁を破壊してくれることがある。
  3. 非同期の「谷間」を、信じるな: asyncを伴う処理の後で、UIを操作(NavigatorScaffoldMessenger)する場合は、必ず、awaitの**「前」**に、contextから必要なものを変数に保存しておく。これが、非同期UIの「黄金律」である。
  4. pubspec.yamlは、全ての「設計図」: 新しいパッケージを使いたい時は、まず、この「持ち物リスト」に、正しく、宣言する。全ての依存関係は、ここから、始まる。

おわりに

この数日間は、まさに「地獄」でした。
しかし、その果てに、「AIが、私の焙煎に、初めて、言葉を与えてくれた」、あの瞬間の感動は、一生、忘れることはないでしょう。

この記事が、これからFlutterとFirebase、そしてAIという、エキサイティングな世界に飛び込もうとしている、誰か一人の、小さな「勇気」や「道しるべ」になれば、これほど嬉しいことはありません。

最後まで読んでいただき、本当に、ありがとうございました!
いいね・ストック・コメントで、この、しがない個人開発者を応援していただけると、焙煎する豆が、一つ、グレードアップします🚀

#Flutter #Firebase #Gemini #AI #個人開発 #アプリ開発 #Qiita

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?