# 杨俊报销就绪:技术设计 ## 1. 设计目标 以最小生产变更打通“杨俊企微登录 → 杨俊提交真实报销 → 马建勇审批 → 王芝玲财务处理”。本任务不新增产品能力,复用现有通讯录导入、用户主管写入、报销工作流和异机备份能力。 ## 2. 已确认边界 - 企业微信成员与 OA 员工是两个独立事实:杨俊已在企微通讯录,但生产尚无 OA 员工记录和企微绑定。 - 单人通讯录输入可唯一筛出杨俊;手机号为空符合现有 nullable 合同,企业邮箱存在,`incomplete=0`。 - 生产已有 37 个 active 费用类型和 1 个 active 报销工作流定义。 - active 法体为 0,但当前报销创建、提交和费用控制不以法体为硬门禁,本任务不创建法体。 - 杨俊的真实直属主管由用户确认是马建勇。 - 自动备份 daily/watchdog/drill-reminder 与 WARCH3 service 的 `BUILD_SHA` 均已漂移,必须先修复。 ## 3. 数据流与执行门禁 ```text 现场只读复核活动构建与 4 个 unit → 重装 automatic-backup 三项 timer/service 与 WARCH3 timer → 验证 unit BUILD_SHA、enabled、active → 手工触发一份真实自动异机备份 → 验证源端成功与 ARM 恢复点完整/新鲜 → 从管理员导出通讯录在内存中仅筛选杨俊 → production dry-run(create=1、conflict/skip/fail=0) → production apply(初始角色仅 employee) → 验证 OA 员工 active、企微绑定唯一、其他成员未导入 → 通过现有用户管理接口设置 direct_manager_id=马建勇 → 验证主管 active、不同人、具备 expense.approve,并核对审计 → 杨俊本人企微登录并提交真实报销 → 马建勇审批,随后进入王芝玲财务处理链路 ``` 任一门禁失败即停止后续步骤,不用后续成功掩盖前序失败。 ## 4. 复用合同 ### 4.1 通讯录导入 - 复用 `server/src/scripts/import-wecom-directory-export.js` 的 stdin 输入,不把筛选后的 XLSX 或成员原始 payload 写入磁盘、日志、Trellis 或聊天。 - dry-run 只记录人数与结果计数。 - apply 必须同时满足脚本 `--apply` 参数和容器内 `WECOM_DIRECTORY_EXPORT_APPLY=1`。当前 Compose v1 调用必须显式使用 `docker-compose exec -T -e WECOM_DIRECTORY_EXPORT_APPLY ...`,不能只在宿主 shell export。 - 输入严格只有杨俊一人;成功创建后的初始角色集合严格为 `employee`,不导入其他通讯录成员。 - 此路径是“管理员导出企微通讯录 → OA 员工/身份绑定”的单向导入。OA 侧主管字段仅服务 OA 工作流;不调用企微成员 create/update/disable,也不把 OA 主管、姓名、部门、手机或邮箱写回企微。 - 企微成员资料如需变化,由成员本人在企微允许的入口修改,或由企微管理员在管理后台修改;OA 后续只通过重新导出/受控同步读取变化。 ### 4.2 直属主管 - 复用 `POST /api/users/batch/set-manager`,不直写数据库。 - 写入目标仅杨俊,主管仅马建勇;接口负责 active、自指等现有校验。 - 写后核对 `SYSTEM_USERS_BATCH_SET_MANAGER` 审计增量,不记录完整账号或原始请求体。 - 马建勇必须是 active、与杨俊不同且按有效角色解析出 `expense.approve`。 ### 4.3 报销业务 - 杨俊无需先存在差旅申请;`linked_travel_request_id` 可空。 - 提交仍须满足既有硬门禁:至少一条费用明细、至少一张已绑定且状态为 `bound` 的真实票据、可匹配工作流并能解析审批人。 - 第一笔真实报销必须由杨俊本人操作;Codex 不代建生产报销、发票、付款或测试业务数据。 ### 4.4 timer 与备份 - 使用现有 `install-automatic-backup-timer.sh` 和 `install-warch3-ops-timer.sh`,从活动部署现场解析并显式传入合同参数;不在任务文档中固化 Secret、宿主路径或完整账号。 - 重装后核对 4 个 service 的 `BUILD_SHA` 与活动 server 一致,并确认对应 timers 为 enabled/active。 - 随后手工触发 daily 自动备份路径,验证源端 service 成功、ARM 批次完成且 dead-man/新鲜度检查通过。 - 新鲜异机恢复点是人员数据写入的前置条件,但不会用于回滚单个人员变更。 ## 5. 失败与回退 - timer 重装或异机备份失败:不写杨俊数据,保留本地诊断并走既有脱敏群告警。 - dry-run 不满足 `target=1 / active=1 / incomplete=0 / planned create=1 / conflicts=0 / skipped=0 / failed=0`:不 apply,重新核对输入或生产现状。 - apply 失败:停止;按脚本结果诊断,不手工拼接残缺账号。 - apply 成功但主管写入失败:保留已创建的 OA 员工和企微绑定,不删除、不恢复整库;主管仍为空时不能提交报销,可安全重试同一主管接口。 - 主管写错:通过同一接口恢复写入前的 `direct_manager_id`,不恢复整库。 - 真实报销提交失败:保留草稿和真实票据状态,按返回的业务错误定位;不得通过扩权、代批或伪造数据绕过。 ## 6. 隐私与审计 - 终端与任务证据只保留布尔值、计数、角色 slug、审计 action 和脱敏状态。 - 不输出手机号、企业邮箱、企微 userid、完整账号、通讯录原始行、票据内容、银行资料、Secret 或完整宿主路径。 - 账号导入与主管写入分别保留现有系统审计,确保每一步可独立追踪和撤销。 ## 7. 不做的设计扩展 - 不新增导入 API、主管兜底规则、CEO 自审批能力或报销状态。 - 不启用 OA → 企微通讯录写回,不修改任何企微成员资料。 - 不创建法体、不补银行账号、不导入其余成员。 - 不把首次真实业务扩成管理员代办的生产自动化测试。