Skip to content
bitzorcas
中EN

Tutorial

配置第一条审批工作流:重大案件合伙人联签实战

使用 BitzOrcas.Modern 自研轻量级 DAG 状态机工作流引擎,为律所重大案件(标的额 5000 万以上)配置包含条件分支网关、合伙人联签与不可篡改审计时间线的审批流。

Last updated

在许多企业级业务开发中,开发者为了“图快”,习惯于将审批流转逻辑硬编码在业务表中(例如在 Controller 里面直接写 matter.Status = 2)。这种做法在业务初期看似简单,但随着企业管理精细化,致命痛点迅速爆发:

  • 分支风暴与状态死锁:一旦管理层增加规则(如“涉案标的额 $\ge 5000$ 万须由主任合伙人与首席风控官联签”、“外资客户须先经过利益冲突豁免审批”),业务代码中将充斥着多层嵌套的 if/else;
  • 审计断裂与合规追责风险:业务字段直接被 UPDATE 覆盖,无法追溯“谁在什么时间、基于何种意见批准了该案件”,在司法合规审计中直接判定为重大缺陷。

BitzOrcas.Modern 内置了自研轻量级有向无环图(DAG)工作流引擎。引擎通过解耦的运行时流转端口(IWorkflowTransitionFlow)、原子维护的 FlowState 状态机,以及不可篡改的流水线审批审计轨迹,让复杂的多租户审批流程像搭积木一样安全落地。

本教程将以真实的律所重大民商事诉讼立案(标的额 $\ge 5000$ 万)主任合伙人与风控官联签审批为背景,带你完整实现一条企业级审批流。

重大案件审批工作流 DAG 拓扑图

存在潜在相对方冲突无利益冲突是 (标的额 = 50M 重大案件)否 (常规民商事案件)审批通过审批通过驳回退回驳回退回

1. 提交立案申请 (SubmitMatterIntake)

2. 利益冲突审查网关 (自动化筛查)

3. 签署利益冲突豁免书 (Conflict Waiver)

4. 标的额条件网关 (ClaimAmount >= 50,000,000?)

5. 主任合伙人 & 首席风控官双人联签 (Countersign)

6. 业务主管合伙人审批 (Single-Sign)

7. 审批归档:自动落盘卷宗编号并触发 CAP 通知

8. 审批驳回:退回主办律师并冻结立案草稿


核心流转端口:IWorkflowTransitionFlow

在 BitzOrcas.Modern 中,工作流的核心操作不直接依赖庞大的单体服务,而是由专注的 IWorkflowTransitionFlow 端口提供状态推进能力:

核心 API 方法业务语义状态与审计保障
StartAsync(...)业务发起工作流实例校验定义版本有效性,原子生成 InstanceId 并压入第一批就绪任务
CompleteTaskAsync(...)审批人完成/通过当前任务校验用户席位与授权,评估会签/或签规则并推进 DAG 游标至下游节点
RejectTaskAsync(...)审批人驳回当前任务支持退回至发起人或指定前置节点,记录不可篡改的驳回意见
WithdrawAsync(...)申请人主动撤回实例仅限特定未流转节点由申请人发起,安全回收全部未决审批任务

第一步:编写立案审批流发起命令(Start Workflow)

在业务切片中,当主办律师提交民商事立案申请后,通过 IWorkflowTransitionFlow.StartAsync 启动审批流水线:

src/Modules/Business/Legal/Application/Commands/SubmitMatterForApproval/SubmitMatterForApprovalCommandHandler.cs
using BitzOrcas.Application.Abstractions.Tenancy;
using BitzOrcas.Application.Security;
using BitzOrcas.Domain.Results;
using BitzOrcas.Modules.Legal.Domain;
using BitzOrcas.Workflow.Abstractions.Services;
using Mediator;
namespace BitzOrcas.Modules.Legal.Application.Commands.SubmitMatterForApproval;
public sealed record SubmitMatterForApprovalCommand(
string MatterId,
decimal ClaimAmount,
bool HasPotentialConflict) : ICommand<Result<string>>;
public sealed class SubmitMatterForApprovalCommandHandler(
IWorkflowTransitionFlow workflowTransition,
ICurrentTenant currentTenant,
ICurrentUser currentUser) : ICommandHandler<SubmitMatterForApprovalCommand, Result<string>>
{
public async ValueTask<Result<string>> Handle(
SubmitMatterForApprovalCommand request,
CancellationToken cancellationToken)
{
var tenantId = currentTenant.Tenant.EffectiveTenantId;
var starterId = currentUser.UserId;
// 组装工作流路由变量:用于 DAG 网关评估条件分支
var workflowVariables = new Dictionary<string, object?>
{
["MatterId"] = request.MatterId,
["ClaimAmount"] = request.ClaimAmount,
["HasPotentialConflict"] = request.HasPotentialConflict,
["IsMajorMatter"] = request.ClaimAmount >= 50_000_000.00m
};
// 委托 IWorkflowTransitionFlow 发起流程实例
var startResult = await workflowTransition.StartAsync(
definitionKey: "WF_LEGAL_MATTER_APPROVAL",
businessKey: request.MatterId,
businessType: "LegalMatterIntake",
starterId: starterId,
tenantId: tenantId,
officeId: null,
variables: workflowVariables,
cancellationToken: cancellationToken);
if (startResult.IsFailure)
{
return Result<string>.Failure(startResult.Error);
}
var instance = startResult.GetValueOrThrow();
return Result<string>.Success(instance.Id);
}
}

第二步:审批人处理任务(通过与驳回)

当主任合伙人登录管理后台后,调用任务流转 API 完成审批决策:

src/Modules/Business/Legal/Application/Commands/ApproveMatterTask/ApproveMatterTaskCommandHandler.cs
using BitzOrcas.Application.Security;
using BitzOrcas.Domain.Results;
using BitzOrcas.Workflow.Abstractions.Services;
using Mediator;
namespace BitzOrcas.Modules.Legal.Application.Commands.ApproveMatterTask;
public sealed record ApproveMatterTaskCommand(
string TaskId,
string ApprovalComment) : ICommand<Result>;
public sealed class ApproveMatterTaskCommandHandler(
IWorkflowTransitionFlow workflowTransition,
ICurrentUser currentUser) : ICommandHandler<ApproveMatterTaskCommand, Result>
{
public async ValueTask<Result> Handle(
ApproveMatterTaskCommand request,
CancellationToken cancellationToken)
{
var userId = currentUser.UserId;
// 调用流转端口完成任务;引擎将原子校验会签进度,并在全部联签完成后自动流转至下游节点
var transitionResult = await workflowTransition.CompleteTaskAsync(
taskId: request.TaskId,
userId: userId,
comment: request.ApprovalComment,
variables: null,
cancellationToken: cancellationToken);
return transitionResult;
}
}

若风控官发现案件当事人存在利益冲突,则可直接发起驳回退回:

任务驳回示例
// 驳回至主办律师,指定驳回原因
var rejectResult = await workflowTransition.RejectTaskAsync(
taskId: request.TaskId,
userId: currentUser.UserId,
comment: "检测到相对方为本所常年法律顾问客户,存在法定利益冲突,请先办理豁免手续。",
targetNodeId: null, // null 表示根据节点配置的 RollbackRule 原路回退至发起人
cancellationToken: cancellationToken);

第三步:端到端工作流集成测试验证

在自动化测试套件中,验证重大案件触发双人联签网关的流转事实:

tests/BitzOrcas.Integration.Tests/Legal/MatterWorkflowIntegrationTests.cs
using BitzOrcas.Modules.Legal.Application.Commands.SubmitMatterForApproval;
using BitzOrcas.Workflow.Abstractions.Engine;
using Shouldly;
using Xunit;
public sealed class MatterWorkflowIntegrationTests : IClassFixture<CustomWebApplicationFactory>
{
private readonly IWorkflowEngine _engine;
public MatterWorkflowIntegrationTests(CustomWebApplicationFactory factory)
{
_engine = factory.GetRequiredService<IWorkflowEngine>();
}
[Fact]
public async Task MajorMatter_Over50Million_ShouldRequirePartnerCountersign()
{
// 1. 模拟提交涉案标的额 6000 万的重大民商事诉讼
var transition = _engine.RuntimeTransition;
var variables = new Dictionary<string, object?>
{
["ClaimAmount"] = 60_000_000.00m,
["HasPotentialConflict"] = false
};
var startResult = await transition.StartAsync(
definitionKey: "WF_LEGAL_MATTER_APPROVAL",
businessKey: "MAT-20260923-9999",
businessType: "LegalMatterIntake",
starterId: "lawyer_001",
tenantId: "1000001",
officeId: null,
variables: variables,
cancellationToken: CancellationToken.None);
startResult.IsSuccess.ShouldBeTrue();
var instanceId = startResult.GetValueOrThrow().Id;
// 2. 机器断言:网关正确分流至重大案件联签节点
var tasksResult = await _engine.Tasks.GetActiveTasksByInstanceIdAsync(instanceId, CancellationToken.None);
tasksResult.IsSuccess.ShouldBeTrue();
var activeTasks = tasksResult.GetValueOrThrow();
activeTasks.Count.ShouldBe(2); // 主任合伙人任务 + 首席风控官联签任务
activeTasks.ShouldContain(t => t.TaskName == "主任合伙人审批");
activeTasks.ShouldContain(t => t.TaskName == "首席风控官联签");
}
}

核心设计收益

  1. 业务与流程彻底解耦:业务切片仅需触发 StartAsync 并透传业务事实(标的额、利冲标识),审批路线与加签规则完全由工作流定义引擎维护;
  2. 审计痕迹不可篡改:每个任务的批准时间戳、审批人数字签名与评审意见均在事务中记录并加密归档,完美满足律所司法合规审计;
  3. 高并发状态机:基于细粒度流转端口 IWorkflowTransitionFlow,消除了全局状态锁竞争,支持海量多租户流程并行推进。

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%