1. cellDuration indicator: compare against local `cellDuration` state
(not effectiveCellDuration which reads stale profile.cellDuration
since saveSetting bails early for DEVICE_SETTINGS_KEYS)
2. viewDays on mobile now uses orientation instead of fixed width:
portrait (h > w) → 1 day, landscape → 3 days, for ≤768px.
Applied consistently in useEffect, early profile load, and cookie
override blocks so the responsive value is never overridden by
the saved DB preference on mobile.
3. list-view day header on mobile: changed from sticky to
position:relative so it flows with content and never covers tasks
4. time/day column scroll sync: weekly-days-grid was overflow-y:auto
on mobile, creating an independent scroll container that drifted
from the time column. Changed to overflow-y:visible so only
time-grid-wrapper scrolls. Added touch-action:pan-y to day columns
so iOS handles pan immediately without waiting for JS.
v1.81.7
- Added solid background to .list-view .weekly-day-header so tasks
don't bleed through the transparent sticky header while scrolling
- On mobile, offset sticky top by 48px + safe-area-inset to sit
below the mobile header bar instead of overlapping it
v1.81.6
- FAB menu items reordered so Task is closest to button (top),
Search is furthest (bottom)
- auth.ts: session maxAge=30d + updateAge=1d so the JWT cookie is
written as a persistent cookie (Max-Age header), preventing iOS
PWA from losing the session when the app is closed/backgrounded
v1.81.5
- Mobile quick settings view switcher now correctly toggles showTimeGrid
when switching views (list → off, simple/calendar → on), matching
the desktop switcher behaviour. This removes the unwanted time column
in list view on mobile.
- ProjectIcon: normalise legacy icon names stored as "faHeart" / "faHouse"
(camelCase with "fa" prefix) to "heart" / "house" so the FA icon lookup
succeeds instead of falling through to the text fallback.
v1.81.3
- Mobile header: removed spinner/error from inside the date button,
placed as a fixed-width (24px) sibling slot after the button — date
text position is now stable regardless of sync state
- Selected day: added selectedDay state tracking the last day column
the user clicked; passed to getSelectedDay() so "Selektierter Tag"
in the header reflects the actual cursor position, not just visibleDays[0]
- getSelectedDay() priority: explicit selection → today if visible → first visible day
- Navigating to a new week resets selectedDay so the header stays accurate
v1.81.1
- Rename options to be clearer:
- "Vollständiges Datum" → "Heutiges Datum" (always today's date)
- "Aktueller Tag" → "Selektierter Tag" with custom format input
- "Benutzerdefiniert" → "Woche Benutzerdefiniert" (week-based tokens)
- Add custom format input for "Selektierter Tag" (headerCurrentDayFormat)
with tokens: DDDD, DDD, DD, MMMM, MMM, MM, YYYY, WW
- Add separate header display settings for Mobile Portrait and
Mobile Landscape (mobilePortraitHeaderDisplay, mobileLandscapeHeaderDisplay)
- Move refresh/sync icon to fixed-width slot right of date — date no
longer shifts when the icon appears or the spinner replaces it
- Add 3 new Prisma fields (db push required on deploy)
- All 5 languages updated (EN, DE, FR, ES, IT)
v1.81.0
New "Current Day" option in the header display settings shows the
currently visible day formatted as "Mo., 30. März 2026" (weekday +
full date), using the user's locale.
- Available in all views (simple, calendar, list, kanban)
- In kanban view: defaults to "Current Day" when no setting is chosen
- On mobile portrait: existing behavior preserved (always shows current day)
- On mobile landscape: respects the new setting like other options
- No year separator shown (year is already part of the format)
- Added to all 5 languages (EN, DE, FR, ES, IT)
v1.80.4
In portrait mode the header now always shows the day currently on
screen (getVisibleDays()[0]), so swiping left/right updates the
header to reflect the active day. Formatted as weekday + full date
using the user's locale (e.g. "Mo., 30. März 2026").
v1.80.3
In portrait mode on mobile, the header center now displays the full
date with weekday (e.g. "Mo. 30. März 2026") using the user's language
locale. Falls back to today if today is in the visible week, otherwise
uses the week's reference date. Landscape mobile keeps existing behavior.
v1.80.2
Replace all individual useState reads (viewStyle, timeFormat, language,
cellDuration, showTimeGrid, showNextTask, showSomeday, showAllDay, etc.)
with profile.fieldName reads. Individual useState declarations remain; only
read sites are migrated. No UI logic changed.
- getEffective() calls use profile.fieldName as global fallback
- workingHoursStart/End derived from profile.startHour/endHour
- All JSX reads (className, conditionals, child props) use profile.*
- SettingsSidebar value props use profile.* (setters unchanged)
- Add weekStartDay: 1 to profile defaults
- ProjectsSidebar function body reverted (uses language prop, not profile)
- darkMode excluded: localStorage-only, not an API profile field
v1.80.1
- saveSetting: add setProfile(p => ({...p, [key]: value})) so profile
stays in sync with individual setting changes — prevents auto-save
from overwriting fresh settings with stale profile object values
- Extract SettingsSidebar (4725 lines) from WeeklyView.tsx into its own
file; lazy-load with next/dynamic so the ~4500-line settings panel
is deferred until the user opens settings
- Extract shared constants/helpers to src/lib/:
fontConstants.ts (AVAILABLE_FONTS, FONT_WEIGHTS, isCustomFont)
weeklyViewTranslations.ts (translations object, ~1100 lines)
weeklyViewConstants.ts (WeatherDisplayKey, WEATHER_DISPLAY_DEFAULTS)
- WeeklyView.tsx: 16,209 → 10,364 lines (-36%)
v1.80.0
- tasks/route.ts: add per-unit instance cap for virtual task projection
(daily: 60, weekly: 26, monthly: 12, yearly: 3) to prevent unbounded
generation from high-frequency recurring tasks
- WeeklyView: extract calendarEditabilityMap as a separate useMemo keyed
on connections; replace O(n²) nested find() loop with O(1) Map.get()
lookup in the calendarEvents deduplication useMemo
v1.79.0
- tasks/sync GET: batch Google/Outlook/Synology credential fetches with
Promise.all instead of sequential awaits; move per-list Synology
findMany outside the loop to eliminate N+1
- calendar/sync: replace fire-and-forget background refresh with 800ms
Promise.race so fast refreshes return fresh data without blocking
- Extract icon data to iconRegistry.ts; lazy-load IconPicker via
next/dynamic so picker UI code is deferred until needed
v1.78.0
The .time-grid-wrapper .weekly-day-header was set to position:sticky, causing
the day name (MITTWOCH 1. APR.) to appear as a ghost header while scrolling.
The correct sticky element on mobile is the existing day-bar overlay (DO 2.4.)
at the top. Reverted .weekly-day-header to position:relative.
v1.77.6
Batch errors like 'fetch failed' were only retried at the login/client-init
level. Per-calendar fetchCalendarObjects calls had no retry, so a single
transient iCloud network timeout silently dropped all events from that
calendar. Now wraps each fetchCalendarObjects with withRetry(2 retries, 3s/6s).
v1.77.5
Three root causes fixed:
1. Scroll enforcement interval (every 50ms for 2s) was the main blocker:
The setInterval forced gridRef.scrollTop on every frame, making iOS think
the page was always scrolling programmatically. User touches during those
2 seconds were overridden. The header appeared 'stuck' because the view
was frozen. Replaced with a single setTimeout scroll (300ms on first load,
50ms on subsequent). Added history.scrollRestoration='manual' so Safari
doesn't fight us with scroll position restoration.
2. touch-action: pan-y was only on .time-grid-wrapper — NOT inherited by CSS.
Slot child elements had touch-action: auto (default), so iOS still waited
for JS before committing scroll on day column touches. Added touch-action:
pan-y directly to .time-slots-container (the actual touched element area).
Time column labels have no JS handlers so iOS scrolled them freely — this
explains why time column worked but day columns didn't.
3. align-items: start on .weekly-days-grid was wrong (added in last commit).
Removed — CSS grid default stretch is correct.
v1.77.4
Root cause: React registers onTouchStart props as non-passive listeners at the
app root. iOS Safari sees any non-passive touchstart on an ancestor and blocks
the scroll gesture on those elements, waiting for JS to finish. This is why
the time column (no handlers) scrolled freely but day columns (slots had
onTouchStart) were frozen.
Changes:
- Removed onTouchStart prop from all time-slot divs — no more React touch
handlers in the time grid, so iOS never blocks scroll
- Added data-slot-blocked attribute to occupied/protected slots
- Moved slot long-press logic into the permanent native touchstart listener
on document (passive: true), reading slot/date from data attributes
- Added touch-action: pan-y on .time-grid-wrapper — explicitly tells iOS
that vertical pan = scroll even if child content has touch handlers
- CSS: align-items: start on .weekly-days-grid so sticky headers in each
day column have a proper scroll context
- Reinforced position:sticky on .time-grid-wrapper .weekly-day-header
v1.77.3
The slot onTouchStart called attachTouchListeners() which did
document.addEventListener() synchronously — DOM manipulation inside a touch
handler makes iOS Safari uncertain about scroll intent and blocks vertical
scroll on day columns (but not the time column which has no handlers).
Fix: attach all touch listeners ONCE at mount (permanent, passive). The slot
onTouchStart only writes to a ref (zero DOM side effects). The non-passive
drag-tracking listener is still added dynamically but only after the 500ms
long-press actually activates, at which point the user has clearly committed
to a drag gesture rather than a scroll.
v1.77.2
.time-slots-container and .time-column-slots had overflow-y: auto which created
independent scroll contexts inside each day column, eating touch events and
preventing the parent time-grid-wrapper from scrolling.
v1.77.1
- Header center (KW/year/goal/quote) now fades to 20% opacity and blurs
on hover so the controls behind it are readable on smaller screens
- Fix iOS scroll freeze: touchmove listener on grid slots was non-passive,
causing Safari to wait ~20s (iCloud sync duration) before allowing scroll;
now attaches a passive listener initially and only upgrades to non-passive
when the long-press drag actually activates (after 500ms hold)
v1.77.0
The time grid previously had two separate overflow-y:auto scroll containers
(the time-column labels + the day columns grid), synced via JS scrollTop
assignment. On iOS Safari, this caused severe desync and bounce effects:
momentum scroll continued after touch-end, and the programmatic scrollTop
correction fought against native momentum, making the grid stutter/bounce.
Changes:
- time-grid-wrapper is now the SINGLE overflow-y:auto scroll container
(ref=gridRef, onScroll handler moved here from weekly-days-grid)
- time-column and weekly-days-grid have overflow:visible — they scroll
with their parent wrapper without fighting each other
- Removed handleTimeColumnScroll, timeColumnRef, timeGridWrapperRef
(all sync logic now redundant)
- jumpToHour and initial scroll position now set only gridRef.scrollTop
- CSS: weekly-days-grid overflow changed to visible
- CSS: re-enabled position:sticky on .weekly-day-header for mobile —
sticky now works correctly since scroll container is an overflow-y parent
- CSS: hid time-column-header on mobile (saves vertical space)
v1.76.2
Both settings were stored as per-view overrides by the full settings panel
but the quick sidebar toggles read/wrote the global profile value. The
per-view override took precedence in getEffective(), so global changes
from the quick toggle were silently ignored.
- Settings panel now calls saveField() (global profile) for these two
settings instead of saveViewSetting() (per-view override)
- On change, also clears any stale per-view overrides via
saveViewSetting(key, value, false) so the global value always wins
- Quick sidebar eye icons now reflect effectiveShowTaskCheckboxes /
effectiveShowProjectIcons instead of the raw profile values
v1.76.1
Users can now create sync rules to automatically sync events between
any two connected calendar providers (Google, Apple, Outlook, Synology).
- New Prisma models: CalendarSyncRule + CalendarSyncMapping
- Sync engine in src/lib/calendar-cross-sync.ts: fingerprint-based
change detection, anti-loop protection, one-way and two-way support
- API routes: GET/POST rules, PATCH/DELETE rule by id, POST run
- CalendarSyncRulesPanel component with rule list, add/edit form,
toggle enable/disable, Sync Now button with result summary
- New "Sync" tab in settings sidebar (between Connections and Account)
- Sync rules run automatically after each forced calendar cache refresh
v1.76.0
- Skip optimistic UI update for new recurring events (causes duplicate
when force-sync fetches expanded instances with different IDs)
- Mobile sticky day bar: listen on gridRef scroll instead of window
(time-grid scrolls inside weekly-days-grid, not window)
- Remove broken position:sticky from mobile day headers (CSS sticky
doesn't work inside CSS grid scroll containers); use fixed overlay only
- Also propagate isRecurring flag in create response for Google/Outlook
v1.75.8
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace inline delete buttons (Dieses/Künftige/Alle) with a proper
overlay dialog matching the recurring edit overlay style. Shows animated
dots on the active delete option while processing. Other options dim
during deletion.
v1.75.7
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove translateY on first time-slot-label only (via :first-child) instead
of adding padding-top which broke task alignment. Reverts padding approach.
v1.75.6
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The first time-slot label's translateY(-50%) pushed it above the container
top edge. Added padding-top to time-column-slots and time-slots-container,
and disabled the translate on the first label. Reverted 00→0.
v1.75.5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apple sync was doing 2 logins per cycle: getAppleCalendars (to get calendar
list for filtering) + getUpcomingEventsBatch (to fetch events). Now uses
stored calendar metadata from DB for filtering, reducing to 1 login total.
Same optimization applied to Synology. Also adds 24:00 end-of-day line
to time grid, and throttles tab-focus sync to max once per 5 minutes.
v1.75.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Apple/Synology: batch fetch events with single client login instead of N separate connections
- Apple: add client cache (5min TTL) to reuse authenticated DAVClient across operations
- Apple: add retry with backoff for transient ConnectTimeoutError/SSL failures
- Increase cache stale threshold from 2min to 15min
- Increase background sync interval from 2min to 15min
- Throttle tab-focus sync to at most once per 5min
v1.75.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The scrollable time grid already shows all 24 hours and auto-scrolls
to the preferred start hour on load, making the start/end hour
filter controls redundant. Removed from sidebar, header, and
full settings modal.
v1.75.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of relying on CSS position:sticky (unreliable on iOS Safari),
adds a fixed overlay bar at the top of the viewport that shows the
current day name as the user scrolls through stacked day columns.
Uses IntersectionObserver to track which day header is near the
viewport top. Appears after scrolling past 80px, with blur backdrop.
v1.75.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Log the event ID decomposition, update payload, and Graph API
response status to diagnose why recurring event updates aren't
persisting for Outlook.
v1.74.8
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Reduced cache stale threshold from 15 minutes to 2 minutes
- Reduced background sync polling from 15 minutes to 2 minutes
- Added visibilitychange listener: syncs calendars and tasks when
the user switches back to the tab (catches external edits in
Apple Calendar, Google Calendar, etc.)
v1.74.7
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of force-refreshing all calendar providers after create/update/delete,
now only the specific connection that owns the modified calendar is refreshed.
This significantly speeds up recurring event operations when multiple
providers are connected.
v1.74.6
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Calendar events now use --weekly-task-font, --weekly-task-size,
and --weekly-task-weight instead of separate event font variables,
so events and tasks always look consistent.
v1.74.5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dots pulse sequentially (. . .) to give clear visual feedback
that the operation is still in progress.
v1.74.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Always show provider icon (Google/Apple/Outlook/Synology) at
bottom-right of event blocks using FontAwesome icons
- Save button shows "Erstelle..." / "Creating..." while saving
instead of just "..." to reduce user confusion during sync
v1.74.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All create, update, and delete operations now trigger an immediate
forced refresh from providers instead of relying on stale cache.
Previously, deleting recurring events left ghost instances visible
until the next background sync cycle.
v1.74.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Show provider icon (Google/Apple/Outlook/Synology) left of calendar color dot
- Hide URL field when Synology calendar is selected (not supported)
- Force refresh after creating recurring events so all instances show immediately
(previously only the first occurrence appeared until next sync cycle)
v1.74.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Compact, icon-driven layout inspired by Google Calendar:
- Icon-row layout with left-aligned icons for each field
- Color accent bar and save button match selected calendar color
- Toggle switch for all-day instead of checkbox
- Compact From/To time inputs
- Tighter spacing throughout, smaller font sizes
- German translations for all labels
- Footer bar with subtle background
- Shorter delete buttons for recurring events (This/Future/All)
v1.74.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fixed weekly-days-grid applying fixed height in non-time-grid views
(simple/list), which broke the scroll context for sticky headers
- Reordered mobile FAB menu: Aufgabe, Termin, Projekt, Fokus, Suchen
- Changed "Suche" to "Suchen" in FAB menu
v1.73.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
overflow-x: hidden on .simple-view .weekly-day-column was creating a
scrolling context that broke position: sticky on the day header.
Changed to overflow-x: clip which clips content without affecting sticky.
v1.73.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Non-passive touchmove listener was permanently attached to document,
breaking browser scroll optimizations. Now only attached during active
long-press and removed immediately after.
v1.73.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tap and hold (~500ms) on an empty time slot to activate, then drag to
select time range. Opens calendar event modal with pre-filled times.
Includes haptic vibration feedback on activation. Normal tap and scroll
gestures are not affected.
v1.73.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Collision detection rewritten to check duration-based overlap instead
of exact startTime match. Rolling tasks find the next truly free slot.
v1.72.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Events created or updated via the API were missing the calendar's
backgroundColor, causing them to render without their provider color.
v1.72.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Drag on empty time slots to create calendar events with pre-filled time range
- Rolling tasks now work per-task without requiring global autoRolling setting
- Add firstDayOfWeek to Outlook weekly recurrence patterns
- Add debug logging for Outlook recurrence creation
v1.72.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Outlook Graph API returns datetimes in the user's timezone without Z suffix
by default. The sync path already requested UTC and appended Z, but
create/update responses did not. This caused the optimistic UI update to
show events 1 hour off until the next sync corrected it.
Fix: add Prefer: outlook.timezone="UTC" header to create/update calls
and normalize response datetimes with Z suffix.
v1.71.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cache PrismaClient globally in ALL environments (was only cached in dev).
Without this, production could create multiple PrismaClient instances,
each with its own connection pool, exhausting the database connections.
v1.71.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
iCloud returned 501 Not Implemented for updateObject calls.
Switch to updateCalendarObject which properly sends CalDAV PUT requests.
Fixed in both Apple Calendar and Synology Calendar update + recurring delete paths.
v1.71.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Strip HTML tags from descriptions before sending to CalDAV providers (Apple/Synology)
- Show event location underneath time in calendar event blocks (like Google Calendar)
- Fix German umlaut rendering by adding latin-ext font subset
- Fix CalDAV event updates losing TZID on DTSTART/DTEND (Apple Calendar recurring edit fix)
- Add error logging for CalDAV PUT responses
- Reduce wasted space when all-day events section is collapsed (24px max)
- Fix quotes with missing umlauts (ä, ö, ü, ß)
v1.71.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Redesigned drag/resize and modal recurring edit dialogs with radio buttons
(This event / This and following / All events) with descriptions
- Added German/English i18n to both recurring edit dialogs
- Repeat-on day buttons now respect weekStartDay setting (Mon/Sun start)
- Added language prop to CalendarEventModal
v1.70.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When editing a recurring calendar event (via modal or drag/resize),
the user is now asked whether changes apply to just this instance or
all events in the series.
- Modal: Save button shows "This event" / "All events" options for
recurring events
- Drag/resize: centered overlay prompt with same options + cancel
- API PATCH: editMode=all routes update to the series master ID
(recurringEventId) instead of the instance ID
- Cancel on drag prompt reverts to original position
v1.69.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: background calendar sync every 2min with forceRefresh:true
+ task sync every 5min + cache stale threshold of 2min = 12,500+
Google Calendar + 8,800 Google Tasks API calls/day for a single user.
Changes:
- Calendar background sync: 2min → 15min
- Task sync polling: 5min → 15min
- Cache stale threshold: 2min → 15min
- Remove forceRefresh:true from background sync (let staleness check
decide naturally)
- Remove redundant 8s re-fetch after background sync
- User actions (create/update/delete) still sync immediately
Expected reduction: ~10-15x fewer external API calls.
v1.68.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cross-day drag now works: getEventsForSlot uses drag state's current
start time to assign the dragged event to the correct day column
- Add showCalendarProviderIcon to Prisma schema, profile API GET/PATCH
so the setting persists across sessions (was frontend-only before)
- DB migration applied via prisma db push
v1.68.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Calendar providers return descriptions with HTML tags (e.g. <p>test</p>).
Strip them before displaying in the hover tooltip.
v1.67.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Google recurring events missing isRecurring flag (recurringEventId
was not mapped from Google API response)
- Add note icon (FileText) on events with descriptions, tooltip on hover
- Cross-day drag-and-drop: detect day column under cursor and shift date
- Fix event detail popup opening after drag/resize by setting ref before
async operations
- Add data-date attribute to day columns for drag target detection
- Use CSS class for icon row layout to prevent overlap
v1.67.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Recurring events appeared twice on their creation day because both the
series master (from POST cache) and the expanded instance (from sync)
had different IDs. Now filters out masters when instances exist, and
also deduplicates by title+startTime+calendarId as a fallback.
v1.66.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add resize handles (top/bottom) on hover to change event duration, and
drag-to-move support with live preview and 5-minute snapping. Includes
3px dead zone to distinguish clicks from drags, optimistic UI updates
with server rollback on failure, and recurring/provider icons on
time-grid events. Also fixes Google delete 410 Gone and Outlook delete
404/encodeURIComponent issues.
v1.66.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The base .time-slot-event and .simple-view .time-slot-event CSS had
left: 0 and right: 0 (with !important) which overrode the inline
overlap layout positioning. Removed so events can be placed side by
side when they overlap.
v1.65.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Overlapping calendar events on the same time slot are now rendered
side by side instead of stacked on top of each other. Uses a greedy
column assignment algorithm to compute layout per day.
- Outlook delete/update: use /me/events/{id} as primary endpoint
(without encodeURIComponent) instead of calendar-scoped endpoint,
with fallback. Fixes ErrorItemNotFound for recurring series masters.
v1.65.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a toggle in Calendar settings to show the provider icon
(Google/Apple/Outlook/Synology) in the bottom-right corner of
calendar event blocks. The recurring icon is grouped alongside
when both are visible.
v1.64.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the calendar-scoped Graph API endpoint returns 404 for series
master or instance IDs, fall back to /me/events/{id} which handles
these cases. Fixes ErrorItemNotFound on delete/update of recurring
Outlook events.
v1.63.5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When updating Apple/Synology events that have DTSTART with a TZID
parameter, convert the incoming UTC dateTime to local time in that
timezone before writing back. Prevents ICAL.js from storing UTC
values under a local timezone, which caused +1h shifts on update.
v1.63.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Display the browser-detected timezone (e.g. Europe/Berlin) as a
read-only field in the Localisation settings tab.
v1.63.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add icalTimeToUtcDate() helper to Apple/Synology parsers that
correctly converts ICAL.Time with unresolved TZIDs to UTC dates
(fixes +1h shift on Synology/Apple recurring events across DST)
- Add recurring icon (Repeat) to bottom-right of all calendar event
blocks when event.isRecurring is true
v1.63.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Google: add timeZone to start/end objects when recurrence is present
(fixes "Missing time zone definition for start time" error)
- Outlook: pass user timezone instead of UTC for event create/update,
convert UTC dateTime to local representation (fixes +1h DST shift
on recurring instances)
- Outlook: use instance ID for single-occurrence delete instead of
series master ID (fixes ErrorItemNotFound on delete)
v1.63.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a fourth delete option for recurring events: delete this instance
and all past occurrences. For CalDAV (Apple/Synology), this moves
DTSTART forward to the next occurrence. Includes optimistic UI removal.
v1.63.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Outlook returns dateTime without Z suffix despite timeZone being UTC,
causing JS to parse as local time (1h shift). Now appends Z for UTC dates.
- Added frontend deduplication to prevent stacked rendering of duplicate events.
- Added Outlook event debug logging for recurring event investigation.
v1.62.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Google and Outlook event mappings were missing isRecurring and
recurringEventId fields, so the modal never showed recurring delete
options and displayed recurring events as "Repeat: Never".
v1.62.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Events fetched via /calendarView must be addressed via
/me/calendars/{calendarId}/events/{eventId}, not /me/events/{eventId}.
The latter returns ErrorItemNotFound for calendar-view instance IDs.
v1.62.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When deleting a recurring calendar event, users now choose between
deleting just this instance, this and future instances, or all instances.
Supports Google, Apple (iCloud), and Synology CalDAV providers.
v1.62.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use TZID-based local time (instead of UTC 'Z') for DTSTART/DTEND
when creating recurring CalDAV events, preventing DST-related time
shifts (e.g. 13:40 CET showing as 14:40 CEST after clock change)
- Send browser timezone from CalendarEventModal to server
- Guard against NaN event duration (missing/invalid endTime) which
caused event blocks to stretch to end of day
v1.61.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Store calendar colors (backgroundColor) from Apple and Synology
during connection setup
- Auto-refresh missing colors for existing Apple/Synology connections
- Show color dots next to calendar names in settings
- Add "Custom..." recurrence option with interval (every N days/weeks/
months/years) and day-of-week selection for weekly recurrence
- Generate proper RRULE with INTERVAL and BYDAY for all providers
- Generate proper Outlook Graph recurrence with custom intervals
v1.61.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fetch and display Outlook calendar colors from Microsoft Graph API
instead of hardcoded blue
- Add recurrence end options to calendar event modal: Never, On Date
(UNTIL), or After X occurrences (COUNT)
- Pass recurrence end parameters through to RRULE generation for all
providers (Google, Apple, Synology, Outlook)
v1.60.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move project icons from flex siblings into the text span so that
multi-line task titles wrap around the icon instead of leaving
empty space below it.
v1.59.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New per-view setting to display project icons next to task titles in
simple, calendar, and list views. Toggle via Quick Settings sidebar,
similar to the existing 'Checkboxes' toggle.
v1.59.0
Replace the small grid of ~45 icons with a searchable IconPicker component
featuring ~250 icons from FontAwesome and Material Design Icons. Includes
keyword search, library tabs (All/FA/MDI), and categories covering tech,
home, sports, food, nature, finance, health, and more.
v1.58.0
Add picker-open class when project picker is shown to keep task-actions
visible even when mouse leaves the task hover area. Elevate z-index on
picker-open tasks so the dropdown isn't obscured by adjacent tasks.
v1.57.15
The updatedMin optimization skipped tasks that were missed during
initial sync. Now does a full fetch when a someday list is linked,
ensuring all remote tasks are discovered.
v1.57.13
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Google Tasks and Microsoft To-Do sync now paginate through all
results instead of capping at 100 tasks per list.
- Synology calendar pruning in GET /connections is now fire-and-forget
so a slow/unreachable NAS doesn't block the entire response.
v1.57.12
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Respects Retry-After header when available, otherwise uses
exponential backoff (2s, 4s, 6s) for up to 3 attempts.
v1.57.11
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Raise z-index on the list header when delete confirmation is active
so Cancel/Delete buttons render above the task list items.
v1.57.10
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The "Add task..." input was overlapping the Cancel/Delete buttons,
making it impossible to click Delete.
v1.57.9
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Unlink external references (externalId, externalProvider, externalListId)
from someday lists and tasks when their associated calendar connection
is deleted, so orphaned entries don't persist in the UI.
v1.57.8
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apple calendar events were fetched from ALL calendars regardless of the
user's Display checkbox selection. Now respects the stored selected state,
matching the behavior of Synology/Google/Outlook providers.
Also reverts the title-based deduplication which was too aggressive.
v1.57.7
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Events with the same title, start, and end time from different calendars
are now shown only once instead of duplicated in the all-day and time grid.
v1.57.6
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Log individual calendar names/URLs from server and stale calendar IDs
to diagnose why deleted calendars persist in stored list.
v1.57.5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a Synology calendar returns 404 during event fetch, remove it from
the stored calendar list instead of silently returning empty results.
v1.57.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a Google Tasks list returns 404 during sync, soft-delete all local
tasks linked to it and unlink the synced someday list instead of spamming
error logs.
v1.57.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When loading calendar connections, the API now fetches the live calendar
list from Synology and removes entries that no longer exist on the server.
v1.57.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Notion OAuth integration: start/callback routes, calendar-events dispatch,
CRUD operations (create/update/delete via Notion API)
- New notion-calendar.ts provider library with database discovery
- Onboarding wizard: expanded to 6 steps (header/tasks/display design),
improved preview fidelity, universal dummy content, Notion in connect step
- Apple Calendar: label changed to "events only", added warning that
Reminders are unsupported since iOS 13 (no CalDAV/API from Apple)
- Fixed 12h time format on now-line, wizard settings apply on completion
v1.57.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 6-step onboarding wizard (welcome, language, connect providers,
view style, work hours, styling) for new signups
- Added hasCompletedOnboarding field to User schema
- Fixed subtask progress bar in GridTaskBlock (simple/calendar views)
- Fixed kanban drag-and-drop to someday area
- Fixed weather/provider icon overlap in time grid tasks
- Provider icon positioning: inline when weather on, top-right when off
v1.56.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increased progress bar from 24x4px to 36x5px for better visibility
in the task subtask indicator badge.
v1.55.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Kanban cards now have inline subtask expand/collapse with progress bar,
chevron toggle, and checkbox list. Calendar view subtask badge updated
to match with ChevronDown icon, highlight when expanded, and wider
progress bar. Consistent UX across both views.
v1.55.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move trash icon to lower-left corner, add OK and Cancel buttons
in the lower-right corner.
v1.55.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Click any kanban card to open a Trello-style detail modal with:
- Title editing
- Project assignment with dropdown
- Kanban stage selector
- Due date picker
- Someday list assignment
- Markdown notes editor
- Subtask management (add, toggle, edit, delete)
- Task deletion
Responsive design: slides up as bottom sheet on mobile.
v1.55.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clicking a kanban card now opens the notes sidebar for editing notes,
subtasks, and other task details. Cards also show subtask count and
notes indicator. Added FileText icon import.
v1.54.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add inline task creation in kanban view columns - creates tasks in a
"Kanban" someday list (or project-named list if filtered by project).
Optimize Google Tasks sync: use updatedMin to fetch only changed tasks,
increase sync interval to 5min, handle 429 quota errors gracefully.
v1.54.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds SSE-based push notifications so changes made on one device
appear instantly on all other connected devices for the same user.
- SSE notification hub (src/lib/sse.ts) with per-user client tracking
- Stream endpoint (/api/events/stream) with 30s heartbeat
- Task and list API routes notify connected clients on mutations
- Client auto-connects with 5s reconnect on connection loss
- Existing 2-minute polling sync remains as fallback
v1.53.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JWT callback was querying DB on every request which could hang if DB
is slow. Now only queries when token.id is missing, and wraps in
try/catch so session still resolves on DB errors.
v1.52.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users can now pick which weather data to show per time slot: icon,
temperature, feels like, wind speed, gusts, rain probability,
precipitation, humidity, and UV index. API now fetches all data
from Open-Meteo. Also fixed slot height for 20min duration.
v1.52.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The custom adapter wrapper that stubbed session methods was preventing
sessions from loading. Reverted to plain PrismaAdapter - the original
credentials login issue was caused by missing DB columns, not the adapter.
v1.51.6
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Timeslot options are now 15min (4/hr), 20min (3/hr), 30min (2/hr),
and 1h (1/hr). Removed the 2h option which didn't make sense.
v1.51.5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
viewSettings, weatherEnabled, weatherLat, weatherLon, weatherLocation,
lightTheme, darkTheme, emailVerificationCode, mobileFontScale, and
notificationsEnabled were in the Prisma schema but never had migrations,
causing all profile saves to fail on the server.
v1.51.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The weatherRecentCities field was added to the Prisma schema but no
migration was created, causing PrismaClientValidationError on the server.
v1.51.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix NextAuth CredentialsProvider + PrismaAdapter conflict by stubbing
adapter session methods (JWT strategy doesn't use DB sessions)
- Improve login error handling with redirect:false for real error messages
- Move all-day section resize bar to top when allDayPosition is "below"
- Fix resize drag direction for top-positioned all-day handle
v1.51.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Match the header view switcher icons (Calendar, CalendarDays, ListTodo,
Kanban) in the settings sidebar tab bar.
v1.51.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per-view settings (cellDuration, showSomeday, etc.) now persist across
page reloads by using a ref to avoid stale closure bugs in saveViewSetting
and removing global state pollution from per-view onChange handlers.
Weather display fixed to use effectiveWeatherEnabled for fetch/render.
Added weatherRecentCities (max 8) as quick-switch pill buttons.
Kanban checkboxes now respect the showTaskCheckboxes per-view setting.
v1.51.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move view style selector (Simple/Calendar/List/Kanban) to the top
of the general settings tab. Settings below now automatically apply
to the selected view. Replaces the previous per-view badge approach
with a cleaner tab-based UI: switch to a view tab, adjust its
settings — done.
Per-view settings: hour format, sub-hour labels, weather, checkboxes.
v1.50.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The formatHour function was ignoring the format parameter in 24h
mode, always returning HH:MM. Now "short" returns just the hour
number without leading zero or :00.
v1.49.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add viewSettings JSON field to User model storing per-view overrides.
Settings like hour label format, sub-hour labels, weather, and task
checkboxes can now be set per view (simple/calendar/list/kanban) or
globally. A clickable badge next to each setting shows "All" (global)
or the current view name (per-view). Click to toggle scope.
Also fixes hourLabelFormat not actually being applied to time column
rendering (was hardcoded, now uses effective per-view value).
v1.49.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
In list mode there's no time column, so the all-day label was
causing a left offset mismatch. Removed the label so all-day
events grid lines up with the day columns below.
v1.48.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use trash icon instead of X for delete button
- Add cancel X next to the red confirm button
- Hide all-day calendar events in kanban view
v1.48.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
First click on X shows a red "Confirm" button inline. Second click
deletes the stage and moves all its tasks back to "no phase".
Clicking elsewhere resets the state.
v1.48.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Column headers are now editable: click the name to rename, click
the color dot to change color, hover to reveal delete button
- "+" column at the end to add new stages
- Removed kanban stages section from settings sidebar
v1.48.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The calendar-view time-slot-label override was clobbering the
hour-start font-weight and sub-hour font-size. Now properly
differentiates hour labels (bolder) from sub-hour labels (smaller,
lighter).
v1.47.5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove display:none on time column so it shows again
- Remove all time-slot grid lines for a cleaner look
- Remove vertical column borders (no right borders)
- Bold uppercase headers with subtle bottom border
- Cleaner task items with more padding
v1.47.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only show horizontal grid lines at full hour boundaries, matching
the clean Google Calendar aesthetic from the reference screenshot.
v1.47.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Put + icon (create project) on far left, followed by project drop
chips, then a spacer, then search/filters on the right — all in
one unified toolbar row.
v1.47.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace emoji project icons with FontAwesome solid icons (46 icons)
with proper icon picker grid and legacy emoji fallback
- Fix weather temperature unreadable on mobile (white on white) by
adding explicit dark/light color
- Fix weekday sticky header on mobile: correct top offset for
time-grid scroll container, use overflow-x: clip to not break sticky
- Swap mobile header: quick settings (PanelLeftOpen) on left,
burger menu (settings) on right, remove search icon (available
in left sidebar)
v1.46.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create dedicated Projects sidebar (separate from settings) with full
CRUD, emoji picker, and dark mode support
- Move all quick actions (nav, search, jump to date, calendar event,
recurring tasks, goal, focus, dark mode, view/days/slot/hours,
undo/redo/refresh) from right settings sidebar to left quick settings
- Remove projects tab from settings — all project management via sidebar
- Fix iPhone sticky headers: time-column-header no longer sticky on
mobile, weekly-day-header remains sticky
v1.45.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply maxHeight constraint to time-grid-wrapper on all devices,
not just desktop. iOS Safari needs an explicit height bound for
overflow-y: scroll to work within a flex container.
v1.44.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add weather feature with Open-Meteo API: hourly temp/icon overlay on time slots,
location search via geocoding, weather toggle in settings
- Move project management to dedicated settings tab with emoji icon picker
- Fix iPhone single-day view starting on yesterday instead of today
- Fix deleted Apple calendar events persisting until app reboot by
scheduling a delayed re-fetch after stale background sync
v1.44.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On tablet (≤1024px), hide days-to-show, time range, slot duration,
and goal/quote from header. Move days and slot controls into the
overflow menu. Only view switcher icons + KW/year + navigation remain
in the header bar.
v1.43.2
- Add emoji icon picker for projects (40 icons to choose from)
- Redesign project list in settings with color left-border, icon display
- Show project icons on task cards, project picker, and kanban cards
- Add New Project button to desktop header, tablet overflow menu, and mobile FAB
- Remove duplicate unused /api/tasks/projects route
v1.43.0
Desktop shows all action buttons inline. On tablet (≤1024px), secondary
actions collapse into a dropdown overflow menu with proper touch targets,
dark mode support, and fade-in animation.
v1.42.0
FAB now opens a fan menu with 4 options instead of directly adding tasks:
- Task: opens the existing bottom sheet for quick task entry
- Event: opens the calendar event modal
- Focus: enters focus mode
- Search: opens search modal
FAB rotates to X when menu is open, backdrop dismisses on tap.
Each menu item has a colored icon bubble with label.
v1.41.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Subtasks: slide-in animation, left border accent, hover highlights,
mini progress bar in indicator badge, scale effect on checkbox hover
- Notes: slide-in animation, cleaner toolbar with SVG icons instead of
emoji, proper dark mode support, focus ring on editor, max-height cap
- Both use CSS variables for consistent theming
v1.40.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix goToToday landing on yesterday in single-day view (skip startDayOffset)
- Add quick actions panel to settings sidebar for all screen sizes (not just mobile)
- Add view style switcher, visible hours, search, and new project to sidebar
- Change weekly-container to height:100vh for proper flex layout
- Someday/all-day sections use flex-shrink:0 for stable resize behavior
- Collapse uses height:30px!important to override inline styles
v1.40.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use 1px border style instead of thick background bar
- Switch from maxHeight to height for proper resize control
- Fix overflow conflict in expanded someday CSS
- Both all-day and someday areas now properly resizable
v1.39.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Handle now appears above the someday section as a visible bar with
background color. Dragging up increases height (inverted for top handle).
Handle styling improved with hover/active states for better discoverability.
v1.39.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resize handles for all-day and someday areas were inside the
overflow:auto section, making them scroll away. Now placed
outside the section so they always sit at the bottom border.
v1.39.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rolling ran inside fetchTasks before profile.autoRolling was loaded,
so it always saw false and skipped. Now runs as a dedicated effect
that waits for both profile and tasks to be ready.
v1.39.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Sync tasks to external provider when dragged to a synced Someday list (Google/Outlook/Synology)
- Add Synology support to POST /api/tasks/sync endpoint
- Edit recurring task series (title, interval, unit, time) all at once via new API
- Make Someday and all-day areas vertically resizable with drag handles (height persisted in cookies)
- Include Someday tasks in search results with list name display
- Instant calendar event appearance after creation (improved optimistic update + immediate cache refresh)
- Fix project color not updating on tasks when project color changes
- Add database backup script for Supabase LXC
v1.39.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>