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

8.2 KiB

资产创建跳转与路由回归收尾

Goal

在合同详情迁移开始前,关闭 08-05-business-detail-routing 中已被真实 API 回归证伪的资产创建验收项:资产创建成功后必须直接进入 canonical 详情路由,且不能被“未保存修改”保护误拦截。同时修正采购主链路中已过时的英文姓名断言,并以追加 delta 的方式纠正两个归档任务对失败性质的记录。

本任务只处理 1 条确认的产品回归和 1 条确认的测试断言漂移;其余 8 条 mock 会话/登录态失败保持独立候选,不在本轮扩张。

Confirmed Facts

  • 归档任务 .trellis/tasks/archive/2026-08/08-05-business-detail-routing/prd.md:46 将“资产创建成功后 URL 变为 /assets/:assetId,返回不会回到已提交表单”保留为 PAUSED,原因仅是当时本地数据库缺列,未完成真实创建验证。
  • 迁移基线恢复后,assets-flow.spec.ts 的真实 POST /api/assets 已成功返回实体 ID,但页面 30 秒后仍停留 /assets/new;归档迁移任务已在 implement.md:57 记录该结果。
  • 当前本地 Playwright 失败 DOM 快照明确出现“放弃未保存的修改?”对话框;这证明直接阻塞跳转的是共享未保存保护,而不是 API 响应形状。
  • 后端 server/src/routes/assets.js:1329 返回 { asset },前端 client/src/api/assets.ts:307-311 同样声明 { asset: AssetItem };data.asset.id 可用,响应形状不是根因。
  • client/src/pages/AssetRegistryPage.tsx:577-590 在成功回调中先更新 saved signature,再于同一回调内 navigate(...)。React 状态尚未完成提交时,共享 guard 仍持有 dirty=true,因此程序化成功跳转被当作离开未保存表单而拦截。
  • client/src/components/common/UnsavedChangesGuard.tsx:31-50 已有同步 allowNextNavigationRef,但目前只在用户确认“放弃并离开”时使用,没有“服务端已保存成功后安全跳转”的受控入口。
  • client/tests/e2e/procurement-flow.spec.ts:91-93 已先验证“申请人”,随后仍断言英文 Employee;真实页面展示中文申请人姓名,符合 docs/产品设计规则.md:23,118 的自然中文规则。
  • r103-cross-page-ui-consistency.spec.ts 的 7 条失败与 global-search.spec.ts 的 1 条失败均伴随登录态回落,属于另一个会话/mock 夹具问题集合。

Scope

  • 修复资产创建成功后的程序化跳转,使其绕过仅针对未保存数据的离开确认,并继续使用 replace 与安全 state.from。
  • 让创建成功后的 canonical 跳转成为用户可见关键路径;缓存失效不得先于或阻塞该跳转。
  • 保持普通脏表单的链接、返回、刷新、记录切换和显式返回保护行为不变。
  • 将采购主链路的英文 Employee 断言改为 fixture 中的自然中文申请人姓名。
  • 为 08-05-business-detail-routing 与 08-07-local-database-migration-readiness 的归档材料追加 post-archive delta:资产失败是确认的产品回归,其余 9 条为测试断言或 mock 会话候选;不覆盖原始历史记录。
  • 在现有前端 spec 中补充“成功持久化后的程序化导航不得依赖异步 dirty state 清理”的共享约束。

Requirements

  • R1:资产创建 mutation 只有在 POST 成功并取得实体 ID 后,才可使用共享的 post-save 导航入口绕过未保存拦截;失败、超时或返回无 ID 时不得绕过。
  • R2:创建成功必须 replace 到 buildAssetDetailPath(data.asset.id),保留经校验的 backSource;浏览器返回不得重新打开已提交的 /assets/new。
  • R3:创建成功后的 URL 跳转先于等待列表/详情缓存失效。缓存刷新可在后台继续,但失败不能撤销已成功创建的业务结果,也不能把用户留在创建表单。
  • R4:共享 guard 的新入口必须语义收窄为“成功保存后导航”,复用现有同步 allow-next 机制;不得提供无条件全局关闭 guard 的开关。
  • R5:正常脏表单行为保持不变:未保存时离开仍显示一次确认;继续编辑保留 URL 与输入;放弃后只执行一次目标动作;刷新仍触发浏览器保护。
  • R6:创建请求失败时仍停留 /assets/new,保留输入并展示自然中文错误;不得误清 dirty state 或跳到详情。
  • R7:采购主链路断言使用 EMPLOYEE.name 等 fixture 事实,不硬编码英文角色词,也不降低对“申请人”字段存在和正确对象姓名的验证强度。
  • R8:真实 assets-flow.spec.ts 与 procurement-flow.spec.ts 必须补跑并形成明确结果;真实流产生的 Playwright 合成数据不在本任务清理、seed 或 reset。
  • R9:归档证据只追加复核 delta,保留原 PAUSED 与发现时间线;不得把当时未验证的 AC 倒写成历史已通过。
  • R10:其余 8 条登录态/mock 会话失败对应的用例不做修复,不改登录实现、不顺手增加 service-worker 或会话 fixture 修复;本轮仅扩充资产未保存保护的独立聚焦回归,另行评估那 8 条失败。
  • R11:不修改后端 API、Prisma schema/migration、权限模型、路由 guard、资产数据范围、合同 task 或生产配置。

Acceptance Criteria

  • 真实 API 创建资产成功后,页面直接进入 /assets/:assetId,不出现“放弃未保存的修改?”对话框(真实 assets-flow 通过)。
  • 成功跳转使用 replace 并保留安全列表来源;浏览器返回不会回到已提交的 /assets/new(真实资产链路后退/前进通过)。
  • 创建成功的导航不等待列表/详情缓存失效完成;缓存刷新异常不会阻止 canonical 跳转(代码顺序与后台 catch 复核通过)。
  • 创建失败仍保留表单、dirty protection 与自然中文错误,不发生 post-save bypass(聚焦 mock 400 回归通过)。
  • 资产未保存取消/放弃回归继续通过,证明共享 guard 的普通保护未被削弱(聚焦 mock 回归通过)。
  • assets-flow.spec.ts 真实主链路通过,覆盖创建跳转、返回/前进与后续资产流转(1 passed / 0 failed / 0 skipped)。
  • procurement-flow.spec.ts 不再断言 Employee,而是验证“申请人”与 fixture 中文姓名;完整主链路通过(1 passed / 0 failed / 0 skipped)。
  • 两个归档任务均有 append-only post-archive delta,明确 1 条产品回归与 9 条测试侧问题的不同归属及本任务引用。
  • 现有前端 spec 明确成功持久化导航的 bypass 契约、失败边界和回归要求。
  • cd client && npm run typecheck && npm run build、聚焦 Playwright、任务校验、Trellis governance 与 git diff --check 通过。

Out of Scope

  • 修复 r103-cross-page-ui-consistency.spec.ts 的其余 7 条登录态失败或 global-search.spec.ts 的 1 条登录态失败。
  • 重构全部 React Query mutation、统一全站缓存策略或调整所有成功 toast 时序。
  • 修改采购或资产 API payload、后端业务逻辑、数据库、权限、导航 schema、移动端路由或生产配置。
  • 启动 08-05-contract-detail-workspace 或执行任何合同 migration。
  • seed、reset、批量删除或手工清理本地 Playwright 合成数据。
  • 部署、公网检查、企业微信真机或线上可测试声明。

Test Plan

  1. 静态与构建:
    • cd client && npm run typecheck
    • cd client && npm run build
  2. 共享 guard 与路由聚焦回归:
    • cd client && npx playwright test tests/e2e/business-detail-routing.spec.ts --workers=1 --reporter=list
    • cd client && npx playwright test tests/e2e/r103-cross-page-ui-consistency.spec.ts --grep "资产长表单切回记录列表" --workers=1 --reporter=list
  3. 当前回环本地服务上补跑真实主链路:
    • cd client && E2E_MODE=local E2E_BASE_URL=http://127.0.0.1:3000 npx playwright test tests/e2e/assets-flow.spec.ts tests/e2e/procurement-flow.spec.ts --workers=1 --reporter=list
  4. 记录真实 passed/failed/skipped 数量;若出现范围外新失败,只分类和留证,不顺手扩大修复。
  5. 流程门禁:
    • python3 ./.trellis/scripts/task.py validate 08-07-business-routing-regression-repair
    • node scripts/qa/check-trellis-governance.mjs --json
    • git diff --check