v1.0.379
feat(calendar): multi-day events for trips and other spans
Calendar events could only occupy a single day, so a trip or a conference
had to be entered as its first day (or as one event per day). Non-birthday
events now take an inclusive endDate, and the span is what recurs: every
projected occurrence covers the same number of days.
Server:
- CalendarEvent.endDate; projectEvent stamps each occurrence's own endDate
and treats a span as present until its LAST day — a window that opens
mid-trip still sees it, and a task is overdue only once the span closes. - Occurrences on a shared start date sort longest-span first, so a band
keeps the same row across the cells it crosses. - Route validation: no spans on birthdays, end >= start, 366-day cap, and a
recurring span must close before its next occurrence opens (date, endDate
and recurrence are now merged and validated as one unit on PUT). - Daily News digest lines and Week Ahead rows carry the range; chat's
add/update tools take endDate.
UI:
- The grid expands a span into one DaySegment per covered day, rendered as a
continuous band (squared joins, title repeated at week starts). - The agenda buckets on the span: a trip under way sits under Today as
"day 3 of 7" instead of falling into the past, and rows show "Oct 3 - 9". - The event dialog gets a "Spans multiple days" toggle with an end date;
moving the start drags the end along, keeping the length.
Verified before merge: bun run check clean, 950 tests pass.
Claude-Session: https://claude.ai/code/session_01N1KyQ5QQE1awgozzi58oMG