docs(design): mark contact special-dates implemented + note deviations

Records the UID_2445 (vs SYNC_DATA1) identity decision, the sync-time age
snapshot, and the seeded reminder default; checks off the #14/#15 task lists.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 11:17:23 +02:00
parent e67960d352
commit 030c3e6ce1

View File

@@ -1,9 +1,25 @@
# Design: Contact special-dates calendars (+ per-calendar multiple reminders) # Design: Contact special-dates calendars (+ per-calendar multiple reminders)
Status: **design / not yet implemented** Status: **implemented** on `feat/contact-special-dates` (#14 prerequisite merged in)
Date: 2026-06-30 Date: 2026-06-30 (implemented 2026-07-01)
Tracking: Codeberg #15 (feature), Codeberg #14 (prerequisite) Tracking: Codeberg #15 (feature), Codeberg #14 (prerequisite)
Implementation notes / deviations from this design:
- **Event identity key is a deterministic `Events.UID_2445`**
(`contact-<type>:<lookupKey>@calendula`), not `SYNC_DATA1`. On a LOCAL calendar
the provider drops `_sync` columns unless written through a sync-adapter URI;
`UID_2445` is written/read through the normal event URIs the app already uses
(and doubles as a stable iCal UID). The managed **calendar** still carries a
`CAL_SYNC2` marker for re-adoption (calendar-row writes already use the
sync-adapter URI).
- **Age is a sync-time snapshot.** A `FREQ=YEARLY` row has one static title, so
`{age}` reflects the upcoming birthday at the last sync (refreshed daily / on
foreground), not a per-occurrence value.
- New managed calendars seed a per-calendar all-day reminder default of
on-the-day + one week before, so birthdays get lead time out of the box.
- Title template is user-editable from day one (`{name}`, `{age}`).
This document captures the full design for surfacing contact birthdays — This document captures the full design for surfacing contact birthdays —
and, by extension, anniversaries and custom dates — as auto-updating local and, by extension, anniversaries and custom dates — as auto-updating local
calendars in Calendula. It also specifies #14 (per-calendar *multiple* calendars in Calendula. It also specifies #14 (per-calendar *multiple*
@@ -206,24 +222,25 @@ rest.
## Task outline ## Task outline
### #14 — per-calendar multiple default reminders (`feat/per-calendar-multi-reminders`) ### #14 — per-calendar multiple default reminders (`feat/per-calendar-multi-reminders`)
- [ ] Widen global + per-calendar reminder defaults `Int` → `List<Int>` - [x] Widen global + per-calendar reminder defaults `Int` → `List<Int>`
(`SettingsPrefs.kt`), keep `Inherit/None/Minutes(list)`. (`SettingsPrefs.kt`), keep `Inherit/None/Minutes(list)`.
- [ ] `resolveDefaultReminder()` returns a list. - [x] `resolveDefaultReminder()` returns a list.
- [ ] `ReminderDefaultPicker` → multi-select (mirror event-form UI). - [x] `ReminderDefaultPicker` → multi-select (mirror event-form UI).
- [ ] Seed new events' `EventForm.reminders` from the resolved list. - [x] Seed new events' `EventForm.reminders` from the resolved list.
- [ ] Migration / parse compatibility for existing single-value stored prefs. - [x] Migration / parse compatibility for existing single-value stored prefs.
- [ ] Tests: resolution, parse round-trip, all-day variant. - [x] Tests: resolution, parse round-trip, all-day variant.
### #15 — contact special-dates (`feat/contact-special-dates`) ### #15 — contact special-dates (`feat/contact-special-dates`)
- [ ] Declare `READ_CONTACTS`; feature-gated contextual request on enable. - [x] Declare `READ_CONTACTS`; feature-gated contextual request on enable.
- [ ] Per-type local calendars (create on enable, delete on disable+confirm). - [x] Per-type local calendars (create on enable, delete on disable+confirm).
- [ ] Contacts reader: `Event` rows by `TYPE`, year-less handling. - [x] Contacts reader: `Event` rows by `TYPE`, year-less handling.
- [ ] Sync engine: idempotent diff keyed on `LOOKUP_KEY` in `SYNC_DATA1`; - [x] Sync engine: idempotent diff keyed on the deterministic `UID_2445`
targeted managed-column updates; seed user-owned fields on insert only. (see notes; not `SYNC_DATA1`); targeted managed-column updates; seed
- [ ] `FREQ=YEARLY` event generation + age (when year known). user-owned fields on insert only.
- [ ] Auto-update: on enable, on foreground, daily WorkManager. - [x] `FREQ=YEARLY` event generation + age (when year known; sync-time snapshot).
- [ ] Editor: disable managed fields for managed-calendar events. - [x] Auto-update: on enable, on foreground, daily WorkManager.
- [ ] Revoked-permission detection + stalled-state surface. - [x] Editor: disable managed fields for managed-calendar events.
- [ ] Settings sub-page: enable, per-type toggles, title template, show-age. - [x] Revoked-permission detection + stalled-state surface.
- [ ] Translatable strings (titles, sub-page). - [x] Settings sub-page: enable, per-type toggles, title template, show-age.
- [ ] About / store copy for the optional `READ_CONTACTS` permission. - [x] Translatable strings (titles, sub-page).
- [x] About / store copy for the optional `READ_CONTACTS` permission.