From 8b453b7e590943901f4c3a52b26f4f3d578796f8 Mon Sep 17 00:00:00 2001 From: Mason Fox Date: Tue, 31 Mar 2026 08:59:09 -0400 Subject: [PATCH] fix: invalidate series cache when book status changes When a book's status is changed on /books/:id, the series detail page at /series/:name was not being invalidated, causing stale data to be displayed (incorrect status badges and ratings). This fix adds series cache invalidation at two levels: 1. Client-side (React Query): invalidateBookQueries() now invalidates all series queries using queryKeys.series.all() 2. Server-side (Next.js): SessionService and ProgressService now call revalidatePath('/series') to revalidate series pages The fix uses 'nuclear' invalidation (invalidate all series queries) for simplicity and reliability, consistent with the existing shelf invalidation pattern when specific targeting is complex. All 4,013 tests pass with no regressions. --- hooks/useBookStatus.ts | 3 +++ lib/services/progress.service.ts | 1 + lib/services/session.service.ts | 1 + 3 files changed, 5 insertions(+) diff --git a/hooks/useBookStatus.ts b/hooks/useBookStatus.ts index 66cfc13f..9b3b1a45 100644 --- a/hooks/useBookStatus.ts +++ b/hooks/useBookStatus.ts @@ -54,6 +54,9 @@ export function invalidateBookQueries(queryClient: QueryClient, bookId: string): queryClient.invalidateQueries({ queryKey: queryKeys.dashboard.all() }); queryClient.invalidateQueries({ queryKey: queryKeys.library.books() }); queryClient.invalidateQueries({ queryKey: queryKeys.readNext.base() }); + + // Invalidate series pages (if book belongs to a series) + queryClient.invalidateQueries({ queryKey: queryKeys.series.all() }); // Invalidate shelves containing this book // Try to get shelves from cache; if available, invalidate only those shelves (surgical) diff --git a/lib/services/progress.service.ts b/lib/services/progress.service.ts index 7f5f2bf8..49f66034 100644 --- a/lib/services/progress.service.ts +++ b/lib/services/progress.service.ts @@ -521,6 +521,7 @@ export class ProgressService { revalidatePath("/stats"); // Stats page revalidatePath("/journal"); // Journal page revalidatePath(`/books/${bookId}`); // Book detail page + revalidatePath("/series"); // Series pages (list and detail) } catch (error) { getLogger().error({ err: error }, "[ProgressService] Failed to invalidate cache"); // Don't fail the request if cache invalidation fails diff --git a/lib/services/session.service.ts b/lib/services/session.service.ts index 170c0efc..946a14b8 100644 --- a/lib/services/session.service.ts +++ b/lib/services/session.service.ts @@ -1362,6 +1362,7 @@ export class SessionService { revalidatePath("/stats"); // Stats page revalidatePath("/journal"); // Journal page revalidatePath(`/books/${bookId}`); // Book detail page + revalidatePath("/series"); // Series pages (list and detail) } catch (error) { getLogger().error({ err: error }, "[SessionService] Failed to invalidate cache"); // Don't fail the request if cache invalidation fails