Skip to content

perf(board): load pages incrementally and patch live changes - #1879

Merged
tinsever merged 72 commits into
fix/review-08-filtered-dragfrom
fix/review-11-incremental-board
Sep 30, 2026
Merged

tinsever merged 72 commits into
fix/review-08-filtered-dragfrom
fix/review-11-incremental-board

Conversation

@tinsever

@tinsever tinsever commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

what changed?

board pagination waited for every page and kept reloading the whole board for polling and small realtime changes. show pages as they arrive, fetch bounded task changes, and guard cache patches against newer edits or reorders. keep broad refreshes for events that need them.

finding 11 from the codebase review.

based on #1878 (finding 08). merge that pr first; this diff contains only finding 11.

how did you check it?

incremental page loading, public boards, websocket cache races, local edit guards and pagination lifecycle tests.

checked the combined fix tree with the full workspace test run, uncached workspace typechecks, lint, i18n and openapi checks. postgres integration tests used disposable local test databases; provider and s3 calls were mocked.

Native GitHub stack #1886 (bottom to top): #1873 → #1876 → #1877 → #1878 → #1879 (this PR). Stack base: fix/review-06-integration-scope, the shared #1867 foundation. Merge #1867 first, then move this stack's base to main before merging board changes. If GitHub has not moved it automatically, unstack the still-open board PRs, retarget #1873 to main, and recreate this native stack in the same order.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-30T11:21:37.274446Z 4e674b8 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Mixed activity

Activity patterns show a mix of organic and automated signals.

View full analysis →

This is an automated analysis by AgentScan

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Load board pages incrementally and patch live task changes

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Show authenticated and public board pages as they arrive instead of waiting for the full load.
• Patch individual task changes in the cache, reserving board refreshes for broader events and
 realtime outages.
• Guard against stale patches during pagination, local edits, and reorders; add lifecycle and race
 tests.
Diagram

graph TD
  API["Board API"] --> Loader["Page loader"] --> Cache[("Query cache")] --> UI["Board UI"]
  Socket["WebSocket events"] --> TaskAPI["Task endpoints"] --> Patcher["Guarded patcher"] --> Cache
  Edits["Local edits"] --> Patcher
  Socket --> Patcher
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep invalidating the whole board
  • ➕ Simpler cache consistency model
  • ➕ Less event-specific patching logic
  • ➖ Retains full-board requests for small changes
  • ➖ Can interrupt or repeat lengthy pagination
2. Adopt an infinite-query board model
  • ➕ Makes page boundaries and incremental fetching explicit
  • ➕ Uses established paginated-query behavior
  • ➖ Requires changing existing board consumers and cache shape
  • ➖ Does not eliminate the need to reconcile realtime edits

Recommendation: Keep the PR's progressive snapshots and bounded patches: they improve responsiveness without replacing the existing board cache contract. The simpler invalidation approach forfeits the performance goal, while an infinite-query migration has substantially broader scope. Review the loading and version guards closely because they carry the consistency risk.

Files changed (20) +671 / -59

Enhancement (14) +393 / -57
index.tsxProtect drag reorders during board fetches +9/-1

Protect drag reorders during board fetches

• Prevents reordering while the board query is fetching. Marks moved tasks as changed before updating the cache so older asynchronous patches cannot overwrite the reorder.

apps/web/src/components/kanban-board/index.tsx

get-public-project.tsExpose public-board loading progress +22/-16

Expose public-board loading progress

• Accepts an optional progress callback and forwards it to the shared paginated board loader.

apps/web/src/fetchers/project/get-public-project.ts

get-tasks.tsExpose authenticated-board loading progress +25/-16

Expose authenticated-board loading progress

• Accepts an optional progress callback for task-board requests and forwards it to the shared loader.

apps/web/src/fetchers/task/get-tasks.ts

load-board-pages.tsPublish board snapshots as pages arrive +12/-1

Publish board snapshots as pages arrive

• Reports cloned, column-sorted board snapshots after the first page and each merged continuation or related-data page. Retains the fully merged board as the final result.

apps/web/src/fetchers/task/load-board-pages.ts

use-update-task-description.tsPatch descriptions after successful edits +4/-3

Patch descriptions after successful edits

• Replaces board-wide invalidation with a bounded description update from the mutation response. Retains task-detail and notification invalidations.

apps/web/src/hooks/mutations/task/use-update-task-description.ts

use-update-task-due-date.tsPatch due dates after successful edits +4/-3

Patch due dates after successful edits

• Updates the cached board task's due date from the mutation response instead of refetching the board. Retains other existing invalidations.

apps/web/src/hooks/mutations/task/use-update-task-due-date.ts

use-update-task-status-priority.tsPatch priorities after successful edits +4/-3

Patch priorities after successful edits

• Updates the cached board task's priority from the mutation response instead of invalidating the entire board.

apps/web/src/hooks/mutations/task/use-update-task-status-priority.ts

use-update-task-title.tsPatch titles after successful edits +4/-3

Patch titles after successful edits

• Updates the cached board task's title from the mutation response instead of refetching the board.

apps/web/src/hooks/mutations/task/use-update-task-title.ts

use-get-public-project.tsDisplay public-board pages progressively +9/-2

Display public-board pages progressively

• Writes progress snapshots into an initially empty public-project query cache. Existing cached boards remain visible until their refresh completes.

apps/web/src/hooks/queries/project/use-get-public-project.ts

use-get-tasks.tsPublish initial task pages and remove routine polling +12/-5

Publish initial task pages and remove routine polling

• Writes progressive snapshots when the board cache is initially empty and marks new fetches in the cache-version guard. Replaces fixed 30-second query polling with focus refetching; WebSocket handling supplies outage fallback polling.

apps/web/src/hooks/queries/task/use-get-tasks.ts

use-project-websocket.tsApply bounded realtime updates with race guards +181/-4

Apply bounded realtime updates with race guards

• Fetches and patches changed tasks, applies deletes and reorders locally, and defers events while pagination is active. Uses task and board versions to reject stale responses, retains broad invalidation for project-level changes, and polls only after reconnect attempts are exhausted.

apps/web/src/hooks/use-project-websocket.ts

board-cache-version.tsTrack board and task cache generations +21/-0

Track board and task cache generations

• Adds query-client-scoped version counters for project-wide and task-specific changes. Asynchronous patches can compare generations before writing to the cache.

apps/web/src/lib/board-cache-version.ts

patch-board-task.tsPatch a task without replacing board metadata +46/-0

Patch a task without replacing board metadata

• Adds an immutable board update that preserves existing task fields while placing the task in its status collection. It can also remove deleted or out-of-project tasks and sort the destination by position.

apps/web/src/lib/patch-board-task.ts

update-board-task-cache.tsDefer local patches until board loading completes +40/-0

Defer local patches until board loading completes

• Applies field-level mutation results to the board cache, waiting for an active fetch to finish when necessary. Version checks prevent older queued edits from replacing newer changes.

apps/web/src/lib/update-board-task-cache.ts

Tests (6) +278 / -2
load-board-pages.test.tsTest early, immutable page snapshots +26/-0

Test early, immutable page snapshots

• Verifies that the first page is published before a slow continuation and that subsequent pages do not mutate earlier snapshots.

apps/web/src/fetchers/task/load-board-pages.test.ts

use-get-tasks.test.tsxExpect the public-board progress callback +1/-0

Expect the public-board progress callback

• Adjusts the fetcher call assertion to account for the new progress callback.

apps/web/src/hooks/queries/task/use-get-tasks.test.tsx

use-project-websocket-cache.test.tsxTest realtime cache races and deferred events +151/-0

Test realtime cache races and deferred events

• Covers stale task responses after reorders or broad refreshes, coalescing task events during pagination, and invalidation when an event lacks a task ID.

apps/web/src/hooks/use-project-websocket-cache.test.tsx

use-project-websocket-lifecycle.test.tsxExtend lifecycle query-client mocks +8/-1

Extend lifecycle query-client mocks

• Adds cache subscription, query-state, cancellation, and data methods needed by the WebSocket hook's new cache behavior.

apps/web/src/hooks/use-project-websocket-lifecycle.test.tsx

use-project-websocket.test.tsExtend WebSocket query-client mocks +8/-1

Extend WebSocket query-client mocks

• Provides query-state and cache-subscription mocks for the hook's event deferral and refresh paths.

apps/web/src/hooks/use-project-websocket.test.ts

patch-board-task.test.tsTest bounded patches and local-edit ordering +84/-0

Test bounded patches and local-edit ordering

• Checks preservation of board-only metadata, application of the latest edit after an in-flight load, movement between columns, and removal of tasks moved out of the project.

apps/web/src/lib/patch-board-task.test.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 95478d8138

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/web/src/hooks/use-project-websocket.ts Outdated
Comment thread apps/web/src/hooks/queries/task/use-get-tasks.ts Outdated
Comment thread apps/web/src/hooks/use-project-websocket.ts Outdated
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Some live task changes disappear ✓ Resolved
Description
pendingMessages keys different event types by the same taskId, allowing later comment or task
updates to replace queued events with different cache effects while board pagination is running.
When loading finishes, replaying only the retained event can leave an already-loaded task's board
fields unchanged or skip a relation event's cache invalidation and board-wide refresh.
Code

apps/web/src/hooks/use-project-websocket.ts[R114-115]

+            } else
+              pendingMessages.set(message.taskId || message.type, event.data);
Evidence
Task and comment events both carry a task ID, and the pending map retains only the last message for
that key; replaying a comment event does not refresh the board task. The server also emits relation
and ordinary task events separately for the same task, but only the relation-event handler
invalidates relation caches, so a later task event can prevent that invalidation from running.

Grey Divider

Tip of the day
💡 Did you know, you can route each severity your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread apps/web/src/hooks/use-project-websocket.ts Outdated
Comment thread apps/web/src/hooks/use-project-websocket.ts Outdated
Comment thread apps/web/src/hooks/queries/task/use-get-tasks.ts Outdated
Comment thread apps/web/src/hooks/use-project-websocket.ts
Comment thread apps/web/src/hooks/mutations/task/use-update-task-description.ts Outdated
Comment thread apps/web/src/lib/patch-board-task.ts Outdated
Comment thread apps/web/src/hooks/use-project-websocket.ts Outdated
Comment thread apps/web/src/lib/update-board-task-cache.ts Outdated
Comment thread apps/web/src/hooks/queries/task/use-get-tasks.ts
@tinsever

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd614c1e92

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/web/src/lib/update-board-task-cache.ts
Comment thread apps/web/src/hooks/use-project-websocket.ts
Comment thread apps/web/src/hooks/use-project-websocket.ts
@tinsever

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8e776680e1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/web/src/hooks/use-project-websocket.ts
Comment thread apps/web/src/hooks/queries/project/use-get-public-project.ts
@tinsever

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 95d9006ce0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/web/src/hooks/queries/task/use-get-tasks.ts
Comment thread apps/web/src/hooks/use-project-websocket.ts Outdated
@tinsever

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: 4e674b8213

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@tinsever
tinsever removed this pull request from stack #1886 September 30, 2026 16:59
@tinsever
tinsever added this pull request to stack #1888 September 30, 2026 16:59
@tinsever
tinsever merged commit e25f53a into main Sep 30, 2026
22 checks passed
@tinsever
tinsever deleted the fix/review-11-incremental-board branch September 30, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant