feat: bidirectional CardDAV contact sync#263
Open
salmonumbrella wants to merge 1 commit into
Open
Conversation
Adds two-way contact synchronisation with any CardDAV server, building on the existing read-only client. - Remote-first create/update/delete: local state changes only after the server confirms, with committed intent and read-only recovery for ambiguous writes (no replayed PUT/DELETE). - Retained lossless vCards: properties MailFlow does not model (X-*, CATEGORIES, KEY, TZ, grouped item properties) survive every edit path, including edits made through MailFlow's own CardDAV server and both conflict resolutions. - Conflict detection and resolution: simultaneous local/remote edits raise an explicit conflict with a side-by-side comparison and keep-mine / keep-theirs resolution; deletions conflict too. - RFC 6578 incremental sync with full-resync fallback, RFC 7232 conditional writes (If-Match required on mapped writes), and Retry-After throttling. - Per-book capability discovery (create/update/delete allowed | denied | unknown) drives the UI; read-only books are surfaced as such. - Contacts UI: photos (uploadable from the detail view too), typed additional fields with humanized vCard labels, per-operation controls, conflict queue, and sync-state markers, translated in all seven locales. - Contact list pagination orders by a unique key so paging reaches every contact; the integration's contact count is derived from the sync ledger rather than accumulated, so it cannot drift. Provider-neutral: no code branches on a provider name or hostname; discovery is RFC 6764/6352 (current-user-principal -> addressbook-home-set), and every server capability is optional. Verified against Nextcloud, plus iCloud- and Fastmail-shaped protocol fixtures. Migrations 0034-0037 add the sync schema; the only changes to pre-existing data are a guarded consolidation of duplicate CardDAV address books and removal of the obsolete dupMode config key.
3 tasks
Contributor
Author
|
@maathimself patiently waiting for you to tackle this monster 👉 👈 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes CardDAV contact sync two-way: MailFlow already reads contacts from a CardDAV server (#209); this adds create, update, and delete back, with conflict handling.
Same posture as the read-only client: standards only, no vendor pinning. Nothing branches on a provider name or hostname, discovery is RFC 6764/6352, and every server capability is discovered and optional — a server that advertises nothing still works read-only. Verified against Nextcloud; the iCloud- and Fastmail-shaped fixtures serve as conformance cases, not provider profiles. Stalwart therefore works out of the box.
Changes
PUT/DELETE.X-*,CATEGORIES, groupeditem1.*, …) survive every edit path, including edits through MailFlow's own CardDAV server.Retry-After.dupModekey.Testing
Backend 1,395 unit + 117 PostgreSQL-backed tests (real PostgreSQL 16, real HTTP CardDAV fixture server, wired into CI); frontend 1,418. Verified end-to-end in a browser against a disposable Nextcloud 34 and a live ~900-contact Nextcloud, where created contacts survive a full re-fetch with custom fields intact.
Notes
PUTs — but should MailFlow run a CardDAV server at all, versus bridging to a real one through this client? Your call; the client stands alone either way.isDefault/isSubscribed) is ready — kept out to hold this PR to one capability.Contributor License Agreement
By submitting this pull request I confirm that:
third-party material and confirmed it is compatible with the CLA).