一言で
感情記録とAI分析を提供するZero GravityのSpring Boot REST APIです。 フリーティアクラウド上にインフラからデプロイまで自ら構築し、コスト制約の中でAI機能を設計しました。
- 5つのドメイン、14個のエンドポイント: 認証、感情記録、統計、AI分析を一つのAPIとして設計しました。
- OCI + Terraform 6モジュールでインフラを自ら構築し、Build-first戦略でZero-Downtimeデプロイを実現しました。
- Time BucketサンプリングでGemini API送信量を97%削減し、AI機能をコスト上限内で運用しました。
チームプロジェクトからプロダクションまで。
チームプロジェクトとして始めたSpring Bootバックエンドをプロダクションサービスに転換しました。 基本的なCRUD APIのみ存在していたプロジェクトに認証、インフラ、デプロイパイプラインを構築し、AI分析機能を追加しました。
- レイヤードアーキテクチャをドメイン別構造に再構成しました。
- NextAuth OAuth → JWT認証体系を実装しました。
- OCI上にインフラを自ら構築し、Zero-Downtimeデプロイを実現しました。
- Gemini APIベースの感情分析機能を追加しました。
API Endpoints
Infrastructure
全部送ると一ヶ月も持ちません。
Gemini APIで感情記録を分析する機能を実装しようとしました。 1年分の記録を全て送るとリクエストあたりのInputトークンが~55Kに達しました。プロジェクト予算では賄えませんでした。
データを減らすと分析品質が下がり、機能自体を諦めるにはコア機能でした。
バケット一つ、代表記録一つ。
全てを送れないなら、各期間を代表する記録だけを選んで送ればよかったのです。 期間を均等な時間単位(バケット)に分割し、バケットごとに代表記録を1件ずつ選びました。Year分析なら月単位で12個です。 全体から一度に選ぶと記録の多い月に偏り、1年の流れを捉えられないためです。
残る問題は「代表」をどの基準で選ぶかでした。 基準はすでにサービスの中にありました。チャートが期間ごとに集計していた平均感情レベルと理由統計で代表の条件を定義しました。
- 平均感情レベルに最も近いこと
- 最も頻繁に現れた理由を含むこと
理由統計はバケット単位で再集計し、感情統計のために用意していた集計クエリはそのまま再利用しました。
レベル60% + 理由40%で点数をつけました。
感情レベル60% + 理由マッチング40%の加重スコアで各バケットの代表記録を選別しました。
同点の場合は日記が長い順、理由が多い順、最新順でタイブレークしました。
例: Year分析の1月バケット (平均感情レベル: 4.5、最頻理由: "Work")
送信量97%削減、リクエストあたり$0.002
※ AI分析結果は24時間キャッシュし、感情記録が変更されると該当期間のキャッシュを無効化しました。