文件
hyb-oa/docs/implementation_plan.md
T
wangsli f527633716 feat(server): 完成 P0+P1 后端能力(工作流、RBAC、付款归档)
P0 MVP:

- 认证:login/refresh/logout/forgot/reset + tokenVersion

- RBAC:角色到权限映射 + requirePermission

- 发票池:upload/bind/signed-url + 判重(VALID_003/VALID_005)

- 报销:create/view/submit + 单号生成

- 工作流:approve + department_manager 解析

P1 扩展:

- 动作:reject/return/withdraw(含 comment)

- transfer:任务转审 + 链路上限 3

- pay:approved -> paid + 发票归档 used_complete

- 动态审批链:approval_rules 驱动

回归脚本:

- smoke-test.sh / regression-dedup.sh / regression-workflow-actions.sh
2026-02-07 16:43:31 +08:00

8.6 KiB
原始文件 Blame 文件历史

hyb-oa 实施计划(Phase 1 / P0)

日期:2026-02-06
范围:报销系统及其依赖模块(员工/权限/工作流/附件)

0. 前置结论(不可再分叉)

  • 技术栈:Fastify + Prisma + PostgreSQL(见 docs/tech_stack_report.md)
  • 规格书:以 docs/requirements-specification.md 为单一事实源

1. 复用资产清单(从 shenzhou-business-suite 迁移到 hyb-oa)

资产 来源 复用方式 需要改造
工作流 4 表结构 shenzhou-business-suite/supabase/schema/70_workflow/01_workflow_02_tables.sql 转 Prisma schema Supabase/RPC → Fastify service 事务
approval_rules 同上 转 Prisma schema + seed 3 条 管理 UI 放 P1(P0 先 DB/接口维护)
approval_transfers 同上 转 Prisma schema 与 workflow_tasks 联动,reason≥10 约束
document_sequences 同上 转 Prisma schema + seed 默认报销单号 生成逻辑改为服务端原子更新
权限码体系 shenzhou-business-suite/src/types/permissions.ts 复用命名与粒度 增加 expense.proxy_submit/proxy_manage
工作流类型 shenzhou-business-suite/src/types/workflow.ts 参考 JSON 结构 P0 只用线性审批链(后续扩展保留)
报销表结构参考 shenzhou-business-suite/supabase/schema/20_finance/06_reimbursement_01_tables.sql 参考 forms/items/attachments 字段 补 file_sha256、签名 URL、判重例外审计
默认费用类型 seed shenzhou-business-suite/supabase/seed.sql 迁移 35 启用 + 3 legacy 禁用 hyb-oa 额外启用 utilities/rent 形成 37 启用
存储安全基线思路 shenzhou-business-suite/supabase/migrations/20260131175000_storage_security_baseline.sql 迁移约束到 API 层 P0 本地存储 + 签名 URL;P2 MinIO/OSS
UI 组件 shenzhou-business-suite/src/components/ui/* 实现阶段复制到 client/src/ 替换路由/样式变量;移除 Supabase 依赖
测试基建 playwright + vitest 配置 实现阶段迁移 P0 覆盖鉴权/工作流/判重核心路径

2. Phase 1(P0)里程碑拆解(按可开工顺序)

Milestone 1:Prisma schema 草稿 + 评审

目标:把关键表结构确定下来(后续开发不再反复改 schema)。
范围(至少):

  • 组织/人员:departments、employees、employee_roles
  • 权限:权限码为代码常量;角色集合落 employee_roles
  • 报销:reimbursement_forms、reimbursement_items、invoice_pool(票据/附件池 + 绑定关系)
  • OCR:ocr_results(OCR 去重与结果持久化)
  • 费用类型:expense_types(含 37 默认启用 seed)
  • 单号:document_sequences
  • 工作流:workflow_definitions、workflow_instances、workflow_tasks、workflow_history
  • 审批规则/转审:approval_rules、approval_transfers
  • 认证与审计:auth_sessions、audit_logs
  • 代提交授权:delegation_grants

验收:

  • schema 与 docs/requirements-specification.md 一致
  • 关键约束可实现(单号唯一、转审原因≥10、费用类型 code 唯一、软禁用等)

评审截止(Schema Freeze):

  • 截止:Milestone 1 合并后的 2 个工作日
  • 截止后变更规则:
    • 仅允许 ADD COLUMN / ADD TABLE / ADD INDEX 这类向前兼容变更
    • DROP/RENAME/CHANGE TYPE/CHANGE NULLABLE 等破坏性变更必须走“变更申请”,并同步更新规格书与迁移计划

范围:

  • POST /api/auth/login|refresh|logout|forgot-password|reset-password
  • auth_sessions:refresh hash + deviceFingerprint/ip/UA + session 限额(5)
  • tokenVersion 踢下线

验收:

  • refresh rotation 生效;退出/重置能撤销会话;access 不落 localStorage

Milestone 3A:发票池上传(本地存储)+ SHA256 + 签名 URL

范围:

  • POST /api/invoice-pool/upload(multipart;入参 file + 可选 owner_employee_id + 可选 ocr_type;返回 invoice_pool_id)
  • POST /api/invoice-pool/:id/signed-url(TTL=10m)
  • 上传约束:类型白名单 + ≤10MB
  • 哈希:计算并落库 file_sha256(作为 OCR 去重 key)

验收:

  • 未授权用户无法获取签名 URL;过期不可访问;同文件哈希可用于 OCR 去重复用

Milestone 3B:腾讯云 OCR + ocr_results 去重 + retry 策略

范围:

  • OCR:调用腾讯云 OCR,保存“标准化结果”(rawResponse 仅日志不落库)
  • 去重:ocr_results 以 file_sha256 + ocr_provider + ocr_type 唯一,命中时复用(不重复计费)
  • 状态机:invoice_pool 从 pending_ocr → available/ocr_failed
  • 重试:POST /api/invoice-pool/:id/retry-ocr(attempt<=3;间隔>=60s;错误码 VALID_006/VALID_007)
  • 审计:OCR_REQUESTED/OCR_SUCCEEDED/OCR_FAILED/OCR_RETRIED
  • 自动归档:available/ocr_failed 未绑定条目 90 天后自动归档为 archived_reason=unused_timeout

验收:

  • 同一文件二次上传不重复计费;OCR 失败可重试且次数/频控生效;90 天游离自动归档生效且不参与全局判重;状态与审计一致

Milestone 4:费用类型系统(动态 expense_types)

范围:

  • GET /api/expense-types?enabled=true
  • seed:默认启用 37 项 + legacy 3 项禁用
  • 软禁用语义:禁用后不出现在下拉,但历史可展示

验收:

  • 下拉加载启用类型;禁用类型不显示但历史单据不丢

Milestone 5:单号生成(document_sequences)

范围:

  • 报销单号:BX-YYYYMMDD-0001(daily reset)
  • 生成逻辑:数据库原子递增(同事务写入 reimbursement_forms.form_number)

验收:

  • 并发下无重复编号;失败回滚不产生脏占用

Milestone 6:报销单 CRUD + 提交发起工作流

范围:

  • 报销单:创建/更新/删除草稿/查看
  • 发票池绑定/解绑:POST /api/invoice-pool/:id/bind|unbind(并发行锁;冲突 409/VALID_005;绑定时触发全局判重 409/VALID_003)
  • 删除草稿:自动解绑其绑定的发票池条目并回到 available
  • 提交:校验 items、票据/发票要求(发票池绑定)、判重;生成单号;启动工作流实例并创建首个任务
  • 代提交:校验 delegation_grants(scope & 生效时间)
  • 代提交授权(Delegation Grants)CRUD API(用于自助/代维护):
    • GET /api/delegation-grants(默认返回与本人相关;system.users 可查询任意)
    • POST /api/delegation-grants(本人创建:principal=自己;system.users 可代创建)
    • POST /api/delegation-grants/:id/revoke(本人撤销;system.users 可代撤销)

验收:

  • draft → submitted/reviewing;workflow_instance/task/history 创建完整
  • delegation_grants 可被创建/查询/撤销;所有变更写入 audit_logs

Milestone 7:审批动作(approve/reject/return/withdraw/transfer)

范围:

  • approval_rules 匹配审批链(3 条默认规则)
  • POST /api/workflow/tasks/:taskId/approve|reject|return
  • POST /api/workflow/tasks/:taskId/transfer(reason≥10;链路≤3)
  • 审计:动作写入 workflow_history;关键例外写 audit_logs

验收:

  • 审批推进正确;转审三处证据齐全;状态与任务一致(status=reviewing 但节点来自 task)

Milestone 8:付款标记 + 发票判重例外 + 发票池归档

范围:

  • POST /api/reimbursements/:id/pay(需 expense.finance.pay)
  • 付款完成联动:将该报销单绑定的发票池条目归档(status=archived, archived_reason=used_complete)
  • 发票双策略判重 + 例外(仅 finance_mgr,需原单号+原因,原单 approved/paid 禁止)

验收:

  • approved → paid;发票池条目自动归档为 used_complete;例外受限且审计完整

Milestone 9:最小 CI 门槛(护栏)

范围:

  • typecheck + lint(不改写源码)
  • 最小集成测试:登录/发票池上传+OCR+绑定/提交/审批/转审/判重/付款标记/归档
  • 安全回归:敏感字段脱敏测试(银行卡/身份证等字段在所有对外响应均为脱敏格式;审计日志禁止明文)

验收:

  • CI 通过:typecheck + lint + 最小集成测试 + 脱敏测试全绿

3. Phase 2(扩展)

  • OCR、企微/钉钉通知、报表导出
  • 对象存储(MinIO/OSS)
  • 工作流扩展到其他实体(请假/采购)

4. 风险与阻塞项(P0)

  • 财务对“费用类型/科目默认值”仍可能需要微调:通过 expense_types 配置解决,避免改代码
  • 转审/例外权限属于高风险动作:必须上线前完成审计与权限回归测试