Skip to content

OUT-3545: parallelize home render and batch Copilot price fetch#240

Merged
SandipBajracharya merged 3 commits intomasterfrom
OUT-3545
May 6, 2026
Merged

OUT-3545: parallelize home render and batch Copilot price fetch#240
SandipBajracharya merged 3 commits intomasterfrom
OUT-3545

Conversation

@SandipBajracharya
Copy link
Copy Markdown
Collaborator

@SandipBajracharya SandipBajracharya commented May 5, 2026

Summary

  • Parallelize portal connection check, workspace info fetch, and latest sync log lookup on the home server component (src/app/(home)/Home.tsx); replace internal API round-trip with direct SyncLogService call.
  • Batch Copilot price fetching in ProductService.getFlattenProductList — paginate /prices once and group by productId instead of N+1 calls per product (drops bottleneck).
  • Add a loading.tsx for the home segment and reuse it from dashboard/Main; drop the now-unused checkSyncStatus action (sync flag now read from the eagerly-loaded portal connection's setting).

Test plan

  • Load the home route signed in to a portal that has an active QBO connection — verify spinner renders during streaming, then dashboard hydrates with the correct sync flag, enabled state, and last-sync timestamp.
  • Load the home route signed in to a portal with no QBO connection — verify connect CTA renders and reconnect flow still triggers when ?type=... is passed.
  • Open the products page / any view that calls getFlattenProductList and confirm products with multiple prices still render every price row, sorted ascending by amount.
  • Confirm Copilot price pagination terminates: portal with >100 prices should still return all of them (paginate via nextToken).
  • yarn lint:check && yarn test clean.

🤖 Generated with Claude Code

Initial dashboard load was dominated by two waterfalls. (1) Home.tsx
awaited token validation, portal connection, sync status, latest sync
log (via HTTP self-call) and workspace info strictly in sequence. (2)
ProductService.getFlattenProductList fetched prices per-product through
a global Bottleneck (4 concurrent / 200ms), so N products meant N
throttled round-trips before SettingAccordion could mount.

Server render now runs checkPortalConnection, getWorkspaceInfo and
SyncLogService.getLatestSyncSuccessLog in parallel after token
validation; syncFlag/isEnabled are read from the eager-loaded
portalConnection.setting relation instead of a second DB round-trip;
the HTTP self-call to /api/quickbooks/syncLog/success is replaced by a
direct service call. Add (home)/loading.tsx for segment-level
streaming and share it from Main.tsx's client-side loading state.

Workspace-wide listPrices (paginated) replaces the per-product loop in
getFlattenProductList, dropping calls from 1+N to ~1+ceil(prices/page)
and removing the bottleneck dependency on this read path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 5, 2026

@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
quickbooks-sync Building Building May 6, 2026 10:50am
quickbooks-sync (dev) Ready Ready Preview, Comment May 6, 2026 10:50am

Request Review

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 5, 2026

Greptile Summary

  • Parallelizes three independent home-page fetches (portal connection, workspace info, latest sync log) and removes an extra HTTP round-trip by calling SyncLogService directly; syncFlag is now read from the eagerly-fetched portal connection setting, eliminating the separate checkSyncStatus action.
  • Replaces N+1 bottleneck-throttled per-product price calls with a single paginated sweep of /prices that groups results by productId, while getProducts is now fixed to a single page of up to 1000 products (pagination from callers is no longer supported — intentional trade-off for the single-page product UI).
  • Adds a Next.js streaming loading.tsx for the home segment and de-duplicates the spinner markup in dashboard/Main.

Confidence Score: 4/5

Safe to merge; the one open finding is a minor inefficiency with no correctness impact.

The prior P1 (uncaught sync-log DB error crashing the page) is fixed with .catch(). The remaining finding is P2: the sync-log DB query is issued unconditionally rather than being gated on portalConnectionStatus && syncFlag, wasting a query for connection-less portals. No correctness bugs were found in the price-batching logic or the home parallelization.

src/app/(home)/Home.tsx — unnecessary unconditional sync-log DB query; src/app/api/quickbooks/product/product.service.ts — acknowledged full-price-sweep trade-off documented in code comments.

Important Files Changed

Filename Overview
src/app/(home)/Home.tsx Parallelizes portal connection, workspace, and sync-log fetches; reads syncFlag directly from portal setting instead of a separate DB round-trip. getLatestSyncSuccessLog is now .catch-wrapped (fixes the prior P1) but is always fetched even when no portal connection exists.
src/app/api/quickbooks/product/product.service.ts Replaces N+1 per-product price fetches with a single paginated sweep of /prices grouped by productId. Products > 1000 are silently excluded (acknowledged trade-off); prices are fully paginated via do-while loop.
src/app/api/quickbooks/product/product.controller.ts Drops nextToken/limit query-param forwarding since getFlattenProductList is now a fixed single-page call. MAX_PRODUCT_LIST_LIMIT import remains valid for getItemsFromQB.
src/action/quickbooks.action.ts Removes the now-unused checkSyncStatus action; syncFlag is read directly from the eagerly-loaded portal connection setting in Home.tsx.
src/app/(home)/loading.tsx New Next.js streaming loading boundary for the home segment; reuses shared spinner component.
src/components/dashboard/Main.tsx Replaces the inline spinner markup with the shared Loading component; removes the now-duplicate Spinner import.

Sequence Diagram

sequenceDiagram
    participant Browser
    participant Home as Home.tsx (Server)
    participant DB as DB / token.service
    participant SyncLog as SyncLogService
    participant Copilot as CopilotAPI

    Browser->>Home: GET / (token, type)
    Home->>Home: getTokenPayload(token)
    par Parallel fetches
        Home->>DB: checkPortalConnection(workspaceId)
        Home->>DB: getWorkspaceInfo(token)
        Home->>SyncLog: getLatestSyncSuccessLog() [.catch → null]
    end
    DB-->>Home: portalConnection (with setting)
    DB-->>Home: workspace
    SyncLog-->>Home: latestSuccessLog | null
    alt portalConnectionStatus && !syncFlag
        Home->>Home: reconnectIfCta(type)
    end
    Home-->>Browser: AppProvider stream

    note over Browser,Copilot: Product flatten endpoint (separate request)
    Browser->>Copilot: GET /api/quickbooks/product/flatten
    par Parallel
        Copilot->>Copilot: getProducts(limit=1000)
        loop paginate all prices
            Copilot->>Copilot: getPrices(limit=1000, nextToken?)
        end
    end
    Copilot-->>Browser: { products: flattened[] }
Loading

Reviews (2): Last reviewed commit: "fix(OUT-3545): preserve home render on s..." | Re-trigger Greptile

Comment thread src/app/(home)/Home.tsx
Comment thread src/app/api/quickbooks/product/product.service.ts
…oduct pagination knobs

Home.tsx: catch errors from getLatestSyncSuccessLog inside Promise.all so a
transient DB failure nulls the timestamp instead of crashing the render
(matches the prior HTTP path's withErrorHandler swallowing).

Product flatten endpoint: remove the limit/nextToken query params (only
consumer is the SWR hook, which never passed them and the response DTO never
exposed nextToken). Service now hardcodes MAX_PRODUCT_LIST_LIMIT for the
single-page workload it actually serves, and the workspace-wide price walk
is documented.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@SandipBajracharya
Copy link
Copy Markdown
Collaborator Author

@greptileai review

@SandipBajracharya SandipBajracharya changed the title perf(OUT-3545): parallelize home render and batch Copilot price fetch OUT-3545: parallelize home render and batch Copilot price fetch May 5, 2026
Copy link
Copy Markdown
Collaborator

@priosshrsth priosshrsth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor optional suggestion. But the PR looks good to me and good one. This should help a lot. You are free to merge it as it is if you want.

Comment thread src/app/api/quickbooks/product/product.service.ts Outdated
@SandipBajracharya SandipBajracharya merged commit 209368c into master May 6, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants