Files
panel/docs/features/RADICALE_SYNC.md
RKWojs d4f16d344d feat: Implement comprehensive Contacts Management System with API and UI integration
- Added new `contacts` and `project_contacts` database tables for managing contacts.
- Created API endpoints for CRUD operations on contacts and linking them to projects.
- Developed UI components including `ContactForm` and `ProjectContactSelector`.
- Integrated navigation and translations for Polish language support.
- Documented usage, features, and future enhancements for the contacts system.

feat: Introduce DOCX Template System for generating documents from templates

- Enabled creation and management of DOCX templates with placeholders for project data.
- Documented the process for creating templates, uploading, and generating documents.
- Included detailed information on available variables and custom data fields.
- Implemented troubleshooting guidelines for common issues related to template generation.

feat: Add Radicale CardDAV Sync Integration for automatic contact synchronization

- Implemented automatic syncing of contacts to a Radicale server on create/update/delete actions.
- Documented setup instructions, including environment variable configuration and initial sync script.
- Provided troubleshooting steps for common sync issues and error codes.

feat: Develop Route Planning Feature with Optimization using OpenRouteService API

- Integrated multi-point routing and automatic optimization for project locations.
- Documented setup, usage, and technical implementation details for route planning.
- Included performance considerations and troubleshooting for common routing issues.

chore: Remove unnecessary files and scripts from the codebase

- Deleted temporary, debug-related, and test-specific files that are not needed in production.
- Reviewed and ensured core application code and essential documentation remain intact.
2026-01-16 11:11:29 +01:00

352 lines
8.7 KiB
Markdown

# 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
### Common Issues
**Problem: Sync not working / contacts not appearing in Radicale**
**Check 1: Environment Variables**
```bash
# Verify variables are set
echo $RADICALE_URL
echo $RADICALE_USERNAME
# Don't echo password for security
```
**Check 2: Radicale Server Connectivity**
```bash
# Test server is reachable
curl -I http://your-radicale-server:5232
# Test authentication
curl -u username:password http://your-radicale-server:5232/username/contacts/
```
**Check 3: Application Logs**
Look for sync messages in your application console:
```
✅ Synced contact 123 to Radicale
❌ Failed to sync contact 456 to Radicale: 401 - Unauthorized
```
---
**Problem: 401 Unauthorized errors**
- **Cause**: Invalid credentials or user doesn't exist
- **Solution**:
- Verify `RADICALE_USERNAME` and `RADICALE_PASSWORD`
- Ensure user exists in Radicale
- Check Radicale authentication method (basic auth vs htpasswd)
---
**Problem: 404 Not Found errors**
- **Cause**: Contacts collection doesn't exist
- **Solution**:
- Create collection in Radicale: `/{username}/contacts/`
- Verify collection URL matches `RADICALE_URL`
- Check Radicale collection rights and permissions
---
**Problem: Network timeout or connection refused**
- **Cause**: Radicale server not accessible from app server
- **Solution**:
- Check firewall rules
- Verify Radicale is running: `systemctl status radicale`
- Test with curl from app server
- If using Docker, ensure network connectivity
---
**Problem: Contacts created but not syncing**
- **Cause**: Environment variables not loaded or sync disabled
- **Solution**:
- Restart application after setting env vars
- Check `.env` or `.env.local` file exists
- Verify Next.js loaded environment: check server startup logs
- Test with manual export script: `node export-contacts-to-radicale.mjs`
---
**Problem: Duplicate contacts in Radicale**
- **Cause**: Re-running export script or UID conflicts
- **Solution**:
- UIDs are unique: `contact-{id}@panel-app`
- Existing contacts are overwritten on update
- Delete duplicates manually in Radicale if needed
---
**Problem: VCARD format errors in Radicale**
- **Cause**: Invalid characters or incomplete data
- **Solution**:
- Check contact has at least name field
- Special characters in names are escaped
- Phone/email fields are optional
- Review contact data for completeness
---
### Monitoring Sync Status
**Enable Detailed Logging**
Edit `src/lib/radicale-sync.js` to increase logging verbosity:
```javascript
// Add more console.log statements
console.log('Syncing contact:', contact);
console.log('VCARD:', vcard);
console.log('Response:', await response.text());
```
**Check Radicale Server Logs**
```bash
# Typical log location
tail -f /var/log/radicale/radicale.log
# Or check systemd journal
journalctl -u radicale -f
```
**Manual Sync Test**
Test individual contact sync:
```bash
# Use the export script for a single contact
node export-contacts-to-radicale.mjs
# Select specific contact when prompted
```
---
### Disable Sync Temporarily
Comment out environment variables to disable sync without removing configuration:
```bash
# .env.local
# RADICALE_URL=http://localhost:5232
# RADICALE_USERNAME=admin
# RADICALE_PASSWORD=secret
```
Application will function normally without sync enabled.
---
### Manual Sync Endpoint
For manual sync control, you can trigger sync via API:
```bash
# Sync specific contact
POST /api/contacts/{id}/sync
# Response
{
"success": true,
"message": "Contact synced to Radicale"
}
```
---
### Error Codes Reference
| Code | Meaning | Solution |
|------|---------|----------|
| 401 | Unauthorized | Check credentials |
| 403 | Forbidden | Verify user has write permissions |
| 404 | Not Found | Create contacts collection |
| 409 | Conflict | UID collision (rare) |
| 500 | Server Error | Check Radicale server logs |
| ECONNREFUSED | Connection Refused | Server not reachable |
| ETIMEDOUT | Timeout | Network/firewall issue |
---
## 📋 Configuration Reference
### Required Environment Variables
```bash
RADICALE_URL=http://localhost:5232
RADICALE_USERNAME=your_username
RADICALE_PASSWORD=your_password
```
### Default Settings
- **Collection Path**: `/{username}/contacts/`
- **VCARD Version**: 3.0
- **UID Format**: `contact-{id}@panel-app`
- **Sync Mode**: Asynchronous (non-blocking)
- **Retry Logic**: None (fire-and-forget)
---
## 📂 Files Reference
| File | Purpose |
|------|---------|
| `src/lib/radicale-sync.js` | Core sync logic, VCARD generation |
| `src/app/api/contacts/route.js` | Create sync trigger |
| `src/app/api/contacts/[id]/route.js` | Update/delete sync triggers |
| `export-contacts-to-radicale.mjs` | Bulk export utility |
---
## 🔒 Security Best Practices
**Do's:**
- Use HTTPS for production Radicale servers
- Store credentials in environment variables (never in code)
- Use strong, unique passwords
- Limit Radicale user permissions to contacts collection only
- Regularly rotate credentials
- Use separate credentials per environment (dev/staging/prod)
**Don'ts:**
- Don't commit credentials to git
- Don't use HTTP in production
- Don't share credentials between environments
- Don't log passwords or sensitive data
- Don't grant unnecessary permissions
---
## 🚀 Advanced Configuration
### Custom Collection Path
Modify `src/lib/radicale-sync.js`:
```javascript
const baseUrl = `${process.env.RADICALE_URL}/${process.env.RADICALE_USERNAME}/my-custom-collection/`;
```
### Batch Sync Operations
For large-scale sync (future enhancement):
```javascript
// Collect contacts, then sync in batches
const batchSize = 50;
// Implement batch logic
```
### Webhook Integration
Future: Trigger webhooks on sync events:
```javascript
// POST to webhook URL on sync success/failure
fetch(WEBHOOK_URL, {
method: 'POST',
body: JSON.stringify({ event: 'contact_synced', contact_id: id })
});
```
---
**See Also**: [Contacts System](CONTACTS_SYSTEM.md) | [Main README](../../README.md#-cardav-integration-radicale) | [API Documentation](../../README.md#contacts)