Skip to content

Feature/c1 optimization#1243

Open
priosshrsth wants to merge 64 commits into
mainfrom
feature/c1-optimization
Open

Feature/c1 optimization#1243
priosshrsth wants to merge 64 commits into
mainfrom
feature/c1-optimization

Conversation

@priosshrsth
Copy link
Copy Markdown
Collaborator

Changes

Feature branch for task app optimization (esp detail page)

priosshrsth and others added 30 commits May 6, 2026 15:02
Add a layout-level WorkspaceFetcher that uses SWR to populate
authDetails.workspace from /api/workspace on the client. SSR pages
((home), detail, client, manage-templates, manage-templates/[id]) no
longer block on copilot.getWorkspace() per request — they let the
Redux store hydrate from the cached client fetch (60s deduping).

Server-side route uses React cache() via getMemoizedWorkspace for
per-request memoization. Workspace consumers (Sidebar, AppBridges,
HeaderBreadcrumbs, TaskBoard) now read portalUrl from the store via
selectAuthDetails instead of taking it as a prop.

Add tsc script (tsc --noEmit) to package.json for type-only checks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…page

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restore the AssigneeCacheSetter side-effect that was nested inside the
deleted AssigneeFetcher. AssigneeCacheGetter still reads on cold load
per page; without a Setter, IDB never refreshed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* optimize parent tasks fetching

* feat: fetch workspace via SWR in layout instead of SSR per page

Add a layout-level WorkspaceFetcher that uses SWR to populate
authDetails.workspace from /api/workspace on the client. SSR pages
((home), detail, client, manage-templates, manage-templates/[id]) no
longer block on copilot.getWorkspace() per request — they let the
Redux store hydrate from the cached client fetch (60s deduping).

Server-side route uses React cache() via getMemoizedWorkspace for
per-request memoization. Workspace consumers (Sidebar, AppBridges,
HeaderBreadcrumbs, TaskBoard) now read portalUrl from the store via
selectAuthDetails instead of taking it as a prop.

Add tsc script (tsc --noEmit) to package.json for type-only checks.

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

* fix traversal

* remove perf.now code

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…it/out-3702-optimize-assignee-fetcher-to-be-once-per-session

# Conflicts:
#	src/app/layout.tsx
#	src/app/manage-templates/page.tsx
- replace module-level hasFetched flag with Redux-state guard (assignee.length === 0)
  so HMR / store resets trigger refetch correctly
- IDB write via setAssigneesIDB was already present
…s-app into anit/out-3702-optimize-assignee-fetcher-to-be-once-per-session
…s-app into anit/out-3702-optimize-assignee-fetcher-to-be-once-per-session
…s-app into anit/out-3702-optimize-assignee-fetcher-to-be-once-per-session
…s-app into anit/out-3702-optimize-assignee-fetcher-to-be-once-per-session
…s-app into anit/out-3702-optimize-assignee-fetcher-to-be-once-per-session
…s-app into anit/out-3702-optimize-assignee-fetcher-to-be-once-per-session
Per-request memoization deduplicates Copilot API calls within a single
RSC / route handler invocation. Validated in measurement: 4 call sites
of getInternalUser(self) collapsed to 1 actual network fetch on the
detail page.

Falls back to no-op outside a request context (CLI scripts, Trigger.dev
jobs) so unrelated code paths are unaffected. Cache key includes the
optional customApiKey so workspace-key-override calls don't collide.
priosshrsth and others added 15 commits May 12, 2026 10:23
Removing the unmount-time `setActiveTask(undefined)` closed one race but
risked other regressions on flows that depend on activeTask being cleared
when leaving the detail page. Restore the cleanup and instead add a
small idempotent effect that re-dispatches setActiveTask(task) whenever
the SSR `task` prop is defined but Redux `activeTask` has drifted away
(undefined or different id).

This covers both:
  - First-load races where Sidebar mounts before/around the CSU effect
    and Redux state hasn't been populated yet.
  - Fast Esc → click → repeat sequences where a stale cleanup from a
    previous unmount lands AFTER the new mount's dispatch.

Effect deps are just (task, activeTaskInStore), so the work is cheap and
the dispatch is idempotent — once they're in sync it no-ops.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(state): isolate activeTask/activeTemplate seeding (OUT-3714)
…s-app into anit/out-3701-detail-page-optimizations
…s-app into anit/out-3701-detail-page-optimizations
…s-app into anit/out-3701-detail-page-optimizations
…s-app into anit/out-3701-detail-page-optimizations
…ptimizations

perf(detail): cache + parallelize + skip redundant work in the detail page handler
@priosshrsth priosshrsth self-assigned this May 20, 2026
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 20, 2026

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

Project Deployment Actions Updated (UTC)
tasks-app Ready Ready Preview, Comment May 25, 2026 4:06am

Request Review

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 20, 2026

Greptile Summary

This PR optimises the detail page and reduces server-side latency by calling the service layer directly (bypassing HTTP round-trips), parallelising DB queries in TasksService.getOneTask, and moving workspace/assignee fetching to lightweight client-side SWR components in the root layout.

  • Detail page overhaul: authenticateWithToken + four parallel loaders replace six serial HTTP self-calls; WorkflowState is now included in the initial findFirst and parent-task traversal collapses N serial queries into one findMany.
  • Global client-side fetchers: WorkspaceFetcher and AssigneesFetcher (with retry) are placed in the root layout, allowing portalUrl and assignee data to be read from Redux everywhere without prop-drilling through server components.
  • State seeding refactor: SeedActiveTask / SeedActiveTemplate extract active-entity lifecycle from ClientSideStateUpdate, using a dual-effect pattern to handle React 18 concurrent-mode unmount races; React.cache() is added to getWorkspace and getInternalUser for per-request memoisation.

Confidence Score: 4/5

Safe to merge after fixing the VERCEL_BRANCH_URL priority in getAppUrl(); all other changes are clean optimisations.

The getAppUrl() refactor in src/config/index.ts now checks VERCEL_BRANCH_URL before VERCEL_URL. VERCEL_BRANCH_URL is a Vercel-managed branch alias that gets reassigned to newer deployments, so an in-flight SSR request on deployment A can route its internal API calls to deployment B after B goes live. The previous code used VERCEL_URL (unique per deployment) which avoids this cross-deployment version skew entirely. All other changes are well-structured and free of correctness issues.

src/config/index.ts — the new getAppUrl priority order.

Important Files Changed

Filename Overview
src/config/index.ts Refactored getAppUrl() now prioritises VERCEL_BRANCH_URL over VERCEL_URL, which can route internal API calls to a different deployment during rolling deployments and cause version skew.
src/app/detail/[task_id]/[user_type]/page.tsx Detail page now calls service layer directly via authenticateWithToken plus parallel loaders - clean optimisation with no issues found.
src/app/detail/[task_id]/[user_type]/loaders.ts New loader layer with typed error handling; NOT_FOUND is correctly caught and rethrown for other errors.
src/hoc/state-seeders.tsx New SeedActiveTask and SeedActiveTemplate components extract state seeding from ClientSideStateUpdate; dual-effect pattern correctly handles React 18 concurrent-mode races.
src/utils/CopilotAPI.ts getWorkspace and getInternalUser now use React.cache() for per-request memoisation; private methods called directly inside the cache to avoid recursion.
src/app/api/tasks/tasks.service.ts DB queries consolidated: workflowState included in initial findFirst; body update, subtask count, and assignee fetch run in a single Promise.all; parent traversal optimised from N serial queries to one findMany.
src/app/_fetchers/AssigneesFetcher.tsx Replaced SSR AssigneeFetcher with a client-side SWR component in the layout; errorRetryCount and errorRetryInterval address the previously flagged fetch-retry regression.
src/app/_fetchers/WorkspaceFetcher.tsx New client-side SWR component for workspace data; skips fetch when already in Redux store and when no token is present.
src/app/layout.tsx WorkspaceFetcher and AssigneesFetcher added globally in root layout inside Suspense boundaries; both guard on token presence.
src/hoc/ClientSideStateUpdate.tsx Removed task, accesibleTaskIds, and template props in favour of dedicated SeedActive* components; cleanup effects now live in the seeders.

Sequence Diagram

sequenceDiagram
    participant Browser
    participant DetailPage as DetailPage (Server)
    participant Loaders as loaders.ts
    participant DB as Database
    participant WF as WorkspaceFetcher (Client)
    participant AF as AssigneesFetcher (Client)
    participant Redux as Redux Store

    Browser->>DetailPage: Navigate to detail page

    DetailPage->>Loaders: authenticateWithToken
    Loaders-->>DetailPage: user

    par Parallel DB calls
        DetailPage->>Loaders: loadTask
        Loaders->>DB: findFirst + workflowState + assignee + subtask count
        DB-->>Loaders: task data
    and
        DetailPage->>Loaders: loadSubtaskStatus
        Loaders->>DB: getSubtaskStatus
        DB-->>Loaders: status
    and
        DetailPage->>Loaders: loadTaskPath
        Loaders->>DB: findMany parents
        DB-->>Loaders: ancestors
    and
        DetailPage->>Loaders: loadViewSettings
        Loaders->>DB: getViewSettings
        DB-->>Loaders: settings
    end

    DetailPage-->>Browser: HTML with SSR task data

    Browser->>WF: Mount
    WF->>Redux: dispatch setWorkspace

    Browser->>AF: Mount
    AF->>Redux: dispatch setAssigneeList
Loading

Reviews (2): Last reviewed commit: "thrown error when getting subtask count ..." | Re-trigger Greptile

Comment thread src/app/_fetchers/AssigneesFetcher.tsx
Comment thread src/app/detail/[task_id]/[user_type]/loaders.ts
Comment thread src/utils/copilotMemo.ts Outdated
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 20, 2026

Deployment failed with the following error:

Deploying Serverless Functions to multiple regions is restricted to the Pro and Enterprise plans.

Learn More: https://vercel.link/multiple-function-regions

@priosshrsth
Copy link
Copy Markdown
Collaborator Author

@greptileai review the pr again.

Comment thread src/config/index.ts
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