MemoFlow · Goal 数据同步开发笔记
按版本记录 Goal Store 初始化、聚合刷新、同步通知和 Mutation Receipt。
Goal 数据同步目标
Goal 页面需要快速展示已有目标,也要在新增 KR、Record 或修改目标后立即显示正确数据。我希望尽量复用已加载的 Store,不必每次切换页面都重新请求全部数据。
但 Store 本身不能取代业务数据真值,需要明确谁负责持久化,谁负责让页面更新。
V1.0.0
现在使用 Store Persistence 插件保存一部分客户端状态,但初始化时发现持久化后的数据不完整。
第一步先检查:哪些字段确实经过序列化、初始化先后顺序是否正确、服务端返回数据与 Store 缓存有没有被混用。不能只因为启用了 Persistence 插件,就认为嵌套实体和全部引用关系都一定能正确恢复。
页面希望优先使用已经载入的数据,同时在初始化时补齐缺失部分。缓存只是为了提升体验,不能成为权威业务状态。
v1.1.0
另一个问题是子实体变化:修改了 KeyResult 或 GoalRecord,父级 Goal 聚合和其他页面不一定马上显示新进度。
当前可以先在成功保存后重新获取整个 Goal,再更新 Store,保证页面能看到服务端返回的最新值。这个办法简单,但每次改动都要重新加载较大的聚合,多个组件也可能反复刷新。
因此想继续把“哪次业务操作成功”与“哪几个视图应该刷新”分开。
V2.0.0
这版考虑用领域事件或应用层通知协调刷新:KR、Record 修改成功后,发出含 Goal ID 的变更消息,由 Sync Service 或 Store 订阅者更新相关视图。
优点是不会让每个组件各自猜测需要刷新哪里;但不能只靠一个内存事件就认为数据一定一致。事件丢失、重复消费、页面迟到订阅或请求乱序,都可能让客户端留下旧值。
事件负责“某个对象发生变化”的信号,持久化结果仍需要由真正拥有 Goal 数据的应用服务返回。
V3.0.0
现在把 Goal 的写入统一交给拥有 Goal/KR/Record/Review 的聚合边界。修改已有对象时携带 expectedVersion,服务端发现冲突就返回明确结果,不能静默覆盖。
成功变更返回权威的 GoalMutationReceipt,包含可以用于合并或失效缓存的信息。客户端按 Goal/KR/Record 的身份更新,而不是依赖旧对象引用碰巧触发 Vue 响应。
跨模块的 Task→Goal 贡献也一样:Task 只提交带来源和幂等身份的贡献意图,由 Goal 结算并生成 Record。这样刷新页面之前,首先能够确认真正成功提交的是哪一次业务变更。
这一版的重点从“强制刷新 Store”转到了用有版本的写入结果维护缓存与业务真值的一致性。