feat: implement Radicale CardDAV sync utility and update contact handling for asynchronous sync
This commit is contained in:
157
RADICALE_SYNC_README.md
Normal file
157
RADICALE_SYNC_README.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```javascript
|
||||
// POST /api/contacts
|
||||
const contact = createContact(data);
|
||||
|
||||
// Sync to Radicale asynchronously (non-blocking)
|
||||
syncContactAsync(contact);
|
||||
|
||||
return NextResponse.json(contact);
|
||||
```
|
||||
|
||||
### When Updating a Contact
|
||||
|
||||
```javascript
|
||||
// PUT /api/contacts/[id]
|
||||
const contact = updateContact(contactId, data);
|
||||
|
||||
// Sync updated contact to Radicale
|
||||
syncContactAsync(contact);
|
||||
|
||||
return NextResponse.json(contact);
|
||||
```
|
||||
|
||||
### When Deleting a Contact
|
||||
|
||||
```javascript
|
||||
// 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
|
||||
|
||||
1. Check environment variables are set correctly
|
||||
2. Verify Radicale server is accessible
|
||||
3. Check application logs for sync errors
|
||||
4. 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:
|
||||
```bash
|
||||
# RADICALE_URL=
|
||||
# RADICALE_USERNAME=
|
||||
# RADICALE_PASSWORD=
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
- **`src/lib/radicale-sync.js`** - Main sync utility with VCARD generation
|
||||
- **`src/app/api/contacts/route.js`** - Integrated sync on create
|
||||
- **`src/app/api/contacts/[id]/route.js`** - Integrated sync on update/delete
|
||||
- **`export-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
|
||||
Reference in New Issue
Block a user