Skip to content

Add two-way vault sync with manifest v2, WebDAV, and sync settings UI - #67

Merged
ultraelectronica merged 20 commits into
mainfrom
versionF
Aug 5, 2026
Merged

Add two-way vault sync with manifest v2, WebDAV, and sync settings UI#67
ultraelectronica merged 20 commits into
mainfrom
versionF

Conversation

@ultraelectronica

Copy link
Copy Markdown
Member

Summary

Adds two-way vault sync with conflict detection, a v2 manifest carrying full restore metadata (tags, favorites, albums, folders, encryption params), WebDAV transport with generous timeouts, a sync settings screen with multi-profile support, and comprehensive sync tests.

Changes

Sync Engine

  • Add two-way sync support with conflict detection (LWW, tombstones, local resurrection)
  • Run sync engine in an isolate to keep UI responsive
  • Add progress reporting and instance-based SyncService
  • Add sync result summary and duration to SyncState
  • Add per-device id generation and caching to SyncProfileService

Manifest v2

  • Bump manifest schema to v2 with full restore metadata (originalName, type, mimeType, fileSize, encryption fields, tags, isFavorite, albumIds, folderId)
  • Enable fresh-device reconstruction from remote manifest

WebDAV

  • Set generous timeouts on WebDAV client for NAS and cold server connections
  • Allow cleartext traffic in network security config

UI

  • Add sync settings screen for local-server sync
  • Refactor sync settings screen for multi-profile support (one active sync target, delete confirmation, auto-activation)
  • Add sync provider with Riverpod state management + connectivity guard
  • Add Server Sync option to vault settings
  • Add FloatingCapsuleBottomBar widget with curved diamond border
  • Replace custom bottom bar with configurable import button side

VaultStore

  • Add VaultStore.getSubdirectory refactored into static subdirFor
  • Expose VaultStore getter on VaultService for shared access

Testing

  • Add conflict resolution tests (LWW divergence, remote tombstone, resurrection)
  • Add manifest v2 round-trip test with v1 backward-compat defaults
  • Add two-way sync integration tests (pull pushed file, pull remote edit, propagate tombstone)
  • Add runSync tests for push and tombstone scenarios with in-memory store

Documentation

  • Add embedded PocketBase local store design doc
  • Update local_server_sync.md (S3 implemented, manifest v2, S3 ceilings)

- Rename title to "Local Server Sync (WebDAV)"
- Condense overview section, removing status markers and pending items
- Clarify that the server is dumb encrypted blob storage
Planning document for embedding a PocketBase instance as a structured,
queryable local datastore for vault metadata. Covers architecture,
security model, data model, phased implementation plan, and open
decisions. No code yet — P0 is a feasibility gate.
Allows Riverpod-constructed services like SyncService to share the same
VaultStore caches without creating a new singleton instance.
Adds two tests covering the `SyncService.runSync` flow: one verifying
that local files are pushed as remote blobs with a matching manifest and
idempotent on re-run, and another verifying that tombstoned files reap
their remote blob and record a deleted entry. Includes an in-memory
`_MemStore` implementing `RemoteStore` to avoid network calls in tests.
Introduces `SyncNotifier` and `SyncState` to bridge `SyncService`
with the settings UI. Handles connectivity checks (Wi‑Fi guard),
profile lookup, progress reporting, and error state. Also exposes
`syncProfilesProvider` for the profile list.
Document that S3 (two-way pull/restore) is now implemented and
unit-tested (100 tests), update the manifest v2 description, mark
S3.1–S3.3 as Done, and add the S3 ceilings section explaining
deliberate simplifications around pull integrity, conflict detection,
tombstones, and album/folder sync.
Add v2 fields to ManifestEntry (originalName, type, mimeType, fileSize,
dateAdded, dateModified, isEncrypted, encryptionIv, encryptionAlgorithm,
keyDerivationSalt, kdfIterations, tags, isFavorite, albumIds, folderId)
and update serialization/deserialization. Change default RemoteManifest
version from 1 to 2.
Introduce `message` and `duration` fields on `SyncState` so the UI can
display a one-line run summary (e.g. "2 pushed · 1 pulled · 1 conflict")
and the wall-clock time the sync took. The `_summarize` helper builds
the
message from `SyncResult` counts and the conflict list.
- Add multiple profile management with one active (sync target) profile
- Replace single-profile load with bootstrap + reactive provider
  listening
- Add sync success bottom sheet and sync log entries
- Add connection error classification for friendlier error messages
- Add profile delete confirmation dialog with cleanup
- Auto-activate new profiles so sync works immediately
Run the sync engine in an isolate to keep the UI responsive during
file I/O and hashing. Manifest v2 carries full restore metadata
(original name, type, encryption params, tags, favorites, album and
folder refs) so a fresh device can reconstruct files. Tombstone LWW:
a remote tombstone deletes the local copy only when at least as new
as the local file; a strictly newer local copy resurrects via push.
Fix listProfiles to return an explicitly typed empty list.
Added docs/local_server_testing.md to .gitignore.
- Add conflict-resolution tests covering LWW with divergence,
  no-conflict when remote unchanged, remote tombstone, and
  local-newer-than-tombstone resurrection.
- Add manifest v2 round-trip test verifying restore metadata
  (tags, favorite, album, folder, encryption fields) and v1
  backward-compat defaults.
- Add push-only test confirming a missing local blob is skipped
  (not fatal) and leaves the file unmodified.
- Add two-way sync integration tests: pull a pushed file,
  pull an edit from another device, and propagate a remote
  tombstone to local deletion.
- Bump manifest version assertion from 1 to 2 in existing test.
configurable import button side

- Replace hand-built bottom bar with FloatingCapsuleBottomBar widget
- Add FeatureSide (left/right) for import button placement
- Persist and restore import side preference via SharedPreferences
- Add toggle in customize sheet for import button position
@ultraelectronica ultraelectronica self-assigned this Aug 5, 2026
@ultraelectronica
ultraelectronica merged commit 467b8e8 into main Aug 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant