mirror of
https://github.com/multica-ai/multica.git
synced 2026-09-28 13:23:48 +08:00
* feat(server): add a change log and sync endpoints for local search (MUL-7754) Web and Desktop will keep a per-workspace copy of issue, comment, and project text for instant search. Triggers on issue/comment/project record the xid of each entity's latest write in search_index_change, covering every write path including hard and cascaded deletes. Clients bootstrap with GET /api/search-index/manifest + /snapshot pages and catch up with POST /api/search-index/changes, whose cursor is a pg_snapshot: a change is returned once it is visible in the target snapshot but not in the one the client holds, so late commits are never skipped and long transactions do not stall catch-up. Workspace teardown skips the triggers and clears the table, and an hourly scheduler job prunes rows older than 30 days; a cursor older than the prune mark gets 410 and rebuilds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * feat(core): add a synced local search index for web and desktop (MUL-7754) Each (user, workspace) gets an IndexedDB copy of its issue, comment, and project text, kept in a worker (SharedWorker when available, otherwise a dedicated worker per tab) and searched in memory. Matching, ranking, and snippets port the server's issue/project search, so local rows have the server's shape and order. The worker bootstraps from /api/search-index/manifest + snapshot pages, catches up through /changes after realtime events, reconnects, focus, and every five minutes, and resumes an interrupted bootstrap. It has no credentials of its own: tabs run its requests through their API client. Local results are served only while the copy is complete and recently confirmed; otherwise searchIssues/searchProjects fall back to the server. Workspaces over 500 MB of text, lost access, and expired cursors are handled by declining, wiping, and rebuilding respectively. Session cleanup deletes every local index. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * feat(views): search through the local index first (MUL-7754) The command palette, @mention suggestions, the issue picker, and duplicate suggestions now call the core local-first search. The palette drops its 300 ms debounce while the local index is serving, since no request leaves the tab. An E2E spec checks that palette results match server ranking without any server search request, follow issues created and deleted through the API, and that logging out deletes the local copy. .env.example documents the FF_LOCAL_SEARCH_INDEX kill switch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * fix(core): close local search gaps found in review (MUL-7754) - Access loss: deleting, leaving, or being removed from a workspace now destroys its local copies right away (worker and tab both delete the database, since a full-page relocate may end the worker first). The sync hook also prunes every copy outside the user's current workspace list, which covers access lost while offline or on another device; copies a tab is showing are kept in case the list is stale. - Memory budget: the engine counts UTF-8 bytes the way the manifest does, and the budget is checked on every load, snapshot page, and catch-up batch, not only at bootstrap. An over-budget copy is dropped and search falls back to the server until the workspace is measured again. - Frozen tabs: a port the sweep dropped is restored with its workspace the next time the tab sends anything, a page restored from the bfcache attaches again, and a null local answer clears the tab's "serving" flag so the palette goes back to debounced server search. E2E now also covers being removed from a shared workspace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai>