experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(mobile): remove active sync_source usage from iOS sync

Replace sync_source-based push filtering with synced_at-based filtering
in iOS mobile backend. Stop writing sync_source on pull and post-push.
Clean up sync_source from test scripts. Column kept in schema for
backward compatibility. All 4 e2e sync phases pass.

+29 -31
+6 -6
backend/tauri-mobile/seed-test-data.sh
··· 62 62 63 63 sqlite3 "$DB_PATH" <<EOF 64 64 -- Insert test items (unsynced - no sync_id) 65 - INSERT OR IGNORE INTO items (id, type, url, content, created_at, updated_at, sync_id, sync_source) 66 - VALUES ('$UUID1', 'url', 'https://mobile-only-1.example.com', NULL, '$NOW', '$NOW', '', ''); 65 + INSERT OR IGNORE INTO items (id, type, url, content, created_at, updated_at, sync_id) 66 + VALUES ('$UUID1', 'url', 'https://mobile-only-1.example.com', NULL, '$NOW', '$NOW', ''); 67 67 68 - INSERT OR IGNORE INTO items (id, type, url, content, created_at, updated_at, sync_id, sync_source) 69 - VALUES ('$UUID2', 'text', NULL, 'This text was created on mobile only', '$NOW', '$NOW', '', ''); 68 + INSERT OR IGNORE INTO items (id, type, url, content, created_at, updated_at, sync_id) 69 + VALUES ('$UUID2', 'text', NULL, 'This text was created on mobile only', '$NOW', '$NOW', ''); 70 70 71 - INSERT OR IGNORE INTO items (id, type, url, content, created_at, updated_at, sync_id, sync_source) 72 - VALUES ('$UUID3', 'url', 'https://mobile-news.example.com', NULL, '$NOW', '$NOW', '', ''); 71 + INSERT OR IGNORE INTO items (id, type, url, content, created_at, updated_at, sync_id) 72 + VALUES ('$UUID3', 'url', 'https://mobile-news.example.com', NULL, '$NOW', '$NOW', ''); 73 73 74 74 -- Add tags for the items 75 75 INSERT OR IGNORE INTO tags (name, frequency, lastUsed, frecencyScore, createdAt, updatedAt)
+11 -13
backend/tauri-mobile/src-tauri/src/lib.rs
··· 4326 4326 fn get_items_to_push(conn: &Connection) -> Result<Vec<(String, String, Option<String>, Option<String>, String, String, String, Option<String>)>, String> { 4327 4327 // Returns: (id, type, url, content, metadata, updated_at, sync_id, deleted_at) 4328 4328 // Push items that: 4329 - // 1. Have never been synced (sync_source = '' or NULL), OR 4329 + // 1. Have never been synced (synced_at IS NULL), OR 4330 4330 // 2. Have been locally modified after their last sync (updated_at > synced_at) 4331 4331 // 3. Have been soft-deleted locally with a sync_id (need to propagate delete to server) 4332 - // This prevents re-pushing items that were just pulled from the server 4333 4332 let mut stmt = conn 4334 4333 .prepare( 4335 4334 "SELECT id, type, url, content, COALESCE(metadata, ''), updated_at, COALESCE(sync_id, ''), deleted_at FROM items 4336 - WHERE (deleted_at IS NULL AND (sync_source = '' OR sync_source IS NULL OR (synced_at IS NOT NULL AND updated_at > synced_at))) 4335 + WHERE (deleted_at IS NULL AND (synced_at IS NULL OR updated_at > synced_at)) 4337 4336 OR (deleted_at IS NOT NULL AND sync_id IS NOT NULL AND sync_id != '' AND synced_at IS NOT NULL AND updated_at > synced_at)" 4338 4337 ) 4339 4338 .map_err(|e| format!("Failed to prepare query: {}", e))?; ··· 4503 4502 }; 4504 4503 4505 4504 conn.execute( 4506 - "INSERT INTO items (id, type, url, content, metadata, sync_id, sync_source, synced_at, created_at, updated_at) 4507 - VALUES (?, ?, ?, ?, ?, ?, 'server', ?, ?, ?)", 4505 + "INSERT INTO items (id, type, url, content, metadata, sync_id, synced_at, created_at, updated_at) 4506 + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", 4508 4507 params![ 4509 4508 &new_id, 4510 4509 item_type, ··· 4793 4792 // Update local item with sync info 4794 4793 let now = Utc::now().to_rfc3339(); 4795 4794 conn.execute( 4796 - "UPDATE items SET sync_id = ?, sync_source = 'server', synced_at = ? WHERE id = ?", 4795 + "UPDATE items SET sync_id = ?, synced_at = ? WHERE id = ?", 4797 4796 params![&create_response.id, &now, item_id], 4798 4797 ).ok(); 4799 4798 ··· 4889 4888 4890 4889 // Count pending items (never synced, locally modified after last sync, or locally deleted needing push) 4891 4890 let pending_count: usize = conn.query_row( 4892 - "SELECT COUNT(*) FROM items WHERE (deleted_at IS NULL AND (sync_source = '' OR sync_source IS NULL OR (synced_at IS NOT NULL AND updated_at > synced_at))) OR (deleted_at IS NOT NULL AND sync_id IS NOT NULL AND sync_id != '' AND synced_at IS NOT NULL AND updated_at > synced_at)", 4891 + "SELECT COUNT(*) FROM items WHERE (deleted_at IS NULL AND (synced_at IS NULL OR updated_at > synced_at)) OR (deleted_at IS NOT NULL AND sync_id IS NOT NULL AND sync_id != '' AND synced_at IS NOT NULL AND updated_at > synced_at)", 4893 4892 [], 4894 4893 |row| row.get::<_, i64>(0), 4895 4894 ) ··· 5322 5321 let id = uuid::Uuid::new_v4().to_string(); 5323 5322 5324 5323 conn.execute( 5325 - "INSERT INTO items (id, type, url, sync_id, sync_source, synced_at, created_at, updated_at) VALUES (?, 'url', ?, ?, ?, ?, ?, ?)", 5326 - params![&id, "https://sync-test.com", "remote-123", "server", &now, &now, &now], 5324 + "INSERT INTO items (id, type, url, sync_id, synced_at, created_at, updated_at) VALUES (?, 'url', ?, ?, ?, ?, ?)", 5325 + params![&id, "https://sync-test.com", "remote-123", &now, &now, &now], 5327 5326 ) 5328 5327 .expect("Failed to insert item with sync columns"); 5329 5328 5330 5329 // Retrieve and verify 5331 - let (sync_id, sync_source, synced_at): (String, String, String) = conn 5330 + let (sync_id, synced_at): (String, String) = conn 5332 5331 .query_row( 5333 - "SELECT sync_id, sync_source, synced_at FROM items WHERE id = ?", 5332 + "SELECT sync_id, synced_at FROM items WHERE id = ?", 5334 5333 params![&id], 5335 - |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), 5334 + |row| Ok((row.get(0)?, row.get(1)?)), 5336 5335 ) 5337 5336 .expect("Failed to query sync columns"); 5338 5337 5339 5338 assert_eq!(sync_id, "remote-123", "sync_id should be saved"); 5340 - assert_eq!(sync_source, "server", "sync_source should be saved"); 5341 5339 assert_eq!(synced_at, now, "synced_at should be saved"); 5342 5340 } 5343 5341
+12 -12
scripts/e2e-full-sync-test.sh
··· 458 458 CREATE INDEX IF NOT EXISTS idx_blobs_item ON blobs(item_id); 459 459 460 460 -- Seed iOS-origin items 461 - INSERT INTO items (id, type, url, content, metadata, sync_source, created_at, updated_at) 461 + INSERT INTO items (id, type, url, content, metadata, created_at, updated_at) 462 462 VALUES 463 - ('ios-e2e-url-1', 'url', 'https://example.com/ios-origin-1', '', '', '', datetime('now'), datetime('now')), 464 - ('ios-e2e-note-1', 'text', '', 'Note created on iOS', '', '', datetime('now'), datetime('now')); 463 + ('ios-e2e-url-1', 'url', 'https://example.com/ios-origin-1', '', '', datetime('now'), datetime('now')), 464 + ('ios-e2e-note-1', 'text', '', 'Note created on iOS', '', datetime('now'), datetime('now')); 465 465 466 466 -- Tags (TEXT IDs matching desktop/server format: tag_{timestamp}_{random9}) 467 467 INSERT INTO tags (id, name, frequency, lastUsed, frecencyScore, createdAt, updatedAt) ··· 762 762 763 763 # Seed into iOS SQLite (no sync_id — appears as local-only) 764 764 sqlite3 "$IOS_DB" << SQLEOF 765 - INSERT INTO items (id, type, url, content, metadata, sync_source, created_at, updated_at) 765 + INSERT INTO items (id, type, url, content, metadata, created_at, updated_at) 766 766 VALUES 767 - ('ios-crossdev-1', 'url', '$CROSS_URL', '', '', '', datetime('now'), datetime('now')); 767 + ('ios-crossdev-1', 'url', '$CROSS_URL', '', '', datetime('now'), datetime('now')); 768 768 769 769 INSERT OR IGNORE INTO tags (id, name, frequency, lastUsed, frecencyScore, createdAt, updatedAt) 770 770 VALUES ('tag_e2e_crossdev', 'cross-device', 1, datetime('now'), 1.0, datetime('now'), datetime('now')); ··· 806 806 807 807 # Seed into iOS SQLite 808 808 sqlite3 "$IOS_DB" << 'SQLEOF' 809 - INSERT INTO items (id, type, url, content, metadata, sync_source, created_at, updated_at) 810 - VALUES ('ios-tagset-1', 'tagset', '', '', '', '', datetime('now'), datetime('now')); 809 + INSERT INTO items (id, type, url, content, metadata, created_at, updated_at) 810 + VALUES ('ios-tagset-1', 'tagset', '', '', '', datetime('now'), datetime('now')); 811 811 812 812 INSERT OR IGNORE INTO tags (id, name, frequency, lastUsed, frecencyScore, createdAt, updatedAt) 813 813 VALUES ··· 1093 1093 1094 1094 # iOS duplicates (snake_case schema, url column for url-type, content for text-type) 1095 1095 sqlite3 "$IOS_DB" << 'SQLEOF' 1096 - INSERT INTO items (id, type, url, content, metadata, sync_source, created_at, updated_at) 1096 + INSERT INTO items (id, type, url, content, metadata, created_at, updated_at) 1097 1097 VALUES 1098 - ('dup-ios-url-1', 'url', 'https://example.com/ios-origin-1', '', '', '', datetime('now'), datetime('now', '-1 day')), 1099 - ('dup-ios-text-1', 'text', '', 'Note created on iOS', '', '', datetime('now'), datetime('now', '-1 day')); 1098 + ('dup-ios-url-1', 'url', 'https://example.com/ios-origin-1', '', '', datetime('now'), datetime('now', '-1 day')), 1099 + ('dup-ios-text-1', 'text', '', 'Note created on iOS', '', datetime('now'), datetime('now', '-1 day')); 1100 1100 1101 1101 -- Duplicate tagset 1102 - INSERT INTO items (id, type, url, content, metadata, sync_source, created_at, updated_at) 1103 - VALUES ('dup-ios-tagset-1', 'tagset', '', '', '', '', datetime('now'), datetime('now', '-1 day')); 1102 + INSERT INTO items (id, type, url, content, metadata, created_at, updated_at) 1103 + VALUES ('dup-ios-tagset-1', 'tagset', '', '', '', datetime('now'), datetime('now', '-1 day')); 1104 1104 1105 1105 INSERT INTO item_tags (item_id, tag_id, created_at) 1106 1106 VALUES ('dup-ios-tagset-1', 'tag_e2e_shared', datetime('now'));