文件
hyb-oa/.trellis/tasks/07-28-travel-reimbursement-guide/design.md
T
wangsli fa326f92fa
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s
收敛真实OCR样票验收入口(07-28-travel-reimbursement-guide)
2026-07-29 08:28:42 +08:00

7.4 KiB
原始文件 Blame 文件历史

技术设计

边界

本任务不开发新的 OCR provider,也不开放图片发票或改变审批流。在现有腾讯 provider 内把统一入口从 VatInvoiceOCR 改为 RecognizeGeneralInvoice,增加票种感知的安全归一化和上传大小门禁,再完成生产配置恢复、真实链路验证及两份既有业务文档更新。

生产配置写入、容器重建、腾讯 API 调用和真实样票上传均属于单独受控步骤;每一步只在前一步通过后继续。

配置与运行拓扑

  • 生产环境文件继续作为 OCR 配置事实源。
  • 凭证采用 OA OCR 专用的最小权限子用户密钥;不使用主账号永久密钥,不从聊天、仓库、日志、命令参数或历史残留复制。
  • 用户在现场终端静默输入凭证。自动化只检查 provider、必要字段是否非空、文件权限和配置 smoke,不回显值或长度。
  • 当前仅 server 执行 jobs,因此只重建 server,不启动 worker;重建后再次确认只有一个 OCR job executor。
  • provider 从 mock 直接切换为 tencent 只能发生在服务开通、权限、计费状态和密钥均确认后。任一前置失败时保持禁止真实票据上传,不用 mock 代替真实能力。
  • 计费只使用 RecognizeGeneralInvoice 对应的通用票据识别(高级版)每月 1,000 次专用免费包,不接独立火车票接口。生产固定中国大陆地域;控制台确认免费包已到账、后付费关闭,并配置费用或余额告警。免费包耗尽时服务失败关闭,应用记录额度类可解释终态,不自动付费续用。

生产部署根收敛

  • 生产只读核验发现,活动 Compose 的工作目录被错误设置成标准部署根下的 deploy/trialrun 子目录,导致仓库再次同步到自身子目录,形成重复的 deploy/trialrun/deploy/trialrun。活动 server、环境文件和四个 systemd 运维 timer 均已引用该嵌套拓扑,因此它不是可直接删除的闲置副本。
  • 本次发布把部署根收敛回 deploy 脚本约定的标准单层根。迁移窗口开始时先暂停相关 timer,将当前活动根原子改名为时间戳回退目录,再创建干净标准根;不在原目录上用 rsync --delete 就地清理,以免同时破坏活动配置与回退证据。
  • 从回退目录把生产环境文件复制到标准根的预期相对位置,保持所有者和 0600 权限,不读取、打印或经本地中转 Secret。数据库和附件继续使用部署根之外的既有宿主目录,不搬迁、不初始化、不重置。
  • 使用同一 Compose project 和已批准提交部署 server;数据库容器与数据卷保持原位,不创建 worker。部署后重新安装自动备份 daily/watchdog/drill-reminder 与 WARCH3 timer,使所有 WorkingDirectory、ExecStart 和环境文件引用只指向标准根。
  • 验收包括活动 Compose 工作目录不再重复、环境文件唯一受控、server /ready 和构建标识正确、provider 为 tencent、仅一个 job executor、四个 timer 启用且各自 dry/status 检查通过。旧根作为短期回退保留,本任务不删除;后续删除需在新备份成功且另行批准后执行。

腾讯 API 合同

  • API:RecognizeGeneralInvoice,版本 2018-11-19,由当前腾讯 Node SDK 调用。
  • PDF 请求:Base64、第一页、关闭多页、切图、坐标、二维码和印章返回。
  • 一份 PDF 只允许解析出一张受支持票据;零张、多张、未知或不支持子类型进入明确失败状态。
  • 支持子类型按两族归一化:住宿 VAT/电子普通发票;电子发票(铁路电子客票)。
  • 质量门禁按 documentSubtype 选择必填字段;无代码电子票据不再伪造发票代码。
  • OcrResult.result_json 仅保存规范化业务字段和安全元数据,不保存 provider 原始响应或乘车人身份字段。
  • PDF 原文件上限为 7MiB,使 Base64 后保持在腾讯 10M 上限内;大小错误在上传阶段阻断。

验证数据流

  1. 用户在腾讯云控制台确认通用票据识别(高级版)每月免费包已到账、中国大陆地域、后付费关闭和费用/余额告警。
  2. 用户创建或轮换 OA OCR 专用子用户密钥,并确认 OCR 服务可用。
  3. 用户在现场终端把 provider、密钥和地域写入生产受控环境文件。
  4. 重建 server,使新配置进入实际运行进程。
  5. 运行外部依赖 smoke、运行时 smoke、/ready、构建标识和 job 拓扑检查。
  6. 经样票单独授权后,通过现有 PDF 发票入口分别上传住宿电子普通发票和铁路电子客票样票。
  7. 只记录 provider、状态、尝试/完成证据和脱敏字段命中摘要;不记录票面、完整字段或原始 payload。
  8. 正常清理或归档测试业务记录,再允许杨俊提交真实票据。

授权样票验证工具边界

  • 既有 check-ocr-provider-samples.mjs 必须与生产 adapter 使用同一 RecognizeGeneralInvoice 入口和按票种必填字段规则,不得继续引用已删除的 VAT-only 导出或把铁路电子客票套入 VAT 五字段门禁。
  • 真实 PDF 从本地受控、Git 忽略的样票目录按匿名别名选择,经 SSH 标准输入直接流入生产 server 容器内存;不得把原件、临时副本或 manifest 写入远端磁盘、OA 附件存储、数据库、仓库或报告。
  • 每个进程只接收一份 PDF,验证文件签名和 7MiB 上限后最多调用一次 RecognizeGeneralInvoice。住宿与铁路样票分两次执行,任一失败立即停止,不自动遍历目录中的其他文件。
  • 输出只允许匿名别名、provider、票种、安全传输模式、耗时、字段命中布尔值、缺字段名和稳定错误码;不得输出文件名、原始响应、识别值、人员/企业名称、票号、金额或票面内容。
  • live runner 的代码、合成测试和生产部署先通过,再单独取得两次真实 API 调用批准;工具可用不等于真实样票已验证。

文档口径

  • docs/员工快速上手.md 增加一页式差旅报销步骤:火车票和住宿费拆明细,官方 PDF 绑定对应明细,两类费用均附支付截图,金额差异必须说明,提交后进入主管和财务流程。
  • docs/报销发票附件规则.md 固化支付证明必交、敏感字段遮挡、退款/代付/优惠差异和无截图例外口径。
  • OCR 结果仅辅助识别和查重;财务仍核对明细、PDF 原件和个人支付证明。

失败与回退

  • adapter 聚焦测试、配置 smoke、腾讯调用或任一真实样票验证失败:停止开放真实票据,不继续制造 pending/retry 数据。
  • 若新配置导致运行异常,恢复变更前环境文件的受控副本并重建同一 server;回退后不得使用 mock 处理真实票据。
  • 若标准根部署、timer 重装或健康检查失败,停止继续发布,将 Compose 工作目录和 systemd unit 恢复到时间戳回退根并重建原 server;数据库和附件目录不参与回退切换。
  • 样票失败记录使用可解释状态和脱敏摘要,不直接修改数据库字段绕过状态机。

历史凭证结论

2026 年 5 月的证据能证明真实腾讯 OCR 曾可用,但不能证明当时密钥仍有效或满足当前最小权限。当前生产机、历史容器、同机旧环境文件、开发机环境文件及 shell 历史均无可恢复凭证;数据库/附件备份也不包含环境密钥。因此本任务不设计“从旧部署复制密钥”的路径。