GinconnectがFirebaseを中心にシステムを構築した理由
Ginconnect は、銀行や支店のマスタデータを Web API で取得できるサービスです。API キーを発行して HTTP 経由で取得する方法と、Excel や Google スプレッドシートの関数から参照する方法の二通りで提供しています。
現在、本サービスを Nextjs(App Router)で再構築しており、そのインフラ基盤を Firebase に集約しています。本記事では、選定の理由と、設計の中核となった Cloud Firestore の MongoDB 互換機能について整理します。
ざっくりした構成
構成要素は次のとおりです。
- 会員サイト・管理画面・ドキュメント:Nextjs(Firebase App Hosting で運用)
- ログイン認証:Firebase Authentication
- 会員情報・APIキー・ログなどのデータ:Cloud Firestore
- 銀行・支店マスタ:Cloud Firestore(MongoDB 互換モード)
- 公開 API(
/v1/*):Cloud Functions(Express) - 定期バッチ・非同期処理:Cloud Functions(スケジュール実行および Firestore トリガー)
- 課金決済:Stripe
外部の決済サービスである Stripe 以外は、すべて Firebase の環境内に集約しています。
1. 小さいサービスを少人数で回すため
Ginconnect は小規模なサービスです。そのため、サーバーの運用管理に割く時間はできるだけ削減したいと考えました。
認証基盤を自前で実装せず、データベースサーバーや API サーバーも個別に構築しない方針を採りました。Firebase に寄せると、開発チームが保守すべき対象はアプリケーションのコードのみになります。OS のアップデートやデータベースのバックアップ機構などを個別に設計・保守する手間を省ける点が、少人数での運用において有用です。
2. 認証を自分で書かないため
ログイン、会員登録、パスワード再設定の処理は Firebase Authentication に任せています。
Nextjs 側では、ログイン時に Firebase のセッション Cookie を発行し、サーバーサイドで検証を行っています。管理者権限の有無は Custom Claims に保持させているため、ユーザー情報のデータベースとは別個に権限管理用のテーブルを持つ必要がありません。認証基盤は自前で構築すると不具合や脆弱性を生じやすい領域であるため、実績のあるマネージドサービスを活用して実装リスクを抑えています。
3. 公開APIと会員サイトを分けられるため
外部から呼び出される銀行・支店マスタ API は、Nextjs のサーバーサイドではなく Cloud Functions に配置しています。Nextjs 側は API キーの発行管理、決済処理、ドキュメントの表示を担当し、API リクエストの処理は Cloud Functions が独立して応答します。
責務を分けておくことで、公開 API に突発的なリクエストが集中しても会員サイトの表示には影響しません。API は api.ginconnect.jp で提供しており、Firebase Hosting のリライト設定によって /v1/** への通信を Cloud Functions に転送しています。Cloud Functions 内部のコードは Express で記述しているため、Firebase 固有の作法に依存しすぎず、標準的な記法で保守できます。
4. Firestore の MongoDB 互換がとにかく良い
Cloud Firestore には MongoDB 互換 の接続モードが用意されています。Firestore でありながら、MongoDB のドライバからそのまま接続できます。接続文字列の形式は次のとおりです。
mongodb://...firestore.goog:443/...インターフェースは MongoDB でありながら、背後のストレージ基盤は Firestore として動作します。Ginconnect の銀行・支店マスタは、この互換モードのコレクションに格納しています。
コードは MongoDB のまま
コードは公式の mongodb パッケージをそのまま使っています。
import { MongoClient } from "mongodb";
const client = new MongoClient(uri, options);
await client.connect();
const db = client.db(dbName);Firestore の SDK に書き直す必要はなく、find による柔軟な検索や updateOne による upsert 処理を、MongoDB 既存の記法のまま実装できます。
それでいて、DB がもう一つ増えない
MongoDB を直接導入する場合、通常は MongoDB Atlas などの外部サービスを別途契約することになります。そうするとアカウントの管理単位が分かれ、請求、監視対象、ネットワーク経路の設定がそれぞれ別個に発生します。
MongoDB 互換の Firestore を採用すれば、すべてのリソースが Google Cloud の同一プロジェクト内で完結します。接続文字列は Secret Manager に保管し、Nextjs(App Hosting)と Cloud Functions の双方から同じシークレットを参照しています。運用の監視対象を増やすことなく、使い慣れたクエリインターフェースを導入できます。
普通の Firestore と並べて使う
Ginconnect では、通常の Firestore と MongoDB 互換の Firestore を役割に応じて使い分けています。
- 会員情報・APIキー・監査ログ:通常の Firestore
- 支店同期のジョブ・キュー・排他制御:通常の Firestore
- 銀行・支店マスタ本体:MongoDB 互換の Firestore
支店マスタの同期は対象の金融機関数が多く、1 回の関数実行では完了しません。そこで、通常の Firestore に同期ジョブのドキュメントを作成し、それを検知する Firestore トリガー で Cloud Functions を起動して、MongoDB 互換側へ順次 upsert する構成を採りました。一定数の処理を終えた段階で次のドキュメントを更新して後続の処理インスタンスへ引き継ぎます。実行制限時間の前に分割して引き継ぐため、処理の中断を防止できます。二重実行を防ぐロック処理も、通常の Firestore のドキュメントを用いて実現しています。
Firestore トリガーによるイベント駆動と、MongoDB のクエリ表現力を、単一のインフラ環境で組み合わせて運用できます。キュー専用のミドルウェアや別のデータベースクラスタを用意する必要はありません。
ハマったところ
導入過程において、支店マスタの同期処理が次のエラーで停止する現象が発生しました。
Transaction number is unknownMongoDB のドライバは、初期状態でリトライアブルライト(再試行可能な書き込み)が有効になっています。この設定が有効な場合、ドライバは書き込みごとに txnNumber を付与してリクエストを送信します。しかし、Firestore の MongoDB 互換モードはリトライアブルライトをサポートしていないため、付与された txnNumber を処理できずにエラーを返していました。
対応策として、接続オプションで該当機能を無効化しました。
const options = {
// Firestore MongoDB互換モードはリトライアブルライト未サポートのため無効化
retryWrites: false,
};調査に時間を要した要因は、Nextjs 側の接続設定にはこのオプションを指定していたものの、Cloud Functions 側の設定から漏れていた点にあります。同一のデータベースに接続しているにもかかわらず、実行環境の差異によって片方のみで障害が発生する状態となっていました。互換モードは MongoDB の全機能を網羅しているわけではないため、サポート対象外の機能がないか事前の仕様確認が求められます。
また、Cloud Functions のシークレット参照仕様にも注意が必要です。Cloud Functions(第2世代)では、環境変数のシークレット値がデプロイ時点のバージョンに固定されます。Secret Manager の接続文字列を変更した際、App Hosting は次のロールアウトで新しい値を即座に読み込みますが、Cloud Functions は明示的に再デプロイを行わない限り古い値を参照し続けます。シークレットを変更した場合は、Cloud Functions の再デプロイ作業を合わせて実施する必要があります。
5. ローカルで動かせるため
Firebase にはローカルエミュレータスイートが用意されており、Authentication、Firestore、Cloud Functions、Hosting などの各機能をローカル環境上で起動できます。
$ pnpm emulators:startテストデータをローカル環境内でのみ保持できるため、開発作業中に誤って本番環境や検証環境のクラウドデータを変更する懸念を排除できます。
気をつけていること
- Firestore のセキュリティルール:クライアントから直接アクセスできるコレクションは最小限に絞り込み、業務ロジックを伴うデータ操作はサーバー環境(Firebase Admin SDK)経由でのみ受け付ける設計にしています。
- ベンダーロックインへの配慮:公開 API は Express、マスタデータのアクセスは MongoDB 公式ドライバで記述しているため、将来的に基盤を移行する際もロジックの流用が可能です。認証と会員データについては運用の身軽さを優先し、Firebase の機能を活用する方針をとっています。
まとめ
Ginconnect が Firebase を中心に据えた理由は、小規模なサービスを少人数で運用するにあたり、自前で保守する対象をアプリケーションのコードに絞り込みたかったためです。認証、データベース、API の実行環境、非同期処理を Firebase に集約することで、インフラの運用負荷を抑えつつ、サービスそのものの開発に時間を割けるようになりました。
その中でも、Firestore の MongoDB 互換モードは構成を決めるうえで大きな役割を果たしました。MongoDB のドライバとクエリをそのまま使いながら、データベースを Firebase の外に増やさずに済むため、「書き慣れた方法で実装したい」と「運用対象を増やしたくない」という二つの要件を両立できています。リトライアブルライトのように互換モードで使えない機能もあるため、事前の確認は欠かせませんが、それを踏まえても十分に採用する価値のある選択肢だと考えています。
Firebase で小さなサービスを構築しようとしている方や、MongoDB を使いたいものの別途データベースを契約することに迷っている方の参考になれば幸いです。

望月 涼太 / polidog
Co-Founder / Web Engineer
