5.5 KiB
5.5 KiB
实施清单:非参与人报销详情只读投影修复
1. 实施前门禁
- 用户已审查并明确批准本 PRD、设计和实施清单;运行
task.py start后再修改业务代码。 - 加载
trellis-before-dev,重读 frontend/backend/approval/reimbursement 规约和当前任务材料。 - 冻结工作区与基线;确认部署任务仍为 planning,未推送、未部署、未访问或写入生产。
2. 服务端对象资格
- 将报销头、删除、附件、明细和提交路由的
ensureApplicantOrAdmin收紧为 owner/submitter 参与人检查,保留原状态与权限码门禁。 - 为项目关联补
expense.edit_own,从expense.view_all可写收紧为 owner/submitter 可写,并增加draft/rejected状态门;不改变现有 feature flag 和 payload。 - 为 precheck 补 owner/submitter 或
expense.view_all对象级读守卫;普通非参与人 403 且 precheck 服务零调用,合法查看者保持成功。 - 将 reimbursement 发票 bind/unbind 分支从
isOwn || expense.view_all收紧为 owner/submitter;保持 travel order 分支不变。 - 统一 403 详情码并检查失败顺序,确保资格失败发生在数据、文件、审计、workflow 和通知副作用之前。
3. PC 与移动端动作投影
- 建立统一的参与人/可维护资格事实,PC 和移动端都使用“参与人 AND 状态”控制维护动作。
- PC 收紧主要动作、明细增改删、项目选择、票据添加/移除、附件上传/删除、提交、删除草稿、撤回和催办。
- 移动端收紧 sticky submit、明细增改删、票据添加/移除、附件上传/删除、删除草稿、撤回和催办。
- 保留 owner/submitter 既有动作、财务/审批专用流程、材料查看和打印。
4. 只读文案与信息
- 非参与人显示“只读查看”上下文,并把 draft/rejected 的下一步改为等待报销人处理的事实文案。
linkedItemId为空改为“关联明细:未关联”,无法解析改为“关联明细:无法识别”;移除“自动生成或匹配明细”。- 当前不可维护视角的 bound 发票显示“已关联”,不渲染“草稿或驳回状态可移除”;参与人可维护视角保留必要操作说明。
- 检查 PC/移动无禁用的伪操作、无内部权限码或实现术语,继续使用语义化按钮/链接和现有焦点/触控合同。
5. 回归测试
- 服务端合成矩阵按 S1/S2/S3 分档覆盖:admin、finance/
expense.view_all非参与人对 form/items/attachments/submit/project/invoice bind-unbind 的 403 与零副作用;approved/paid 项目关联为 409 且零写入。 - 服务端保留 owner/submitter 成功、GET/material preview 读取、workflow/finance pay 和 travel invoice 分支基线。
- Playwright 覆盖 PC/移动 nonparticipant draft 的无维护动作和文案,并保留 participant 主流程;rejected/reviewing 由相同资格投影与既有撤回/催办测试覆盖。
- 运行前端 typecheck/build、后端 node check/Prisma/聚焦测试及相关报销回归。
6. 复核、规约与提交
- 按
trellis-check复核跨层资格流,修复发现后重跑聚焦与全局门禁。 - 因涉及权限模型,实施完成后启动独立只读 review,不让 reviewer 修改代码;结论为 PASS,无权限阻断。
- 将“全量查看不等于对象维护、非参与人报销详情默认只读”的稳定合同更新到报销规约,避免再次 fail-open。
- 运行 task validate、process contract、Trellis governance、敏感检查和
git diff --check。 - 用户批准提交后,使用中文并引用
08-28-reimbursement-nonparticipant-readonly-projection;业务提交为e8d6766,未推送、未部署、未归档。 - 提交完成后更新部署子任务候选依赖;完整 PRD 已明确固定回滚、迁移状态和公网角色检查,继续等待用户审查部署方案。
7. 实施发现与验证记录
link-project原实现调用未定义的parseBody,feature flag 打开后会在写入前返回 500,因此其错误的expense.view_all写授权历史上不可实际利用。本轮在同一路由范围内改为专用 Zod 解析函数,测试覆盖 draft 参与人 200、非参与人 403、approved/paid 409。- r102 完整文件仍为 5/6:唯一失败保持在
spec.ts:412,根因仍是 travel category 夹具使showDescription=false,与本轮 diff 无关;本轮新增的管理员 PC/移动只读投影用例通过。 - 后端全量 Vitest 为 1303/1306;3 个失败均在既有付款单 BIFF8 生成链路,错误为
payment_order_generator_unavailable,本轮 diff 未触及付款批次或生成器。当前任务相关的聚焦与扩展套件均通过。 - 独立只读权限复核结论 PASS:非参与人写入守卫位于副作用前,读取、workflow、财务付款和差旅专用分支未收紧。非阻断建议是后续补附件 DELETE 单独用例及 rejected/reviewing UI 状态矩阵。
- 提交前复核发现 precheck 缺少对象级读授权;本轮决定直接修复。路由现在先读取报销并复用
ensureOwnOrCanViewAll,普通非参与人 403 且 precheck 服务零调用,owner/submitter 与expense.view_all保持成功。父 tasktask.json末字节已再次确认为0a。 - 本轮没有 schema 或 migration 变化,没有访问生产、推送、部署或归档;部署任务继续处于 planning 并阻塞于本任务复核与提交决定。