文件
hyb-oa/.trellis/tasks/07-27-yang-jun-reimbursement-readiness/prd.md
T
wangsli 0e44aa72f3
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s
收敛报销明细与材料交互(07-27-yang-jun-reimbursement-readiness)
2026-07-31 22:01:25 +08:00

18 KiB

杨俊报销就绪

Goal

让已在企业微信通讯录中的杨俊尽快具备真实报销能力,同时避免让真实员工承担首轮试错:先使用通讯录中既有的“测试员工”和“测试主管”两个企微测试成员,在生产 OA 完成一条受控、可清理的报销体验验收;验证通过并清理测试数据后,再请杨俊通过企微进入 OA、创建并提交真实报销,由其真实直属主管马建勇审批,再进入王芝玲负责的财务处理链路。

Background

  • 杨俊已存在于管理员导出的企业微信通讯录,因此具备企微成员账号;生产只读体检已确认他尚无 OA 员工记录和企微绑定。
  • 上一轮通讯录 apply 只包含两名财务职责目标,明确没有把其余四名成员送入生产输入。
  • 报销是当前急需的真实业务,不等待站内通知、入职向导、审批流简化或月度报表等后续产品项。
  • 生产写入前需同时确认自动异机备份 timer 的构建合同未因最近部署发生漂移。
  • 通讯录单人子集唯一、active、企业邮箱完整、手机号缺失但满足现有 nullable 合同。
  • 当前有 37 个 active 费用类型和 1 个 active 报销工作流定义;active 法体为 0,但代码确认报销创建/提交不读取法体,法体不是本次硬门禁。
  • 当前自动备份 daily/watchdog/drill-reminder 和日常巡检 service 的 BUILD_SHA 均与活动 server 不一致;最近一次备份成功发生在该漂移被今晚任务触发之前,不能视为今晚安全。
  • 管理员导出的通讯录中已有“测试员工”和“测试主管”两个专用企微测试成员;二者均有唯一账号、部门及联系方式且状态为已激活,但生产 OA 尚无姓名包含“测试”的员工或绑定。
  • 受控测试发现生产 OCR_PROVIDER=mock 且腾讯 OCR 凭证未配置;合成 PDF 被写入虚构的 Mock 发票字段并直接标记可用。该行为可用于测试,但不得作为杨俊真实发票的正式识别结果。
  • 生产已将 OCR_PROVIDER 切换为 off 并重建实际承载后台任务的 server;复验确认票据不进入 OCR 队列、业务字段为空且仍可绑定和提交。ocr_provider 因既有非空 schema 默认值仍记录为 tencent,但 OCR 尝试数和请求/完成时间均为空;该历史字段语义不作为“已调用腾讯 OCR”的证据。

Requirements

  • 生产只读体检必须一次性核对:OA 员工、企微绑定、active 状态、角色、直属主管、主管 active/审批权限、可用费用类型、报销功能开关和审批定义;法体仅记录现状,不作为报销阻断项。
  • 同时比较自动备份 systemd unit 中烤入的 BUILD_SHA 与活动 server 构建标识;只输出是否一致,不输出环境文件或宿主路径。
  • 若 OA 账号缺失,复用现有通讯录 stdin 路径只筛选目标员工,先 dry-run,另行获批后 apply;初始角色严格为 employee,其余通讯录成员不进入输入。
  • 通讯录导入只允许把企微管理员导出的成员资料写入 OA 并建立身份绑定;OA 不调用企微成员 create/update/disable,不反向修改企微姓名、部门、主管、手机号或邮箱。企微成员资料由本人在企微或企微管理员在管理后台维护。
  • 将杨俊的 direct_manager_id 设置为用户已确认的真实直属主管马建勇;写入前仍需只读确认马建勇为不同、active 且具有 expense.approve 权限的 OA 员工,不得为了报销绕过审批或扩宽角色。
  • 若费用类型或报销工作流缺失,只补足完成报销所需的最小主数据;不为了本次报销新建法体,不顺带整理全部组织架构或导入其余员工。
  • 杨俊写入后只做账号、绑定、主管解析、费用类型和提交流程的安全验证;杨俊本人名下不创建测试报销、测试发票或测试付款数据。
  • 允许从同一份管理员通讯录中仅筛选既有的“测试员工”和“测试主管”两个企微测试成员,先 dry-run 再 apply;不得新建企微成员,不得把其他真实成员带入输入。
  • 两名测试成员进入 OA 后,“测试员工”角色严格为 employee,“测试主管”角色严格为 employee + manager;测试员工的 OA 直属主管仅指向测试主管。不得授予 finance、finance_mgr、administration 或 admin,不得借测试查看真实薪资、银行资料或系统管理数据。
  • 每次受控验证最多创建一条明确标记“系统测试、非真实业务、禁止付款”的测试报销和一张不含真实票据、银行或个人资料的安全测试 PDF;金额使用最小测试值,测试单不得审批通过或进入财务付款链路。配置复验或固定门禁诊断需要重跑时,每批都必须独立退回、删除报销并归档票据。
  • 受控测试必须覆盖:两个测试成员分别通过企微登录、申请人创建/编辑报销、上传安全 PDF、处理 OCR 失败分支(如发生)、绑定票据、提交、主管待办可见及执行“退回”。退回后申请人删除 draft 报销,释放后的测试票据手工归档。
  • 测试结束后撤销两个测试成员的 OA 会话并停用其 OA 账号;仅停用 OA,不修改或停用企微中的两个测试成员。后续需要复测时可通过现有 OA 接口重新启用。
  • 杨俊上传真实发票前必须消除生产 mock OCR:要么配置并验证真实腾讯 OCR,要么显式关闭 mock 并采用人工录入/核对方案;不得把 Mock 字段展示为真实识别结果。
  • 真实报销提交前至少需要一条费用明细和一张已绑定、状态有效的票据;这由员工在真实业务中提供,不用合成数据代替。
  • 最近部署后必须重装自动备份三项 service/timer 和日常巡检 timer,使 unit BUILD_SHA 与活动 server 一致;重装后手工触发一次真实自动异机备份,确认源端成功且 ARM 恢复点新鲜,再允许写入杨俊账号或主管关系。
  • 第一笔真实业务由员工本人正常发起,目标链路为“员工提交 → 真实主管审批 → 财务处理”;付款批次仍遵守既有 maker-checker。
  • 当前小团队取消报销金额分层,所有金额统一按“直属主管 → finance”审批;不得保留无人持有的 finance_mgr 节点,也不得因马建勇同时是主管和 CEO 而让同一人重复审批。
  • 真实首笔报销暴露审批可读性阻断:待办列表卡片能够进入审批任务详情,但任务详情只显示单号、申请人和金额摘要,没有通往费用明细、发票和附件的业务详情入口。移动端必须在审批任务详情区提供明确的“查看完整报销单”入口,复用既有 /mobile/reimbursements/:id 路由和 state.from 回跳约定;PC 审批任务详情同步提供报销单入口。
  • 报销详情当前把后端 ISO UTC 时间直接截取为字符串,附件和审批记录会在中国时区显示早 8 小时;报销链路的日期时间必须复用共享格式化能力并固定按 Asia/Shanghai 展示,不修改数据库时间或 API ISO 合同。
  • PC 与移动报销详情应按 KISS 原则收敛为“概况 → 明细 → 发票 → 附件 → 审批记录”的业务主线:删除重复状态、重复标题和面向只读用户的操作教学;没有实际内容或动作的辅助区块不渲染,同时保留编辑态必要控件、风险提示和审计信息。
  • 生产真机验收确认企微 WebView 可继续运行部署前的旧前端包:公网资源已包含“查看完整报销单”,但存活页面仍只显示报销日期。页面从后台恢复到前台时必须用现有前后端构建标识做一次轻量比对;不一致时只显示用户可控的“发现新版本,点击刷新”,点击后清理旧 PWA 缓存并重载,不自动打断当前页面操作,不扩展为完整更新管理系统。
  • 真实审批继续暴露材料查看阻断:PC 能打开普通附件,但 PC 与移动报销详情均没有发票原件入口,企微 WebView 中异步 window.open(blob:) 只下载附件而不能预览。企业微信自建应用内必须优先使用官方 ww.previewFile / wx.previewFile 原生能力查看 PDF;普通 PC 浏览器保留浏览器预览,两端保持“查看原件”的业务能力一致。
  • 生产验收发现移动报销列表固定请求 scope=own,导致已有 expense.view_all 的管理员无法在企微工作台找到杨俊的报销单并代为验证原生预览。移动端必须与 PC 的范围能力对齐:仅对 expense.view_all 用户显示“我的 / 全部”切换,默认仍为“我的”,选择“全部”时复用现有 scope=all API;普通员工不显示范围切换,不修改后端权限模型。
  • 企业微信原生预览使用准确的文件字节数、带扩展名的文件名和短时签名 URL。原生层不会携带 OA Bearer token 或可靠复用 WebView Cookie,因此附件可以在当前任务内增加仅用于 previewFile 的短时 bearer URL 例外;该 URL 必须在签发前执行当前对象级授权和下载理由检查,绑定文件与访问人、短时过期、不得包含长期凭据,并在实际取件时写审计。
  • 生产可见性验收通过后发现报销详情仍把每张发票、每个补充附件都暴露为独立“查看原件”按钮,且费用明细与其 linkedItemId 发票分区展示,不利于财务逐条核对。PC 与移动端应统一采用“业务关联优先、材料入口收敛”的展示:每条明细直接显示并可预览其关联发票;全部发票和补充附件仍在单一“报销材料”区按类型汇总,文件信息行本身作为预览入口,不新增独立材料浏览路由、轮播器或后端模型。

Scope

本轮范围只包括:修复生产 automatic-backup/WARCH3 timer 的构建合同并取得新鲜异机恢复点;从通讯录导入杨俊及两个既有企微测试成员;设置各自真实或测试主管关系;用两个测试成员完成一条可清理的生产报销体验验收;清理测试业务数据并停用测试 OA 账号;最后由杨俊本人使用真实数据发起报销;修复真实审批任务详情到完整报销单的移动端和 PC 入口。所有真实报销内容由杨俊本人提供和提交,所有真实审批与财务处理由对应真实人员完成。

Acceptance Criteria

  • 只读体检给出脱敏、可执行的缺口清单,并确认 timer BUILD_SHA 是否与活动构建一致。
  • 目标员工在 OA 中为 active,企微绑定唯一,初始业务角色不超过 employee。
  • 至少有一个 active 费用类型可用于填单;法体缺失已确认不阻断当前报销创建/提交。
  • direct_manager_id 能解析到真实、active 且具有 expense.approve 权限的不同员工。
  • 报销相关功能开关和工作流定义可用;无需差旅申请也能创建报销。
  • 自动备份三项 timer 与日常巡检 timer 的 BUILD_SHA 均与活动 server 一致,且 timer 保持 enabled/active。
  • timer 修复后生成一份新的成功异机批次,ARM 侧完整性/新鲜度检查通过;该门禁先于任何杨俊生产数据写入。
  • 目标员工完成一次真实企微登录并能看到报销入口;主管能看到相应审批入口。
  • 两个既有企微测试成员分别成功通过企微登录 OA;没有创建新的企微成员。
  • 两个测试成员均通过普通浏览器账号密码登录并完成首次改密;企微 SSO 仍保留为人工确认项。
  • 测试员工仅有 employee,测试主管仅有 employee + manager,测试主管能看到测试员工提交的待办且执行“退回”。
  • 每次受控验证最多产生一条带明确测试标识的报销和一张安全测试 PDF;所有批次均未审批通过、未进入财务或付款链路,并已逐批清理。
  • 退回后的测试报销已删除,测试票据已解绑并归档,两个测试 OA 账号已停用且会话已撤销;企微测试成员未被修改或停用。
  • 不持久化通讯录筛选文件,不导入杨俊及两个测试成员之外的其他成员,不产生测试付款。
  • 生产已显式关闭 mock OCR;off 路径已用测试账号复验,空发票元数据仍可绑定、提交、主管退回和清理,真实使用暂由财务查看 PDF 原件并人工核对。
  • 本轮没有调用企微成员写接口;企微成员资料未被 OA 反向修改。
  • 生产审批规则已收敛为唯一全金额规则,499.99、500、5000 三个边界均解析为 department_manager → finance,且没有 CEO 重复节点或 finance_mgr 空节点。
  • 移动审批任务详情中的报销摘要区提供明确的“查看完整报销单”入口,进入现有移动报销详情并能通过既有 state.from 返回原审批任务。
  • PC 审批任务详情提供对应的“查看报销单”入口;两端均不修改待办列表卡片的既有点击行为,不修改审批状态机、权限矩阵或后端数据合同。
  • PC、移动报销详情和 PC 审批任务详情中的 ISO 时间按 Asia/Shanghai 正确展示,UTC 样例不再直接显示原始小时;数据库与 API 时间合同不变。
  • PC 报销详情合并重复概况,附件区不再出现“附件材料/补充附件”双标题;无关联、无预算/风险内容时不显示空辅助区块。
  • 移动报销详情顶部不重复状态和教学文案;无实际操作时不显示仅含“当前状态不可编辑”的操作卡,编辑态上传与提交能力保持可用。
  • 已登录页面从后台恢复到前台且前后端构建不一致时显示明确刷新提示;构建一致、检查失败或开发构建时不误提示,刷新动作复用缓存清理后重载能力。
  • 移动企微报销详情中的发票和 PDF/图片附件均提供“查看原件”,通过官方 JS-SDK 原生预览打开;调用参数包含准确 size 和带扩展名的 name,不依赖异步弹窗或 WebView 原生 PDF 渲染。
  • PC 报销详情中的发票和附件提供对应的“查看原件”,使用短时签名 URL 或现有认证下载能力;两端审批人均只能查看当前报销绑定材料,不能编辑、解绑、删除或获得票据池管理权限。
  • 移动报销列表仅对具备 expense.view_all 的用户显示“我的 / 全部”切换,默认“我的”;切换“全部”后能通过现有列表进入他人报销详情,普通员工始终只能查看本人列表。
  • JS-SDK 签名接口只接受本站允许 origin 的无 fragment 页面 URL,不向客户端、日志或审计暴露 JSAPI ticket、企微 Secret 或 access token;签名失败和非企微环境安全降级。
  • 发票/附件预览 URL 的过期、篡改、对象不匹配、缺少下载理由和未授权访问均被拒绝;实际文件响应保留审计,用户已确认能在企微查看当前真实报销材料。
  • PC 与移动端每条费用明细展示通过 linkedItemId 关联的发票摘要,点击该摘要可沿用现有安全预览能力打开原件;未关联发票不错误归入任何明细。
  • PC 与移动端将原“发票 / 附件材料”收敛为单一“报销材料”区,显示发票与补充附件计数;材料信息行可点击预览,不再为每份材料重复渲染“查看原件”按钮,同时保留草稿编辑态的添加、移除、上传和删除能力。

Out of Scope

  • 不修改 CEO 本人无主管报销限制,不通过授予 finance_mgr 或管理员代批绕过。
  • 不重构报销状态机、审批引擎、企微 OAuth 或权限模型。
  • 不从 OA 创建、更新或停用企微成员;需要修改企微成员资料时,由本人或企微管理员在企微侧处理。
  • 不提前实现 R63–R66,不扩大为全员入职或组织架构治理。
  • 不在未获单独批准时执行通讯录 apply、主管/法体写入、生产报销或付款操作。
  • 不使用真实发票、真实金额、真实银行资料或真实员工个人资料作为测试材料;不让测试单进入“通过/待财务/付款”状态。
  • 不把手机号缺失视为导入阻断项;该员工使用企微或企业邮箱登录,后续按需补手机号。
  • 不在本轮顺带修复请假、采购、差旅等其他审批类型的同类“业务单据详情入口”缺口;将其记录为后续统一审批中心体验任务候选。

Test Plan

  • Trellis task/governance、敏感扫描、流程与文档门禁、git diff --check。
  • 通讯录聚焦 dry-run 仅输出人数、计划、冲突、跳过和失败计数。
  • 生产只读 SQL/Prisma 只返回布尔值和计数,不输出手机号、邮箱、企微 userid、完整账号或原始 payload。
  • 使用既有报销 workflow/权限聚焦回归验证主管解析和 expense.approve,不写生产业务单据。
  • 前端运行 cd client && npm run typecheck && npm run build,并用聚焦 Playwright 覆盖:移动审批任务详情进入完整报销单、返回原任务后审批动作仍可见,以及 PC 审批任务详情进入报销单。
  • 用合成 UTC 时间在聚焦 Playwright 中验证附件时间转换为上海时间,并验证 PC/移动 KISS 信息层级、编辑态关键入口和无动作只读态;不读取生产真实报销内容。
  • 用合成 /ready 响应验证前台恢复时的构建不一致提示、同版本静默和检查失败静默;不依赖生产真机数据。
  • 用合成企微 ticket、签名 URL 和 PDF/图片元数据验证:JS-SDK URL 签名、origin allowlist、原生 previewFile 参数、PC fallback、审批人对象级只读授权、附件理由门禁、短时 token 过期/篡改拒绝和实际查看审计;不得使用真实发票或附件。
  • 用合成管理员与普通员工权限验证移动报销范围:管理员默认请求 scope=own,切换后请求 scope=all 并显示他人报销;普通员工不显示“全部”且始终请求 scope=own。
  • 用合成多明细、已关联发票、未关联发票和补充附件验证 PC/移动一致性:关联发票出现在正确明细内;统一材料区计数正确且所有材料仍可预览;页面不再出现逐文件“查看原件”按钮;编辑态管理动作不回归。