From ec7d895c00c571b37ad9255b99b2e1756776c9e1 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Tue, 17 Feb 2026 14:43:42 -1000 Subject: Add calendar cache layer, incremental sync tests, completion assertions - Google Calendar events now cached via CacheFetcher pattern with stale-cache fallback on API errors (new migration 015, store methods, fetchCalendarEvents handler, BuildTimeline reads from store) - Todoist incremental sync path covered by 5 new tests - Task completion tests assert response body, headers, and template data Co-Authored-By: Claude Opus 4.6 --- internal/handlers/handlers.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'internal/handlers/handlers.go') diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 876326e..e06c35e 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -267,7 +267,7 @@ func (h *Handler) aggregateData(ctx context.Context, forceRefresh bool) (*models if h.googleCalendarClient != nil { fetch("Google Calendar", func() error { - events, err := h.googleCalendarClient.GetUpcomingEvents(ctx, 10) + events, err := h.fetchCalendarEvents(ctx, false) if err == nil { mu.Lock() data.Events = events @@ -450,6 +450,22 @@ func (h *Handler) fetchMeals(ctx context.Context, forceRefresh bool) ([]models.M return fetcher.FetchWithCache(ctx, forceRefresh) } +// fetchCalendarEvents fetches Google Calendar events from cache or API +func (h *Handler) fetchCalendarEvents(ctx context.Context, forceRefresh bool) ([]models.CalendarEvent, error) { + if h.googleCalendarClient == nil { + return nil, nil + } + fetcher := &CacheFetcher[models.CalendarEvent]{ + Store: h.store, + CacheKey: store.CacheKeyGoogleCalendar, + TTLMinutes: h.config.CacheTTLMinutes, + Fetch: func(ctx context.Context) ([]models.CalendarEvent, error) { return h.googleCalendarClient.GetUpcomingEvents(ctx, 50) }, + GetFromCache: h.store.GetCalendarEvents, + SaveToCache: h.store.SaveCalendarEvents, + } + return fetcher.FetchWithCache(ctx, forceRefresh) +} + // fetchBoards fetches Trello boards from cache or API func (h *Handler) fetchBoards(ctx context.Context, forceRefresh bool) ([]models.Board, error) { fetcher := &CacheFetcher[models.Board]{ @@ -999,10 +1015,7 @@ func (h *Handler) HandleTabPlanning(w http.ResponseWriter, r *http.Request) { boards, _ := h.store.GetBoards() tasks, _ := h.store.GetTasks() - var events []models.CalendarEvent - if h.googleCalendarClient != nil { - events, _ = h.googleCalendarClient.GetUpcomingEvents(r.Context(), 20) - } + events, _ := h.fetchCalendarEvents(r.Context(), false) var scheduled []ScheduledItem var unscheduled []models.Atom -- cgit v1.2.3