united-tattoo/docs/CALDAV-SETUP.md
Nicholai a77f62f949 feat: implement CalDAV Nextcloud bidirectional calendar integration
Adds complete CalDAV integration for syncing appointments between the web app
and Nextcloud calendars with real-time availability checking and conflict resolution.

Core Features:
- Bidirectional sync: Web ↔ Nextcloud calendars
- Real-time availability checking with instant user feedback
- Conflict detection (Nextcloud is source of truth)
- Pending request workflow with 'REQUEST:' prefix for unconfirmed appointments
- Hard time blocking - any calendar event blocks booking slots
- Graceful degradation when CalDAV unavailable

New Dependencies:
- tsdav@^2.0.4 - TypeScript CalDAV client
- ical.js@^1.5.0 - iCalendar format parser/generator

Database Changes:
- New table: artist_calendars (stores calendar configuration per artist)
- New table: calendar_sync_logs (tracks all sync operations)
- Added caldav_uid and caldav_etag columns to appointments table
- Migration: sql/migrations/20250109_add_caldav_support.sql

New Services:
- lib/caldav-client.ts - Core CalDAV operations and iCalendar conversion
- lib/calendar-sync.ts - Bidirectional sync logic with error handling

New API Endpoints:
- GET /api/caldav/availability - Real-time availability checking
- POST /api/caldav/sync - Manual sync trigger (admin only)
- GET/POST/PUT/DELETE /api/admin/calendars - Calendar configuration CRUD

Updated Components:
- app/api/appointments/route.ts - Integrated CalDAV sync on CRUD operations
- components/booking-form.tsx - Added real-time availability indicator
- hooks/use-availability.ts - Custom hook for debounced availability checking

Documentation:
- docs/CALDAV-SETUP.md - Complete setup guide with troubleshooting
- docs/CALDAV-IMPLEMENTATION-SUMMARY.md - Technical implementation overview

Pending Tasks (for future PRs):
- Admin dashboard UI for calendar management
- Background sync worker (Cloudflare Workers cron)
- Unit and integration tests

Tested with local database migration and linting checks passed.
2025-10-08 20:44:17 -06:00

320 lines
9.4 KiB
Markdown

# CalDAV Nextcloud Integration Setup Guide
This document provides instructions for setting up and configuring the bidirectional CalDAV integration with Nextcloud.
## Overview
The CalDAV integration allows your tattoo booking system to:
- Sync appointments FROM the web app TO Nextcloud calendars in real-time
- Check availability FROM Nextcloud calendars to prevent double-bookings
- Pull events FROM Nextcloud TO the database (for manual calendar entries)
- Handle conflicts automatically (Nextcloud is the source of truth)
## Prerequisites
1. A Nextcloud instance with CalDAV enabled
2. Admin access to Nextcloud to create app-specific passwords
3. Individual calendars set up for each artist in Nextcloud
## Environment Variables
Add these variables to your `.env.local` file:
```env
# CalDAV / Nextcloud Integration
NEXTCLOUD_BASE_URL=https://your-nextcloud-instance.com
NEXTCLOUD_USERNAME=admin_or_service_account
NEXTCLOUD_PASSWORD=app_specific_password
NEXTCLOUD_CALENDAR_BASE_PATH=/remote.php/dav/calendars
```
### Getting Nextcloud Credentials
1. Log in to your Nextcloud instance
2. Go to **Settings****Security**
3. Scroll to **Devices & Sessions**
4. Under **App passwords**, create a new app password named "Tattoo Booking System"
5. Copy the generated password (it will look like: `xxxxx-xxxxx-xxxxx-xxxxx-xxxxx`)
6. Use this as your `NEXTCLOUD_PASSWORD` value
## Database Migration
The CalDAV integration requires new database tables. Run the migration:
```bash
# For local development
npm run db:migrate:local -- --file=./sql/migrations/20250109_add_caldav_support.sql
# For production
wrangler d1 execute united-tattoo --remote --file=./sql/migrations/20250109_add_caldav_support.sql
```
This creates the following tables:
- `artist_calendars` - Stores calendar configuration for each artist
- `calendar_sync_logs` - Tracks sync operations for monitoring
- Adds `caldav_uid` and `caldav_etag` columns to `appointments` table
## Configuring Artist Calendars
After setting up the environment variables, you need to configure which Nextcloud calendar belongs to each artist.
### Step 1: Get Calendar URLs from Nextcloud
1. Log in to Nextcloud
2. Go to the **Calendar** app
3. For each artist calendar:
- Click the **⋮** (three dots) menu next to the calendar name
- Select **Settings**
- Copy the **Calendar Link** (WebDAV URL)
- It should look like: `https://your-nextcloud.com/remote.php/dav/calendars/username/calendar-name/`
### Step 2: Configure in Admin Dashboard
1. Log in to your tattoo booking admin dashboard
2. Navigate to **Admin****Calendars**
3. Click **Add Calendar Configuration**
4. Fill in the form:
- **Artist**: Select the artist from dropdown
- **Calendar URL**: Paste the WebDAV URL from Nextcloud
- **Calendar ID**: Enter the calendar name (last part of URL)
5. Click **Test Connection** to verify
6. Save the configuration
### API Method (Alternative)
You can also configure calendars via API:
```bash
curl -X POST https://your-domain.com/api/admin/calendars \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN" \
-d '{
"artistId": "artist-uuid-here",
"calendarUrl": "https://nextcloud.com/remote.php/dav/calendars/user/artist-name/",
"calendarId": "artist-name"
}'
```
## How It Works
### Booking Flow
1. **User submits booking** → Creates `PENDING` appointment in database
2. **Real-time sync** → Event created in Nextcloud with title "REQUEST: [Client Name] - [Description]"
3. **Artist/admin reviews** → Sees pending request in their calendar app
4. **Admin approves** → Status changes to `CONFIRMED`, event updated in Nextcloud
5. **Any conflicts** → Detected automatically before booking is created
### Conflict Resolution
- **Before booking creation**: System checks Nextcloud calendar for conflicts
- **Nextcloud is source of truth**: If an event exists in Nextcloud, that time slot is blocked
- **User feedback**: Clear messaging if selected time is unavailable
- **Alternative times**: Users can provide backup date/time preferences
### Event Syncing
**Web → Nextcloud (Real-time)**
- Appointment created → Event created in CalDAV
- Appointment updated → Event updated in CalDAV
- Appointment cancelled → Event deleted from CalDAV
**Nextcloud → Web (Manual/Scheduled)**
- Use the admin sync button for manual sync
- Background worker (future implementation) will sync periodically
- Any calendar event blocks that time slot for web bookings
## API Endpoints
### Check Availability
```http
GET /api/caldav/availability?artistId=UUID&startTime=ISO_DATE&endTime=ISO_DATE
```
Returns:
```json
{
"artistId": "uuid",
"startTime": "2025-01-15T14:00:00Z",
"endTime": "2025-01-15T16:00:00Z",
"available": true,
"reason": null
}
```
### Manual Sync
```http
POST /api/caldav/sync
```
Body:
```json
{
"artistId": "uuid-or-omit-for-all",
"startDate": "2025-01-01T00:00:00Z",
"endDate": "2025-03-31T23:59:59Z"
}
```
### Manage Calendar Configurations
```http
GET /api/admin/calendars
POST /api/admin/calendars
PUT /api/admin/calendars
DELETE /api/admin/calendars?id=UUID
```
## Testing
### 1. Test Calendar Connection
```bash
# Using the admin UI
1. Go to Admin → Calendars
2. Click "Test Connection" on any calendar
3. Verify green checkmark appears
# Or via curl
curl -X GET https://your-nextcloud.com/remote.php/dav/calendars/username/ \
-u "username:app-password"
```
### 2. Test Booking Flow
1. Create a test appointment via the booking form
2. Check Nextcloud calendar - event should appear with "REQUEST:" prefix
3. Update appointment status to CONFIRMED in admin dashboard
4. Check Nextcloud - event title should update (no "REQUEST:" prefix)
5. Delete appointment - event should disappear from Nextcloud
### 3. Test Conflict Detection
1. Manually create an event in Nextcloud for a specific time
2. Try to book the same time slot via the web form
3. Verify error message appears: "Time slot not available"
### 4. Test Availability Checking
1. Open booking form
2. Select an artist, date, and time
3. Wait for availability indicator (green checkmark or red X)
4. Verify real-time feedback as you change selections
## Troubleshooting
### "CalDAV not configured" warnings
**Problem**: Environment variables not set or incorrect
**Solution**:
1. Verify all NEXTCLOUD_* variables are in `.env.local`
2. Restart your development server
3. Check credentials are correct (test with curl)
### "Calendar configuration not found"
**Problem**: Artist doesn't have a calendar configured
**Solution**:
1. Go to Admin → Calendars
2. Add calendar configuration for the artist
3. Test the connection
### Sync fails with 401/403 errors
**Problem**: Authentication issue with Nextcloud
**Solution**:
1. Verify app password is correct (regenerate if needed)
2. Check username matches Nextcloud username
3. Ensure calendar permissions allow API access
### Events not appearing in Nextcloud
**Problem**: Sync is failing silently
**Solution**:
1. Check Admin → Calendars → Sync Logs
2. Look for error messages in logs
3. Verify calendar URL is correct (trailing slash matters!)
4. Test connection manually with curl
### Availability always shows "not available"
**Problem**: CalDAV client returning errors
**Solution**:
1. Check browser console for errors
2. Verify API endpoint works: `/api/caldav/availability`
3. Check network tab for failed requests
4. Ensure artist has calendar configured
## Monitoring
### View Sync Logs
```sql
-- In Wrangler D1 console
SELECT * FROM calendar_sync_logs
ORDER BY created_at DESC
LIMIT 20;
```
Or via the admin dashboard:
- Go to **Admin****Calendars**
- Click on any artist
- View **Recent Sync History**
### Key Metrics to Monitor
- **Sync success rate**: Should be >95%
- **Events processed**: Track volume over time
- **Error patterns**: Look for repeating errors
- **Sync duration**: Should be <2 seconds per artist
## Best Practices
1. **Use app-specific passwords**: Never use main Nextcloud password
2. **Test before production**: Verify with test appointments first
3. **Monitor sync logs**: Check regularly for failures
4. **Calendar naming**: Use clear, consistent artist names
5. **Backup strategy**: Export calendars regularly from Nextcloud
6. **User communication**: Inform users that Nextcloud is authoritative
## Future Enhancements
- [ ] Background worker for automatic periodic sync (every 5 minutes)
- [ ] Webhook support for instant sync when Nextcloud calendar changes
- [ ] Bulk calendar configuration import
- [ ] Sync status dashboard with real-time updates
- [ ] Email notifications for sync failures
- [ ] Two-way sync for appointment details (not just create/delete)
## Security Considerations
- Credentials stored in environment variables (never in code)
- App-specific passwords (not main password)
- Admin-only calendar configuration endpoints
- CalDAV responses validated before database updates
- Rate limiting on API endpoints
- Sanitized event data before storing
## Support
For issues or questions:
1. Check the troubleshooting section above
2. Review sync logs in admin dashboard
3. Test with curl commands to isolate issues
4. Check Nextcloud server logs if needed
## References
- [CalDAV RFC 4791](https://datatracker.ietf.org/doc/html/rfc4791)
- [Nextcloud CalDAV Documentation](https://docs.nextcloud.com/server/latest/user_manual/en/groupware/calendar.html)
- [tsdav Library](https://github.com/natelindev/tsdav)
- [ical.js Library](https://github.com/kewisch/ical.js)