アイランドモードサーバー
物理サイトに常駐する小さなNodeサーバーが、そのサイトのFirestoreスライスのRxDBレプリカを保持します。インターネット接続中は不可視ですが、回線が切れるとLAN上のキオスク/スタッフ端末が透過的にフェイルオーバーし、注文の受け付け、在庫の移動、ハードウェアの制御を継続します。再接続時には、オフライン作業がクラウドにフラッシュされます。すべてを形作る一つの洞察: 同期は二つのシステムであり、一つではない — 状態のためのドキュメントレベルRxDBレプリケーションに加え、クラウドが独自のロジック(在庫増加、監査取り込み)で適用する必要があるビジネスイベントのHTTPフラッシュ。どちらか一方だけでは不十分です。
使用する場合
- サイトが実際の書き込み(予約、在庫、ハードウェア制御)を含むインターネット障害に耐える必要がある場合。
- 端末がブラウザベース(PWA/キオスク)で、透過的なフェイルオーバーが必要な場合。
- Firestoreがクラウドの真実源であり、その状態を維持する場合。
使用しない場合
- 純粋な読み取りキャッシュや、Firestoreの組み込みオフライン永続化のみを必要とするPWA — Firebase SDKが既に処理するため、サーバーは不要。
- 異なるクラウドデータベース(Supabase/Postgres): レプリケーション層の概念は汎用的ですが、すべてのテンプレートはFirestore固有です。
- ピアサイト間のマルチマスター同期 — この設計は厳密にハブアンドスポークであり、クラウドを真実源とし、最終書き込み勝ちの競合解決を行います。
アーキテクチャ
Internet
|
+--------+---------+
| Cloud (SSoT) | Firestore + 公開API + cronステータスマーカー
+--------+---------+
| |
RxDBレプリケーション HTTPフラッシュ(再接続時)
| |
+-+-------------+-+
| ローカルサーバー | Node/NestJS + RxDB、LAN :443 via nginx TLS
+--------+--------+
|
LAN — キオスクPWA、スタッフPWA、ハードウェアコントローラー
重要事項
- レプリケートされたコレクションへのすべてのクラウド書き込みは、チェックポイントフィールド(
serverTimestamp: FieldValue.serverTimestamp())および_deleted: falseを付与する必要があります — RxDB FirestoreプラグインはserverTimestamp > checkpointでプルします。スタンプされていないドキュメントはレプリケーションでプルされません。 - コレクションごとに選択される3つのレプリケーション層: プル専用(サイトが消費する設定)、双方向(サイトが変更する運用状態)、プッシュ専用(サイトが生成するログ)。コレクションの層を誤ることが主な設計上の誤りです。
- インメモリRxDBストレージでは、オフライン再起動によりすべてのオフライン作業が失われます。 レプリカはFirestoreから再構築されますが、オフライン中に作成されたドキュメントは消えます。ストレージのトレードオフは明示的に判断してください — replication.md を参照。
- フラッシュはat-least-onceであるため、クラウド取り込みは冪等でなければなりません — すべての適用をクライアント生成IDでキー付けし、既に適用済みのものはスキップします。
- プッシュフィルターがエコーを防止: 双方向プッシュは
_offlineCreated/_locallyModifiedフラグが設定されたドキュメントのみを送信するため、プルされたクラウドドキュメントが戻ってくることはありません。 - 端末はクラウドを優先 — フォールオーバーはN回連続のヘルスチェック失敗後にのみ発動し、オフライン中もローカルサーバーを再スキャンし続ける必要があり、一度の切り替えで終わりではありません。
厳格なルール
クラウド同期取り込みエンドポイントを認証なしに公開しないでください。 在庫増加を適用し、注文を注入します。共有秘密ヘッダーが最低限の要件です。
オンライン中にオフラインのスタッフトークンを緩く検証しないでください。 検証なしデコードのフォールバックはLAN専用の許容されたトレードオフであり、サーバーが実際にオフラインである場合にのみゲートされるべきです。そうしないと、署名検証のバイパスになります。
同期が確認されていないトランザクションのローカル在庫デルタをリセットしないでください。 確認応答ごとにID単位でリセットするか、オフライン販売が二重計上されるか、利用可能在庫から消失します。
ローカルサーバーにクラウドが所有するビジネスルール(営業時間、価格設定)を発明させないでください。 設定をレプリケートし、そこから計算するか、島モードの動作がウェブサイトから乖離します。
クイックスタート
- コレクションを層にモデル化し、境界に名前を付けます — architecture.md。
- RxDB + カスタムトークン認証とセキュリティルールを使用したレプリケーションを立ち上げます — replication.md。
- 再接続フラッシュと冪等なクラウド取り込みを追加します — sync-flush.md。
- ハートビート/ステータスチェーンとクライアントのフェイルオーバーを配線します — network-failover.md。
- ローカルAPI(スタッフ/キオスク/ハードウェア HMAC/静的トークン)を保護します — auth.md。
- 端末が必要とするクラウドエンドポイントをミラーリングします — local-api.md。
- サイトにデプロイ: systemd、nginx TLS、mDNS、監視 — operations.md。
リファレンスディレクトリ
| シナリオ | トリガーキーワード | リファレンス |
|---|---|---|
| トポロジー、層、境界、名前変更テーブル | pull-only、bidirectional、push-only、dual-path、locationId、conflict | architecture.md |
| レプリカセットアップ、スキーマ、チェックポイントトラップ | RxDB、replicateFirestore、serverTimestamp、custom token、storage-memory、firestore.rules | replication.md |
| 再接続フラッシュ、在庫デルタ、取り込み | flushAll、idempotent、FieldValue.increment、localDelta、syncedIds | sync-flush.md |
| 障害検出とAPI切り替え | heartbeat、lastHeartbeatAt、cron、NetworkManager、apiBaseUrl、failover | network-failover.md |
| ローカルAPI認証 | AuthGuard、HMAC、replay window、offline JWT fallback、kiosk key | auth.md |
| オフラインエンドポイントと書き込み | availability、mutex、offline booking、check-in、pricing stock filter | local-api.md |
| オンサイトデプロイメントとランブック | systemd、nginx、self-signed TLS、mDNS、avahi、journalctl、rollback | operations.md |
| 元帳: 監査が変更、保持、追加したもの | provenance、audit、deviations、kept deliberately | provenance.md |
信頼に重要なロジック(HMAC検証、オフライントークンデコード、実際のRxDB上のデルタ展開、フォールバック再スキャン)のvitestスイートをパス: assets/behavior.test.ts — 対象プロジェクトにリグレッションカバレッジとして持ち込んでください。