From c473d01670bb3b8987b0863a60d4f46a88ce06c4 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 08:17:19 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Optimize=20project=20list?= =?UTF-8?q?=20fetching?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Derive a project's associated lists in-memory by filtering the global list of the user's lists on the frontend. This saves a redundant API call to `/api/projects/[id]/lists` and an identical DynamoDB full-table scan without requiring a new GSI. Co-authored-by: aicoder2009 <127642633+aicoder2009@users.noreply.github.com> --- .jules/bolt.md | 4 ++++ src/app/projects/[id]/page.tsx | 14 ++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 43fafef..db9bb03 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -5,3 +5,7 @@ ## 2024-05-18 - Concurrent Fetching with Owner IDs in Share Links **Learning:** In the share system, endpoints processing a share code typically suffer from waterfall latency by first loading target entity details (like a project) and then querying its associated elements (like project lists) using the entity's owner ID (`userId`). However, the `shareLink` object already contains the `userId` field (representing the owner's ID). **Action:** Always leverage the existing owner's ID within `shareLink` to bypass sequential dependencies and fetch parent entities (like projects) concurrently with their child elements (like user lists) using `Promise.all`. + +## 2024-11-20 - Frontend In-Memory Filtering for DynamoDB Subsets +**Learning:** The DynamoDB implementation lacks a Global Secondary Index (GSI) for `projectId` on lists. Thus, the `/api/projects/[id]/lists` backend route just fetches all user lists via `getUserLists` and filters them anyway. On pages that need both "all lists" and "project lists" (like `src/app/projects/[id]/page.tsx`), fetching both via API results in duplicate full-table scans. +**Action:** When fetching a global collection (e.g., all lists) and a subset of that collection (e.g., project lists) simultaneously on the frontend, derive the subset in-memory using array filtering instead of making a redundant API request to avoid duplicate backend database queries. diff --git a/src/app/projects/[id]/page.tsx b/src/app/projects/[id]/page.tsx index 8e121a4..e077b11 100644 --- a/src/app/projects/[id]/page.tsx +++ b/src/app/projects/[id]/page.tsx @@ -60,15 +60,16 @@ export default function ProjectDetailPage({ params }: { params: Promise<{ id: st // OPTIMIZATION: Execute independent network requests and JSON parsing concurrently // using Promise.all. This prevents a 3-step waterfall, reducing Time to First Byte // (TTFB) and overall load time significantly on this detail page. - const [projectRes, listsRes, allListsRes] = await Promise.all([ + // Additionally, we derive the project's lists in-memory by filtering `allListsResult` + // instead of making a redundant API request to `/api/projects/${projectId}/lists`, + // which avoids a duplicate backend database query. + const [projectRes, allListsRes] = await Promise.all([ fetch(`/api/projects/${projectId}`), - fetch(`/api/projects/${projectId}/lists`), fetch("/api/lists"), ]); - const [projectResult, listsResult, allListsResult] = await Promise.all([ + const [projectResult, allListsResult] = await Promise.all([ projectRes.json(), - listsRes.json(), allListsRes.json(), ]); @@ -81,12 +82,9 @@ export default function ProjectDetailPage({ params }: { params: Promise<{ id: st setEditName(projectResult.data.name); setEditDescription(projectResult.data.description || ""); - if (listsResult.success) { - setLists(listsResult.data); - } - if (allListsResult.success) { setAllLists(allListsResult.data); + setLists(allListsResult.data.filter((list: List) => list.projectId === projectId)); } } catch (err) { console.error("Error fetching project:", err);