The sidebar page tree only updated on other clients when a change was made via the UI tree, in an open tab, within a ~50ms client relay window — API/MCP/ AI/import changes never propagated. Move the source of truth to the server. Server: - Enrich PageEvent with thin TreeNodeSnapshot(s) so the WS listener never reads the DB (avoids the in-transaction visibility race). insertPage fills the create snapshot from its returning() row; removePage ships only the deleted subtree ROOT (client treeModel.remove drops descendants); restorePage carries spaceId. - New PAGE_MOVED event from movePage with old/new parent + position + snapshot (generic PAGE_UPDATED stays for content/rename). - WsService.emitTreeEvent mirrors emitCommentEvent (per-space restriction gate: spaceHasRestrictions -> hasRestrictedAncestor -> broadcastToAuthorizedUsers); author NOT excluded so non-UI creators see their own page (receiver is idempotent). - WsTreeService.broadcastPageCreated/Deleted/Moved + broadcastRefetchRoot; new PageWsListener (create/delete/move/restore) registered in WsModule. Client: - Remove the client relay (emit + setTimeout(50)) from create/move/delete; keep optimistic local updates. Make the optimistic create insert id-idempotent (find-then-skip) so the now-fast server addTreeNode broadcast can't race it into a duplicate row. addTreeNode inserts by fractional position among loaded siblings (consistent order across clients). Restore uses refetchRootTreeNodeEvent (robust for subtree re-attach). Rename/icon updateOne and cross-space move realtime are deferred (commented as follow-ups). Implements docs/backlog/realtime-tree-server-authoritative.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
15 lines
497 B
TypeScript
15 lines
497 B
TypeScript
import { Global, Module } from '@nestjs/common';
|
|
import { WsGateway } from './ws.gateway';
|
|
import { WsService } from './ws.service';
|
|
import { WsTreeService } from './ws-tree.service';
|
|
import { PageWsListener } from './listeners/page-ws.listener';
|
|
import { TokenModule } from '../core/auth/token.module';
|
|
|
|
@Global()
|
|
@Module({
|
|
imports: [TokenModule],
|
|
providers: [WsGateway, WsService, WsTreeService, PageWsListener],
|
|
exports: [WsGateway, WsService, WsTreeService],
|
|
})
|
|
export class WsModule {}
|