跳到内容

审批工作流

受众:开发者 摘要:审批 / 复核 / 工单状态机 starter,用于统一状态动作、权限校验、附件、审计和超时处理计划。

spring-open-starter-approval-workflow 提供一个轻量同步状态机。它不保存业务表,也不执行 Admin 审批动作;业务模块定义流程和动作,调用 starter 执行动作校验,再把返回的状态、审计记录和超时计划保存到自己的实体或任务中。spring-open-core-approval-workflow 负责后台只读运维台,读取 ApprovalWorkflowCatalog 的流程目录快照和 ApprovalInbox 的跨模块待办摘要,不直接暴露业务审批实例表。

适用场景

场景推荐
内容安全复核、CMS 内容审核、商城售后审批使用审批工作流
提现、结算、广告投放、商户入驻等人工复核使用审批工作流
只是一串同步规则,当前规则决定是否继续使用 责任链
固定步骤编排,没有人工状态流转使用 管道
方法外层审计、指标、鉴权增强使用 钩子

快速接入

1. 引入 Starter

xml
<dependency>
    <groupId>com.springopen</groupId>
    <artifactId>spring-open-starter-approval-workflow</artifactId>
</dependency>

如果业务需要审批工作流能力,请显式引入 spring-open-starter-approval-workflow;框架不再提供 all-in-one starter 兜底。

2. 定义流程

java
@Bean
ApprovalWorkflowDefinition contentReviewWorkflow() {
    return ApprovalWorkflowDefinition.builder()
            .workflow("content.review")
            .name("内容审核")
            .description("内容提交、通过、驳回和超时自动处理")
            .action(ApprovalActionDefinition.builder()
                    .code("submit")
                    .fromStatus("draft")
                    .toStatus("pending")
                    .requiredPermission("cms:content:update")
                    .timeout(Duration.ofHours(24))
                    .timeoutAction("auto-approve")
                    .build())
            .action(ApprovalActionDefinition.builder()
                    .code("approve")
                    .fromStatus("pending")
                    .toStatus("approved")
                    .requiredPermission("cms:content:review")
                    .build())
            .action(ApprovalActionDefinition.builder()
                    .code("reject")
                    .fromStatus("pending")
                    .toStatus("rejected")
                    .requiredPermission("cms:content:review")
                    .remarkRequired(true)
                    .build())
            .build();
}

workflowaction.code 必须稳定。它们会进入审计、配置、任务和后续 Admin 展示。

3. 执行动作

java
ApprovalActionResult result = ApprovalWorkflow.execute(ApprovalActionRequest.builder()
        .workflow("content.review")
        .subject(ApprovalSubject.builder()
                .type("cms-content")
                .id(contentId.toString())
                .title(title)
                .ownerId(authorId.toString())
                .build())
        .currentStatus(currentReviewStatus)
        .action("approve")
        .operatorId(currentUserId.toString())
        .operatorPermission("cms:content:review")
        .remark("内容合规")
        .traceId(traceId)
        .build());

content.setReviewStatus(result.getAfterStatus());
contentLogRepository.save(result.getAuditRecord());

if (result.getTimeoutPlan() != null) {
    reviewTimeoutTaskRepository.save(result.getTimeoutPlan());
}

业务模块仍负责事务、实体保存、日志落库、通知和调度任务。starter 返回的是可落库快照,不替业务模块持久化。

已接入试点

业务流程编码说明
CMS 内容审核cms.content.reviewCMS 定义提交、通过、驳回、自动通过和自动驳回动作,starter 校验状态、权限、驳回备注和超时计划,CMS 保存内容状态与操作日志。
Content Safety 复核content-safety.reviewContent Safety 复核任务校验人工通过 / 拒绝 / 关闭和超时自动处理动作,驳回必须填写备注;Content Safety 只保存检测日志审计字段,不直接修改业务对象状态。
Money 用户余额提现money.balance.withdraw提现审核通过、人工拒绝、进入处理、标记已打款、失败和取消动作先经审批工作流校验;拒绝必须填写备注,外部 payout / Web3 广播前会先校验 approved -> processing,原有冻结释放、出账流水和 txHash 校验仍由 Money Service 负责。
Money Web3 支付结算复核money.web3.payment-settlement.reviewWeb3 支付结算复核日志记录、超时自动通过 / 驳回、自动重试和手动执行结算先经审批工作流校验;工作流只校验动作、来源状态和权限快照,复核指纹、链上确认、订单条件更新、支付流水幂等、Outbox 和补偿仍由 Web3 Service 负责。
Mall 售后审批mall.after-sale.review售后通过、驳回、关闭、退货签收、标记退款成功和超时自动处理先经审批工作流校验;人工驳回必须填写说明,真实退款、余额流水和优惠券返还仍由 Mall 售后 Service 负责。
Mall 商户入驻mall.merchant.review商户提交、审核通过和驳回先经审批工作流校验;驳回必须填写说明,商户启停、店铺归属和角色模板仍由 Mall Service 负责。
Advertising 素材审核advertising.creative.review广告素材提审、审核通过和驳回先经审批工作流校验;内容安全预检、素材版本、审核日志和公开展示状态仍由 Advertising Service 负责。
Advertising 投放启停advertising.creative.delivery广告素材启用和暂停先经审批工作流校验,确保只在合法素材状态之间切换;预算扣费、结算和报表仍由 Advertising Service 负责。

Contract

类型说明
ApprovalWorkflow.execute(request)Facade 短入口
ApprovalWorkflowManager.execute(request)Spring Bean 入口
ApprovalWorkflowCatalog.list()已注册流程的只读目录快照,供 Admin 运维页、文档导出和 smoke 检查展示
ApprovalInbox.snapshot(query)跨模块待处理事项只读聚合快照,供 Admin 运维页或 smoke 检查展示
ApprovalInboxContributor业务模块贡献待处理摘要和待办项目的 SPI
ApprovalWorkflowDescriptor流程只读描述,包含流程编码、展示名、说明、动作数量、超时动作数量和动作清单
ApprovalActionDescriptor动作只读描述,包含来源状态、目标状态、权限、备注要求和超时计划摘要
ApprovalWorkflowDefinition流程定义
ApprovalActionDefinition动作定义,包含来源状态、目标状态、权限、备注和超时计划
ApprovalActionRequest动作请求
ApprovalActionResult动作结果
ApprovalAuditRecord审计快照
ApprovalTimeoutPlan超时自动处理计划
ApprovalAttachment附件引用
ApprovalSubject被审批业务对象引用

后台运维入口

spring-open-core-approval-workflow 默认随应用装配,提供只读后台运维入口:

项目
Admin APIGET /api/v1/admin/approval-workflow/operations
Admin 页面/approval-workflow/operations
菜单 codeapproval-workflow
权限approval-workflow:view

该页面展示:

  • 当前启动期已注册的 workflow、动作、权限、备注要求和超时计划摘要。
  • 各业务模块通过 ApprovalInboxContributor 贡献的待办来源、待处理数量和最近待办摘要。
  • runbook 提示,提醒管理员回到 owning module 的页面执行审批动作。

该入口只读,不执行审批、不创建通用审批实例表、不绕过业务模块权限。处理动作仍必须回到 CMS / Blog / Forum / Money / Mall / Advertising 等业务模块自己的后台 API 和 Service。

边界

  • 不保存数据库,不生成迁移。
  • 不接管业务实体状态字段。
  • 不直接发送通知。
  • 不直接创建 Scheduler 任务,只返回 ApprovalTimeoutPlan
  • 不做页面权限判断;动作权限只校验调用方传入的权限集合。
  • 不代替 Chain / Pipeline。审批工作流关心“状态动作能不能执行、执行后状态是什么”。
  • ApprovalWorkflowCatalog 只展示启动期流程定义,不展示待办数量、审批实例详情或业务敏感字段。
  • ApprovalInbox 只聚合各业务模块贡献的待处理摘要和跳转入口,不保存通用审批实例表,不执行审批动作,不替代业务模块的审核 / 复核 / 举报处理 API。
  • spring-open-core-approval-workflow 只把上述两个只读 contract 暴露到 Admin 运维台,不新增业务状态机,也不接管业务模块补偿逻辑。

统一待办聚合

业务模块可以实现 ApprovalInboxContributor,把自己的待审核内容、待处理举报或待复核记录贡献给统一待办快照:

业务来源source当前贡献内容处理入口
CMScmsreviewStatus=pending 的内容/cms/moderation?reviewStatus=pending
Blogblog草稿 / 内容安全降级草稿组成的待审文章摘要/blog/articles?status=0
Forumforum待处理举报/forum/reports?status=0

待办聚合只负责读取、排序、汇总和限制返回数量。处理动作仍回到各业务模块自己的后台页面和 Service,避免通用 starter 反向持有业务状态。

配置

yaml
spring:
  open:
    approval-workflow:
      enabled: true
配置默认值说明
spring.open.approval-workflow.enabledtrue是否启用审批工作流自动配置

后续接入建议

内容类低风险试点已经覆盖 CMS 内容审核和 Content Safety 复核;资金类首个试点已覆盖 Money 用户余额提现;交易类试点已覆盖 Mall 售后审批,广告素材审核 / 投放启停和 Mall 商户入驻也已作为高风险业务接入样板。后续再接新的高风险流程时,先明确业务状态字段、权限快照、审计落库、补偿 / 回滚和 Admin 操作入口,再逐个业务流程迁移。

Released under the Apache License 2.0.