Add comprehensive database schema for CardDAV multi-account contacts sync:
New tables:
- cardav_accounts: Store CardDAV server credentials
- cardav_addressbook_selection: Per-account addressbook enable/disable
- contact_phones: Multiple phone numbers per contact with labels
- contact_emails: Multiple email addresses per contact with labels
- contact_addresses: Multiple postal addresses per contact with labels
Extended contacts table with 9 new columns:
- organization, job_title, birthday, website, photo, nickname
- cardav_account_id (FK to cardav_accounts, ON DELETE SET NULL)
- cardav_uid (vCard UID from server)
- cardav_addressbook_url (source addressbook URL)
Features:
- UNIQUE constraints on (cardav_url, username) and (account_id, addressbook_url)
- CASCADE delete for addressbook selection and contact sub-tables
- Performance indices for cardav_uid and email lookups
- Support for manual contacts (NULL cardav_account_id)
- is_primary flag for phone/email/address selection
Test coverage:
- 23 comprehensive tests verify all tables, constraints, indices
- FK CASCADE delete behavior validated
- UNIQUE constraints enforced
- Data integrity scenarios tested
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add getCalendars() and updateCalendarSelection() to caldav-sync.js
- Add sync() function for bidirectional CalDAV synchronization
- Add getStatus() to report on all accounts and enabled calendars
- Add 8 new API routes to calendar.js for CalDAV account and calendar management
- All routes require admin role for security
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add createAccount, updateAccount, deleteAccount functions with validation, error handling, and logging. Implements Task 3 from the CalDAV multi-account spec.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove buildICS, escapeICS, unescapeICS imports - these will be
needed in Task 5 (Sync Functions), not in Task 2. Keep only the
4 functions specified in the Task 2 spec: parseICS, formatICSDate,
tzLocalToUTC, applyDuration.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- caldav_accounts table for account credentials
- caldav_calendar_selection table for calendar selection
- Migrate Apple CalDAV data to caldav tables
- Add target_caldav_* columns to calendar_events
- Update external_source CHECK to include 'caldav'
- Update external_calendars.source CHECK to include 'caldav'
- Enhance migration runner to support function-based migrations
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The PR changed dmy from dots to slashes, breaking existing users.
Revert dmy to dots (backward compat), add dmy_slash for DD/MM/YYYY.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Also translate server error message to English and remove stale
comment from calendar.js catch block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix recurring events with FREQ=WEEKLY;INTERVAL=N;BYDAY ignoring the
interval when crossing a week boundary (e.g. Friday → Monday).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Null/undefined items in the Google Calendar API response caused a
TypeError on `item.status` access, silently aborting the sync while
the OAuth callback had already redirected to the success page.
- Filter null items in `upsertGoogleEvents` with an early `continue`
- Await `sync()` in the OAuth callback so errors surface as
`sync_error=google` redirects instead of false success
Resolves#92
Co-authored-by: Ulas Kalayci <ulas.kalayci@googlemail.com>
- router.js: route-announcer used bare `path` variable which is not in scope
inside renderPage(); replaced with `route.path`
- dashboard.js: shoppingLists query used `HAVING open_count > 0` without GROUP BY;
SQLite rejects this — replaced with a WHERE subquery
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Delete public/doc-assets/swagger.html and swagger-init.js (CDN dependency violates project constraints)
- Remove /docs route from server/index.js
- Revert styleSrc and fontSrc in CSP to not include cdn.jsdelivr.net
- Translate all 22 settings.apiToken* keys in de.json from English to German
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>