Fix: reduce N+1 backend requests triggered by RSC prefetch#4888
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR optimizes Next.js metadata caching and link prefetching across frontend pages and components: it adds explicit 60-second ISR revalidation to page metadata generation functions, extends API methods to accept fetch options, disables automatic link prefetching across 20+ components, and introduces a dedicated metadata-focused post fetcher. The backend user profile API now conditionally fetches statistics based on a query parameter, with corresponding frontend type hierarchy updates. ChangesFrontend: ISR Revalidation and Link Prefetch Optimization
Backend: User Profile Statistics and Type Refactoring
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@front_end/src/app/`(main)/questions/[id]/[[...slug]]/utils/get_post.ts:
- Around line 52-54: getPostForMetadata currently calls ServerPostsApi.getPost
directly which bypasses getPost()’s legacy recovery (legacyGetPostId +
permanentRedirect) and causes NEXT_NOT_FOUND during generateMetadata; update
getPostForMetadata to use the existing getPost (or cachedGetPostForMetadata if
caching is needed) so legacyGetPostId() and permanentRedirect() paths are
preserved when generating metadata for page.tsx's generateMetadata.
In `@front_end/src/components/posts_feed/feed_tournament_tile.tsx`:
- Line 26: The current useMemo usage in feed_tournament_tile.tsx (const now =
useMemo(() => Date.now(), [])) freezes the timestamp for the component lifetime;
replace it with a plain per-render timestamp (const now = Date.now()) inside the
FeedTournamentTile component body so time-based labels update each render, and
remove the now useMemo import if it's no longer needed; update any related logic
that assumed a mount-only timestamp to use this per-render now.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5f91fb13-8dec-44f5-813a-0375273c04bc
📒 Files selected for processing (27)
front_end/src/app/(main)/(tournaments)/tournament/[slug]/page.tsxfront_end/src/app/(main)/c/[slug]/[id]/[[...postSlug]]/page.tsxfront_end/src/app/(main)/c/[slug]/page.tsxfront_end/src/app/(main)/notebooks/[id]/[[...slug]]/page.tsxfront_end/src/app/(main)/questions/[id]/[[...slug]]/page.tsxfront_end/src/app/(main)/questions/[id]/[[...slug]]/utils/get_post.tsfront_end/src/app/(main)/questions/[id]/components/key_factors/item_view/question_link/question_link_key_factor_item.tsxfront_end/src/app/(main)/questions/[id]/components/key_factors/questions_feed_view/key_factor_tile_view.tsxfront_end/src/app/(main)/questions/[id]/components/sidebar/similar_questions/similar_question_card.tsxfront_end/src/app/(main)/questions/components/coherence_links/display_coherence_link.tsxfront_end/src/app/(prediction-flow)/tournament/[slug]/prediction-flow/page.tsxfront_end/src/components/comment_feed/comment_post_preview/compact_comment_post_card.tsxfront_end/src/components/communities_feed/community_feed_card.tsxfront_end/src/components/conditional_tile/conditional_card.tsxfront_end/src/components/consumer_post_card/basic_consumer_post_card.tsxfront_end/src/components/forecast_card.tsxfront_end/src/components/news_card.tsxfront_end/src/components/post_card/basic_post_card/comment_status.tsxfront_end/src/components/post_card/basic_post_card/index.tsxfront_end/src/components/post_card/basic_post_card/status_rail.tsxfront_end/src/components/post_card/community_disclaimer.tsxfront_end/src/components/post_card/compact_search_post_card.tsxfront_end/src/components/post_default_project.tsxfront_end/src/components/posts_feed/feed_tournament_tile.tsxfront_end/src/components/ui/button.tsxfront_end/src/services/api/posts/posts.shared.tsfront_end/src/services/api/projects/projects.shared.ts
Cleanup: Preview Environment RemovedThe preview environment for this PR has been destroyed.
Cleanup triggered by PR close at 2026-06-17T17:40:50Z |
…de_stats` query param
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
front_end/src/app/(main)/accounts/profile/components/social_media_section.tsx (1)
90-90:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd
noopener noreferrerfor external links opened in a new tab.Line 90 opens user-provided URLs with
target="_blank"but omitsrel="noopener noreferrer", which leaves a reverse-tabnabbing path.Suggested patch
- <Link href={link} target="_blank" rel="ugc"> + <Link href={link} target="_blank" rel="ugc noopener noreferrer">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@front_end/src/app/`(main)/accounts/profile/components/social_media_section.tsx at line 90, The Link component in the social_media_section.tsx file that opens user-provided URLs with target="_blank" currently only has rel="ugc" but is missing the security attributes needed to prevent reverse-tabnabbing attacks. Update the rel attribute on the Link element to include both "ugc" and "noopener noreferrer" by combining them as a space-separated string in the rel prop.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In
`@front_end/src/app/`(main)/accounts/profile/components/social_media_section.tsx:
- Line 90: The Link component in the social_media_section.tsx file that opens
user-provided URLs with target="_blank" currently only has rel="ugc" but is
missing the security attributes needed to prevent reverse-tabnabbing attacks.
Update the rel attribute on the Link element to include both "ugc" and "noopener
noreferrer" by combining them as a space-separated string in the rel prop.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d472015a-8722-4633-b038-6d09f9570714
📒 Files selected for processing (9)
front_end/src/app/(main)/accounts/profile/[id]/(overview)/page.tsxfront_end/src/app/(main)/accounts/profile/[id]/layout.tsxfront_end/src/app/(main)/accounts/profile/[id]/track-record/page.tsxfront_end/src/app/(main)/accounts/profile/components/profile_menu.tsxfront_end/src/app/(main)/accounts/profile/components/social_media_section.tsxfront_end/src/app/(main)/accounts/profile/components/user_info.tsxfront_end/src/services/api/profile/profile.shared.tsfront_end/src/types/projects.tsfront_end/src/types/users.ts
There was a problem hiding this comment.
🧹 Nitpick comments (1)
front_end/src/services/api/profile/profile.shared.ts (1)
27-30: ⚡ Quick winAlign
this.getgeneric with the overload contract.At Line 27,
this.get<UserProfileWithStats>(...)overstates the response shape whenincludeStatsis false. Use the union type here so implementation typing matches the overload behavior.Proposed change
- return await this.get<UserProfileWithStats>( + return await this.get<UserProfile | UserProfileWithStats>( `/users/${id}/${encodeQueryParams({ include_stats: includeStats })}`, fetchOptions );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@front_end/src/services/api/profile/profile.shared.ts` around lines 27 - 30, The generic type argument in the this.get call on line 27 is always set to UserProfileWithStats, but this overstates the response shape when includeStats is false. Change the generic type from UserProfileWithStats to a union type that accounts for both response shapes (UserProfile | UserProfileWithStats or similar union based on your overload contract) so the typing accurately reflects what the API actually returns based on the includeStats parameter value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@front_end/src/services/api/profile/profile.shared.ts`:
- Around line 27-30: The generic type argument in the this.get call on line 27
is always set to UserProfileWithStats, but this overstates the response shape
when includeStats is false. Change the generic type from UserProfileWithStats to
a union type that accounts for both response shapes (UserProfile |
UserProfileWithStats or similar union based on your overload contract) so the
typing accurately reflects what the API actually returns based on the
includeStats parameter value.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bfb4f5d6-6b2c-4f67-804c-2d578f4014b0
📒 Files selected for processing (3)
front_end/src/app/(main)/accounts/profile/[id]/layout.tsxfront_end/src/app/(main)/accounts/profile/components/social_media_section.tsxfront_end/src/services/api/profile/profile.shared.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- front_end/src/app/(main)/accounts/profile/components/social_media_section.tsx
Summary
Next.js 16 changed RSC prefetching behavior: it calls
generateMetadata()for every visible<Link>on a page during server-side rendering, causing an N+1 request pattern on the main feed – 12–20 individual/api/posts/{id}/requests to Django on every page load.Two complementary fixes were applied to eliminate this N+1:
with_cp=false+revalidate: 60) used bygenerateMetadataacross question, tournament, and community pages, so repeated prefetch triggers within 60s are served from Next.js server-side cache without hitting Djangoprefetch={false}to all<Link>components visible in feeds and post cards to prevent Next.js from triggering RSC prefetch for every visible link in the viewportNote:
KeyFactorsTileViewwas investigated as a source of additionalwith_cp=truerequests – these are legitimate client-side fetches to render the "% chance" label when CP data is absent from the coherence links response, not part of the N+1 patternSummary by CodeRabbit
New Features
Chores
prefetchbehavior, with small related rendering/timestamp cleanups.