---
created: 2026-02-24T23:35:53.621Z
visibility: public
permanent: true
content_id: 01KJ904PGP2WRSA9CSWM0NGKMD
modified: 2026-02-24T23:37:22.216Z
---

# レプリケーションのマージ戦略

> このドキュメントは [data-architecture.md](./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` が別途保持する。
