fix(sync): replicate deletions and keep photos off the wire
Reusing the backup snapshot for sync had two bugs that would bite real use: 1. Deletions didn't propagate. exportInventory() filters isDeleted=false (user backups are tombstone-free by design) and the JSON codec dropped isDeleted (omitted on encode, hardcoded false on decode) — so deleting a variety on one device never reached the others. Now the codec round-trips isDeleted (emitted only when true, so backups stay byte-identical and it's backward compatible), and a new exportForSync() includes tombstones. The importer already merges them LWW-correctly. 2. Photos bloated events. The snapshot embeds photo bytes as base64, so a real inventory would blow past relay event-size limits and sync would silently fail. exportForSync() omits attachments entirely (photos stay device-local; media sync is a separate, deferred concern). buildSnapshot() now uses exportForSync(); backups keep using exportInventory (photos in, tombstones out) unchanged. Tests: a deletion replicates as a tombstone; the sync snapshot carries no photo bytes while a sealed backup still does.
This commit is contained in:
parent
d0dbed9bc2
commit
b15f912ad8
4 changed files with 83 additions and 11 deletions
|
|
@ -1745,6 +1745,29 @@ class VarietyRepository {
|
|||
);
|
||||
}
|
||||
|
||||
/// Snapshots the inventory for device-to-device SYNC — unlike [exportInventory]
|
||||
/// this INCLUDES tombstones (so deletions replicate) and EXCLUDES attachment
|
||||
/// bytes (photos are large and stay device-local for now; syncing media is a
|
||||
/// separate concern). Everything else — the CRDT rows with their sync metadata
|
||||
/// — replicates and merges LWW-by-HLC on the other device.
|
||||
Future<InventorySnapshot> exportForSync() async {
|
||||
final varieties = await _db.select(_db.varieties).get(); // incl. tombstones
|
||||
return InventorySnapshot(
|
||||
varieties: varieties,
|
||||
speciesNamesById: await _scientificNamesFor(
|
||||
varieties.map((v) => v.speciesId).whereType<String>().toSet(),
|
||||
),
|
||||
lots: await _db.select(_db.lots).get(),
|
||||
vernacularNames: await _db.select(_db.varietyVernacularNames).get(),
|
||||
externalLinks: await _db.select(_db.externalLinks).get(),
|
||||
germinationTests: await _db.select(_db.germinationTests).get(),
|
||||
conditionChecks: await _db.select(_db.conditionChecks).get(),
|
||||
movements: await _db.select(_db.movements).get(),
|
||||
parties: await _db.select(_db.parties).get(),
|
||||
// attachments intentionally omitted — photos don't ride the sync wire.
|
||||
);
|
||||
}
|
||||
|
||||
/// Imports a snapshot, reconciling by row id (UUIDv7) so nothing duplicates:
|
||||
/// unknown id → insert preserving the original sync metadata; known mutable
|
||||
/// id → last-writer-wins on the packed HLC `updatedAt`; movements are
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue