feat: support multi-approver steps with ANY/ALL policy

- ApprovalStep now has candidates + ApprovalPolicy (ANY/ALL) instead of a single assignee; ApprovalStep.single(...) kept as a convenience factory for the single-approver case
- AssigneeResolver resolves per-candidate; TaskStatus gains SKIPPED for auto-skipped sibling tasks
- DefaultOrdoEngine creates one task per candidate and advances per-step according to policy (ANY: first approval wins and skips the rest, only rejects once everyone rejects; ALL: fail-fast on first rejection, only advances once everyone approves)
- Added ApprovalTaskRepository.findByInstanceIdAndStepId and JDBC/in-memory implementations
- Added V2 migration: ordo_approval_step.policy column + ordo_step_candidate table
- Updated ApprovalStepMapper/ApprovalTaskMapper/JdbcProcessDefinitionRepository for the new schema, handling null action for SKIPPED tasks
- Migrated all call sites (tests, ordo-example, rhizome demo) to ApprovalStep.single(...) and the 3-arg AssigneeResolver
- Added ANY/ALL policy test coverage; fixed JdbcTestSupport to apply the V2 migration and strip SQL comments before splitting on ';'
This commit is contained in:
0264408
2026-09-10 18:20:33 +08:00
parent c524c74289
commit 581823290a
22 changed files with 440 additions and 90 deletions
@@ -16,8 +16,8 @@ public final class LeaveRequestExample {
public static void main(String[] args) {
OrdoEngine ordo = new InMemoryOrdoEngine();
ordo.register(new ProcessDefinition("leave-request", "Leave request", List.of(
new ApprovalStep("manager", "Manager approval", "maria"),
new ApprovalStep("hr", "HR approval", "henry")
ApprovalStep.single("manager", "Manager approval", "maria"),
ApprovalStep.single("hr", "HR approval", "henry")
)));
var instance = ordo.start("leave-request", "alice", new ProcessContext(Map.of(