文件
hyb-oa/.trellis/tasks/archive/2026-08/08-07-business-routing-regression-repair/design.md
T

3.9 KiB

设计说明

1. 问题与根因

真实创建链路的状态序列为:

资产表单 dirty=true
  -> POST /api/assets 成功并返回 asset.id
  -> setSavedAssetFormSignature(...)
  -> 同一回调内 navigate(/assets/:id)
  -> React 尚未提交 saved signature,UnsavedChangesProvider 仍认为 dirty=true
  -> useBlocker 拦截导航并打开“放弃未保存的修改?”
  -> URL 留在 /assets/new

Playwright 失败 DOM 已出现该确认对话框,因此 await invalidateQueries(...) 可能放大跳转延迟,但不是直接拦截原因。修复必须处理共享 guard 的同步状态边界,不能只交换两个 await 的顺序后碰运气。

2. 设计选择

2.1 共享 post-save 导航入口

在 UnsavedChangesProvider 内复用现有 allowNextNavigationRef,增加语义收窄的同步入口,例如:

runAfterSuccessfulSave(action: () => void): void

并通过专用 hook(例如 usePostSaveNavigation)暴露。入口执行时:

  1. 同步设置 allowNextNavigationRef.current = true;
  2. 执行一次传入的导航动作;
  3. 在 microtask 中恢复为 false;
  4. 不修改、清空或伪造其他表单的 dirty registration。

这个入口只用于服务端已经确认持久化成功后的程序化导航。普通离开继续使用 runGuarded;失败路径不调用该入口。

2.2 资产创建成功顺序

创建分支按以下顺序处理:

清空表单错误 / 记录已保存签名 / 成功反馈
  -> runAfterSuccessfulSave(() => navigate(canonicalDetail, replace + from))
  -> 后台 invalidate asset list/detail caches

编辑既有资产不发生路由切换,可继续等待其详情/列表缓存刷新。本任务不重构其他 mutation。

关键不变量:

  • canonical 导航是成功创建后的用户可见主结果,不能依赖缓存刷新成功。
  • replace 保证历史栈不保留已提交创建页。
  • post-save bypass 只开放一个 navigation window,不能永久关闭 guard。
  • API 失败仍由 mutation onError 处理,表单与 dirty state 保持。

2.3 测试断言

  • assets-flow.spec.ts 继续使用真实 API,验证 POST 成功后 URL、无 unsaved dialog、返回/前进和后续流转。
  • 聚焦运行既有“资产长表单切回记录列表”用例,证明取消/放弃保护未退化。
  • procurement-flow.spec.ts 同时断言“申请人”字段和 EMPLOYEE.name,不再依赖英文角色词。
  • business-detail-routing.spec.ts 保持 canonical path、replace 来源与移动回落的纯契约覆盖。

3. 证据更新

归档材料按 append-only delta 更新:

  • 08-05-business-detail-routing:保留原 AC 的 PAUSED 历史,在文末追加 2026-08-07 真实回归 delta,标明该 AC 当前为失败并由本任务修复。
  • 08-07-local-database-migration-readiness:保留原 16/10/0 记录,追加分类修正:资产跳转是产品回归;采购英文断言及 8 条登录态/mock 失败属于测试侧。

不回写“当时已通过”,不删除原始发现与时间线。

4. 兼容与风险

  • 共享 guard 入口若命名过宽,可能被误用于绕过真实未保存保护;因此 API 必须带 post-save 语义,并在 spec 中限定调用条件。
  • 导航先于缓存失效可能让详情页短暂进入正常加载态,但不会丢失创建结果;当前详情路由已有独立实体查询。
  • 真实资产/采购 E2E 会写入带 Playwright 标记的本地合成记录;不清理,避免误删开发数据。
  • 本任务不碰权限、状态机、API 或数据库,因此不需要 migration/permission reviewer;仍需 trellis-check 做共享组件与跨页面一致性复核。

5. 回滚

  • 代码回滚:撤回共享 post-save 入口及资产页调用,恢复原 mutation 时序。
  • 测试回滚:恢复对应断言,但不得把已证伪的资产 AC 改写为通过。
  • 证据 delta 为历史事实,不随代码回滚删除;若修复回滚,应追加新的状态说明。