レプリケーションのマージ戦略
このドキュメントは data-architecture.md の「Local DB ↔ Remote DB」同期の詳細。
概要
各ブラウザはローカルの RxDB (IndexedDB) を持ち、HTTP pull/push を介して
中央の RxDB (MongoDB) サーバーと同期する。
さしあたり共同同時編集は想定せず、単一ユーザーが一度に一つのデバイスで操作する前提。
戦略: Server Wins
push 時に conflict が検出された場合、サーバーの状態を正とする。
クライアントはサーバー状態を採用して resolve する。
Conflict 検出 (Push)
各 push 行には assumedMasterState(クライアントが想定するサーバーの現在状態)が
付与される。サーバーはこれを実際の状態と比較する:
- 一致 → 書き込みを受理
- 不一致 → 書き込みを拒否し、実際のサーバー状態を conflict として返却
削除と softDeleted フィールド
Local DB では doc.remove() を直接呼ばず、removePage() フック経由でsoftDeleted: true と updatedAt を更新する。これにより:
- 削除済みドキュメントを
find({ selector: { softDeleted: true } })で取得可能 - RxDB の内部
deleted/deleted$と競合しないようsoftDeletedという名前を使用
Remote DB の pages コレクションに削除済みドキュメントを直接保持する
(softDeleted: true で upsert)。tombstones コレクションは廃止。
復活と slug 再利用
- クライアントが
softDeleted: falseを push → 受理して upsert - 非削除ドキュメントの push 時、slug 一意性は
softDeleted: falseのドキュメント間でのみチェック
Push バッチの処理順序
同一バッチ内で削除と作成が混在する場合、softDeleted: true のドキュメントを先に処理する。これにより slug 一意性チェックが
まだ削除されていない旧ページに衝突することを防ぐ。
updatedAt の意味
PageDoc.updatedAt は「DB エントリがいつ書き込まれたか」を表すシステムタイムスタンプ。
ファイルの mtime (fileObj.lastModified) ではなく Date.now() を使用する。
コンテンツの変更日時は content.modified が別途保持する。