Skip to content

Add CardDAV plugin for contact sync with phones and desktops #157

Description

@melvincarvalho

Motivation

JSS already stores contacts as JSON-LD using the W3C vCard vocabulary (vcard:AddressBook, vcard:Individual, vcard:fn, vcard:hasEmail, etc.). Web apps can read and write this data natively. But right now, these contacts live only in the browser — they can't sync to your phone, desktop mail client, or any other app.

CardDAV is the missing bridge. It's the universal standard (RFC 6352) that every contact app already speaks. By adding a CardDAV plugin, every contact stored on a JSS pod becomes instantly accessible from:

  • iOS/macOS Contacts (built-in, zero config)
  • Android (via DAVx⁵ or built-in)
  • Thunderbird (built-in CardDAV support)
  • GNOME/KDE Contacts
  • Nextcloud (can federate with external CardDAV)
  • Outlook (via CalDav Synchronizer plugin)

This turns JSS from a web-only data store into a real personal data hub — your contacts live on your pod, and every device syncs to it.

What this enables

  1. Phone sync — Add a contact in a web app, it appears on your iPhone/Android. Edit on your phone, it syncs back to your pod.
  2. Desktop integration — Thunderbird, Apple Contacts, GNOME Contacts all become Solid-aware without knowing it.
  3. Migration path — Users can export contacts from Google/iCloud and import them into their pod via any CardDAV client.
  4. Interop with Nextcloud — Nextcloud can mount external CardDAV sources, making JSS pods federatable.
  5. Solid ecosystem value — Demonstrates that Solid pods aren't just for web apps; they integrate with the tools people already use.

Architecture

JSS already has the right patterns — this follows the same plugin approach as ActivityPub (src/ap/) and Nostr relay (src/nostr/).

What already works

  • File-based storage with GET/PUT/DELETE on any path
  • Auth (WAC, NIP-98)
  • Content negotiation (JSON-LD ↔ Turtle)
  • The vCard RDF vocabulary is already the data model used by SolidOS contacts-pane

What needs to be added (~300-500 lines)

src/carddav/index.js     ← Fastify plugin registration + route setup
src/carddav/xml.js        ← WebDAV XML request/response helpers
src/carddav/vcf.js        ← JSON-LD vcard ↔ .vcf text conversion

New HTTP methods

Method Purpose Notes
PROPFIND Discover address books and list contacts WebDAV XML envelope
REPORT Query contacts (multiget, sync-collection) CardDAV-specific queries
MKCOL Create new address book collection Simple container creation

GET, PUT, DELETE for individual .vcf resources already work via existing handlers — CardDAV reuses standard HTTP for the actual contact CRUD.

Data flow

Phone/Desktop ←→ CardDAV (vCard .vcf) ←→ JSS Plugin ←→ JSON-LD (vcard vocab) ←→ Filesystem
                                              ↑
                                    Web apps (contacts pane) read/write
                                    the same JSON-LD files directly

The conversion between JSON-LD vcard and .vcf text is mechanical — it's the same fields:

vcard:fn          → FN:Alice Wonderland
vcard:hasEmail    → EMAIL:[email protected]
vcard:hasTelephone → TEL:+1-555-0101
vcard:hasPhoto    → PHOTO;VALUE=URI:https://...
vcard:organization-name → ORG:Acme Corp

Server config

Following the existing pattern:

createServer({
  carddav: true,              // Enable CardDAV plugin
  carddavPath: '/contacts/'   // Mount point (default)
})

CLI: --carddav --carddav-path /contacts/

Prior art

  • Radicale (Python) — minimal CardDAV in ~2000 lines, stores as flat .vcf files
  • Baikal (PHP) — wraps SabreDAV
  • SolidOS contacts-pane — already uses vcard vocabulary, which is the same data model

Size estimate

Small. The WebDAV XML wrapping is the most verbose part, but the actual logic is straightforward. The plugin should be comparable in size to the ActivityPub plugin.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpluginCould be implemented as a plugin (#206); core/plugin line defined in #564

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions