4.0 KiB
4.0 KiB
Radicale CardDAV Sync Integration
This application now automatically syncs contacts to a Radicale CardDAV server whenever contacts are created, updated, or deleted.
Features
- ✅ Automatic Sync - Contacts are automatically synced when created or updated
- ✅ Automatic Deletion - Contacts are removed from Radicale when soft/hard deleted
- ✅ Non-Blocking - Sync happens asynchronously without slowing down the API
- ✅ Optional - Sync is disabled by default, enable by configuring environment variables
- ✅ VCARD 3.0 - Generates standard VCARD format with full contact details
Setup
1. Configure Environment Variables
Add these to your .env.local or production environment:
RADICALE_URL=http://localhost:5232
RADICALE_USERNAME=your_username
RADICALE_PASSWORD=your_password
Note: If these variables are not set, sync will be disabled and the app will work normally.
2. Radicale Server Setup
Make sure your Radicale server:
- Is accessible from your application server
- Has a user created with the credentials you configured
- Has a contacts collection at:
{username}/contacts/
3. One-Time Initial Sync
To sync all existing contacts to Radicale:
node export-contacts-to-radicale.mjs
This script will:
- Prompt for Radicale URL, username, and password
- Export all active contacts as VCARDs
- Upload them to your Radicale server
How It Works
When Creating a Contact
// POST /api/contacts
const contact = createContact(data);
// Sync to Radicale asynchronously (non-blocking)
syncContactAsync(contact);
return NextResponse.json(contact);
When Updating a Contact
// PUT /api/contacts/[id]
const contact = updateContact(contactId, data);
// Sync updated contact to Radicale
syncContactAsync(contact);
return NextResponse.json(contact);
When Deleting a Contact
// DELETE /api/contacts/[id]
deleteContact(contactId);
// Delete from Radicale asynchronously
deleteContactAsync(contactId);
return NextResponse.json({ message: "Contact deleted" });
VCARD Format
Each contact is exported with the following fields:
- UID:
contact-{id}@panel-app - FN/N: Full name and structured name
- ORG: Company
- TITLE: Position/Title
- TEL: Phone numbers (multiple supported - first as WORK, others as CELL)
- EMAIL: Email address
- NOTE: Contact type + notes
- CATEGORIES: Based on contact type (Projekty, Wykonawcy, Urzędy, etc.)
- REV: Last modified timestamp
VCARD Storage Path
VCARDs are stored at:
{RADICALE_URL}/{RADICALE_USERNAME}/contacts/contact-{id}.vcf
Example:
http://localhost:5232/admin/contacts/contact-123.vcf
Troubleshooting
Sync Not Working
- Check environment variables are set correctly
- Verify Radicale server is accessible
- Check application logs for sync errors
- Test manually with the export script
Check Sync Status
Sync operations are logged to console:
✅ Synced contact 123 to Radicale
❌ Failed to sync contact 456 to Radicale: 401 - Unauthorized
Disable Sync
Simply remove or comment out the Radicale environment variables:
# RADICALE_URL=
# RADICALE_USERNAME=
# RADICALE_PASSWORD=
Files
src/lib/radicale-sync.js- Main sync utility with VCARD generationsrc/app/api/contacts/route.js- Integrated sync on createsrc/app/api/contacts/[id]/route.js- Integrated sync on update/deleteexport-contacts-to-radicale.mjs- One-time bulk export script
Security Notes
- ⚠️ Store credentials securely in environment variables
- ⚠️ Use HTTPS for production Radicale servers
- ⚠️ Consider using environment-specific credentials
- ⚠️ Sync happens in background - errors won't block API responses
Future Enhancements
- Bi-directional sync (import changes from Radicale)
- Batch sync operations
- Sync queue with retry logic
- Webhook notifications for sync status
- Admin UI to trigger manual sync