docs: update documentation for CalDAV multi-account feature

- README.md: Updated Calendar feature description to mention multi-account CalDAV support
- docs/SPEC.md: Added caldav_accounts and caldav_calendar_selection table schemas, updated external_source enum, documented target columns
- public/locales/en.json: Added missing CalDAV i18n keys (calendarEnabled, calendarDisabled, calendarsRefreshed, deleteAccountConfirm, lastSync)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ulas Kalayci
2026-05-04 08:51:38 +02:00
parent 4bca84a609
commit 2a4a6b945b
3 changed files with 43 additions and 6 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ The goal is a single, private place for everything that keeps a household runnin
| **Shopping Lists** | Collaborative lists organized by aisle. Import ingredients from meal plans in one click. | | **Shopping Lists** | Collaborative lists organized by aisle. Import ingredients from meal plans in one click. |
| **Meal Planning** | Weekly drag-and-drop planner. Export ingredient lists directly to your shopping list. | | **Meal Planning** | Weekly drag-and-drop planner. Export ingredient lists directly to your shopping list. |
| **Recipes** | Create, duplicate, and scale reusable recipes. Pre-fill meal slots from a recipe or save any meal as a recipe. | | **Recipes** | Create, duplicate, and scale reusable recipes. Pre-fill meal slots from a recipe or save any meal as a recipe. |
| **Calendar** | Two-way sync with Google Calendar (OAuth) and Apple iCloud (CalDAV). Subscribe to any public ICS/webcal URL with per-subscription color and visibility. Overlapping timed events render side-by-side. Events support file attachments (images, PDFs, Office documents). | | **Calendar** | Two-way sync with Google Calendar (OAuth) and multiple CalDAV accounts (iCloud, Nextcloud, Radicale, Baikal). Per-account calendar selection with checkboxes. Subscribe to any public ICS/webcal URL with per-subscription color and visibility. Overlapping timed events render side-by-side. Events support file attachments (images, PDFs, Office documents). |
| **Documents** | Upload and manage family files (PDF, images, Office documents up to 5 MB). Grid/list view, drag-and-drop upload, 14 category tags (medical, school, identity, finance, and more), per-document visibility (family, selected members, private), archive and download. | | **Documents** | Upload and manage family files (PDF, images, Office documents up to 5 MB). Grid/list view, drag-and-drop upload, 14 category tags (medical, school, identity, finance, and more), per-document visibility (family, selected members, private), archive and download. |
| **Budget** | Track income and expenses with recurring entries, monthly trends, and CSV export. 35 predefined categories plus custom ones. Supports 15 currencies. Loans tab for instalment-based loan tracking with per-payment history and automatic paid-off detection. | | **Budget** | Track income and expenses with recurring entries, monthly trends, and CSV export. 35 predefined categories plus custom ones. Supports 15 currencies. Loans tab for instalment-based loan tracking with per-payment history and automatic paid-off detection. |
| **Notes & Contacts** | Colored sticky notes with Markdown support. Contact directory with vCard import/export. | | **Notes & Contacts** | Colored sticky notes with Markdown support. Contact directory with vCard import/export. |
+36 -4
View File
@@ -112,7 +112,7 @@ Reusable recipe cards that can be pre-filled into meal slots.
| assigned_to | INTEGER | FK → Users | | assigned_to | INTEGER | FK → Users |
| created_by | INTEGER | FK → Users, NOT NULL | | created_by | INTEGER | FK → Users, NOT NULL |
| external_calendar_id | TEXT | ID from external calendar | | external_calendar_id | TEXT | ID from external calendar |
| external_source | TEXT | local, google, apple, ics | | external_source | TEXT | local, google, apple, ics, caldav |
| recurrence_rule | TEXT | iCal RRULE | | recurrence_rule | TEXT | iCal RRULE |
| subscription_id | INTEGER | FK → ICS Subscriptions (CASCADE delete) | | subscription_id | INTEGER | FK → ICS Subscriptions (CASCADE delete) |
| user_modified | INTEGER | 0/1 — prevents sync overwrite when 1 | | user_modified | INTEGER | 0/1 — prevents sync overwrite when 1 |
@@ -121,18 +121,50 @@ Reusable recipe cards that can be pre-filled into meal slots.
| attachment_mime | TEXT | MIME type (e.g. image/jpeg, application/pdf), nullable | | attachment_mime | TEXT | MIME type (e.g. image/jpeg, application/pdf), nullable |
| attachment_size | INTEGER | File size in bytes, nullable | | attachment_size | INTEGER | File size in bytes, nullable |
| attachment_data | TEXT | Base64 data URL of attachment (≤ 5 MB), nullable | | attachment_data | TEXT | Base64 data URL of attachment (≤ 5 MB), nullable |
| target_caldav_account_id | INTEGER | FK → CalDAV Accounts (for outbound sync), nullable |
| target_caldav_calendar_url | TEXT | CalDAV calendar URL (for outbound sync), nullable |
### External Calendars ### External Calendars
Display metadata (name, color) for synced Google/Apple calendars. Populated automatically during sync. Display metadata (name, color) for synced Google/Apple/CalDAV calendars. Populated automatically during sync.
| Column | Type | Constraint | | Column | Type | Constraint |
|--------|------|-----------| |--------|------|-----------|
| source | TEXT | 'google' or 'apple', NOT NULL | | source | TEXT | 'google', 'apple', or 'caldav', NOT NULL |
| external_id | TEXT | Calendar ID from the provider, NOT NULL | | external_id | TEXT | Calendar ID from the provider, NOT NULL |
| name | TEXT | Display name from the provider, NOT NULL | | name | TEXT | Display name from the provider, NOT NULL |
| color | TEXT | Background color from the provider (HEX) | | color | TEXT | Background color from the provider (HEX) |
| UNIQUE | | (source, external_id) | | UNIQUE | | (source, external_id) |
### CalDAV Accounts
Multi-account CalDAV integration. Stores credentials for CalDAV servers (iCloud, Nextcloud, Radicale, Baikal, etc.).
| Column | Type | Constraint |
|--------|------|-----------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| name | TEXT | User-defined label (e.g. "My Radicale", "iCloud"), NOT NULL |
| caldav_url | TEXT | CalDAV server base URL, NOT NULL |
| username | TEXT | CalDAV username, NOT NULL |
| password | TEXT | CalDAV password (encrypted if DB_ENCRYPTION_KEY set), NOT NULL |
| created_at | TEXT | ISO 8601 |
| last_sync | TEXT | ISO 8601, nullable |
| UNIQUE | | (caldav_url, username) |
### CalDAV Calendar Selection
Per-account calendar enable/disable state for CalDAV accounts.
| Column | Type | Constraint |
|--------|------|-----------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| account_id | INTEGER | FK → CalDAV Accounts (CASCADE delete), NOT NULL |
| calendar_url | TEXT | CalDAV calendar URL from provider, NOT NULL |
| calendar_name | TEXT | Display name from provider, NOT NULL |
| calendar_color | TEXT | HEX color code from provider, nullable |
| enabled | INTEGER | 0/1 (default 1), controls sync for this calendar |
| created_at | TEXT | ISO 8601 |
| UNIQUE | | (account_id, calendar_url) |
Index: CREATE INDEX idx_caldav_selection_enabled ON caldav_calendar_selection(account_id, enabled)
### Notes ### Notes
| Column | Type | Constraint | | Column | Type | Constraint |
|--------|------|-----------| |--------|------|-----------|
@@ -393,7 +425,7 @@ Reusable recipe cards linked to meal slots.
- Color-coding per person - Color-coding per person
- Recurring via iCal RRULE - Recurring via iCal RRULE
- **Google Calendar:** OAuth 2.0, Calendar API v3, two-way sync - **Google Calendar:** OAuth 2.0, Calendar API v3, two-way sync
- **Apple Calendar:** CalDAV (tsdav), two-way sync - **CalDAV Multi-Account:** Connect multiple CalDAV servers (iCloud, Nextcloud, Radicale, Baikal) with per-account calendar selection via checkboxes, two-way sync (tsdav), optional outbound target selection per event
- **ICS Subscriptions:** Subscribe to any public ICS/webcal URL (e.g. public holidays, sports schedules). Per-subscription color, private/shared visibility, manual "Sync now" and automatic sync on the shared interval. Edit name, color, and visibility of any subscription inline. RRULE events expanded into a rolling ±6/+12 month window. SSRF-protected (DNS pre-resolution), ETag/Last-Modified conditional fetch, 10 MB limit, 15 s timeout. User-edited events are protected from being overwritten (`user_modified`); a "Reset to original" link restores them. - **ICS Subscriptions:** Subscribe to any public ICS/webcal URL (e.g. public holidays, sports schedules). Per-subscription color, private/shared visibility, manual "Sync now" and automatic sync on the shared interval. Edit name, color, and visibility of any subscription inline. RRULE events expanded into a rolling ±6/+12 month window. SSRF-protected (DNS pre-resolution), ETag/Last-Modified conditional fetch, 10 MB limit, 15 s timeout. User-edited events are protected from being overwritten (`user_modified`); a "Reset to original" link restores them.
- **External calendar names & colors:** Google and Apple sync stores each calendar's display name and background color in the `external_calendars` table (migration v14). A colored `event-cal-label` badge appears in event popups, agenda, month, week, and day views when `cal_name` is present. - **External calendar names & colors:** Google and Apple sync stores each calendar's display name and background color in the `external_calendars` table (migration v14). A colored `event-cal-label` badge appears in event popups, agenda, month, week, and day views when `cal_name` is present.
- **Event location:** Event popup and dashboard display the location field with RFC 5545 backslash-escape normalization (`\n`, `\,`, `\;`, `\\`) via `fmtLocation()` in `public/utils/html.js`. - **Event location:** Event popup and dashboard display the location field with RFC 5545 backslash-escape normalization (`\n`, `\,`, `\;`, `\\`) via `fmtLocation()` in `public/utils/html.js`.
+6 -1
View File
@@ -1004,7 +1004,12 @@
"caldavRefreshCalendars": "Refresh calendars", "caldavRefreshCalendars": "Refresh calendars",
"caldavSyncSuccess": "CalDAV sync successful", "caldavSyncSuccess": "CalDAV sync successful",
"caldavSyncFailed": "CalDAV sync failed", "caldavSyncFailed": "CalDAV sync failed",
"caldavConnectionFailed": "Connection to CalDAV server failed" "caldavConnectionFailed": "Connection to CalDAV server failed",
"calendarEnabled": "Calendar enabled",
"calendarDisabled": "Calendar disabled",
"calendarsRefreshed": "Calendars refreshed",
"deleteAccountConfirm": "Really delete CalDAV account? All synced calendars will be removed.",
"lastSync": "Last synced"
}, },
"login": { "login": {
"tagline": "Family planning. Secure. Privacy-friendly. Open source.", "tagline": "Family planning. Secure. Privacy-friendly. Open source.",