Optimize performance: batch DB ops, N+1 fixes, Suspense streaming, and Jotai best practices

- 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>
This commit is contained in:
2026-03-05 17:33:27 -05:00
co-authored by Claude Opus 4.6
parent ed825f3a78
commit f36ca0cbf8
23 changed files with 839 additions and 571 deletions
+6 -6
View File
@@ -7,6 +7,7 @@ import { db } from "@/lib/db/client";
import { episodes } from "@/lib/db/schema";
import {
logEpisodeWatch,
logEpisodeWatchBatch,
logMovieWatch,
markAllEpisodesWatched,
rateTitleStars,
@@ -67,9 +68,10 @@ export async function watchSeason(seasonId: string) {
.from(episodes)
.where(eq(episodes.seasonId, seasonId))
.all();
for (const ep of seasonEps) {
logEpisodeWatch(userId, ep.id);
}
logEpisodeWatchBatch(
userId,
seasonEps.map((ep) => ep.id),
);
}
export async function unwatchSeasonAction(seasonId: string) {
@@ -79,7 +81,5 @@ export async function unwatchSeasonAction(seasonId: string) {
export async function batchWatchEpisodes(episodeIds: string[]) {
const userId = await getSessionUserId();
for (const id of episodeIds) {
logEpisodeWatch(userId, id);
}
logEpisodeWatchBatch(userId, episodeIds);
}