- Add composite indexes on userEpisodeWatches and userMovieWatches for hot queries
- Batch episode tracking: wrap season/batch watches in single transaction (~8 queries vs 8*N)
- Fix N+1 patterns in credits, recommendations, and filmography with batch prefetch+insert
- Stream TV season hydration via Suspense instead of blocking page render
- Optimize webhook logs (per-connection LIMIT 10) and system health queries
- Merge genre filter waterfalls into single Promise.all fetch
- Migrate deprecated Jotai loadable() to unwrap()
- Replace isolated createStore()+Provider with useHydrateAtoms on root store
- Remove unnecessary atomWithStorage SSR guards (handled by Jotai internally)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Motion's initial="hidden" rendered opacity:0 in server HTML, making content
invisible until JS hydrated — causing a multi-second blank gap after skeleton
disappearance. Replaced with CSS @keyframes stagger animation that plays
immediately from SSR. Also made color extraction fire-and-forget, merged
duplicate stats queries, and removed redundant dashboard loading.tsx.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename the person detail route from `app/(pages)/person/[id]` to
`app/(pages)/people/[id]` and update all internal links accordingly.
Strip crew members from the cast carousel so only actors are shown;
remove the `crew` prop from `CastCarousel` and `TitleCast` entirely.
Move the trailer trigger from the metadata row into a centered overlay
on the backdrop image using a new `variant="backdrop"` prop on
`TrailerDialog`, replacing the previous inline button approach.
Swap several icons for better semantic matches: `IconBooks` for the
library section, `IconCheck` for the "Mark Watched" button,
`IconSparkles` on the Recommendations heading, and `IconDeviceTvOld`
on the Seasons heading.
Replace a nested `motion.p` with a plain `<p>` using CSS
`transition-opacity` in `StatsDisplay`. Remove the `animate-gentle-float`
keyframe and the `feed-scroll` utility from `globals.css`, replacing the
latter with the existing `no-scrollbar` class.
Replace ad-hoc useState/useEffect fetch patterns with Jotai atoms and
loadables in StatsDisplay, FilterableTitleRow, BackupScheduleSection,
IntegrationsSection, and CommandPalette. Each component now gets a
scoped Jotai Provider with a pre-initialized store so server-rendered
initial values hydrate correctly. Async data fetching moves into
atom-level loadables, eliminating manual loading flags and cancellation
logic throughout.
Background sparkline area charts on Movies and Episodes cards show watch
activity distribution over the selected period. Periods now use rolling
windows (past 24h/7d/30d/365d) instead of calendar boundaries. Bumped
stats grid breakpoint to lg. Upgraded recharts 2.15.4 → 3.7.0 and fixed
chart.tsx types for v3 (TooltipContentProps, LegendPayload).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Movies and Episodes cards now have an interactive dropdown to switch
between Today, This Week, This Month, and This Year. Extracts reusable
getWatchCount helper in discovery service and adds /api/stats route.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clean up settings section design: consolidate backup cards, add
hover-reveal actions with tooltips, improve icon sizing across
components, and replace custom timeAgo helper with date-fns
formatDistanceToNow in webhook card.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wraps the hero banner h2 in a Link with a subtle primary color
hover transition, matching the app's warm-accent interaction pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Title rows (TitleRow, ContinueWatchingList) now use the shadcn Carousel
component backed by Embla with embla-carousel-wheel-gestures, enabling
mouse wheel horizontal scrolling and drag-to-scroll on desktop while
preserving touch swipe, stagger animations, and existing layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The search modal was inaccessible on mobile since the trigger was
desktop-only. Replace the settings and sign-out buttons (already
available in the mobile tab bar) with a full-width search bar.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace fully client-side dashboard and title detail pages with server
component orchestrators that fetch data directly via service functions,
eliminating extra network round-trips through API routes. Each section
streams independently through its own Suspense boundary.
- Extract getUserStats(), getTitleWithChildren(), getRecommendationsForTitle()
into service layer; update getNewAvailableFeed() to include tmdbId/voteAverage
- Split dashboard into server sections (stats, continue watching, library,
recommendations) with client children for animations
- Split title page into server hero + client interaction provider with shared
context for optimistic mutations across actions and seasons
- Add generateMetadata with OG tags, server-side TMDB ID resolution via
redirect(), loading.tsx and not-found.tsx for both pages
- Add per-section skeleton components, fix ContinueWatchingSkeleton dimensions
- Remove 6 unused API routes (feed/*, titles/[id] GET, titles/[id]/recommendations)
- Remove components/stats-summary.tsx, add lib/types/title.ts for shared types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>