Customizable approval and rejection thresholds for parallel steps, with optional required approvers
Description
Parallel steps currently require unanimous approval. This ticket extends them with two capabilities:
-
Configurable thresholds: define how many approvals are required for the step to pass, and how many rejections are required for the step to fail.
-
Required approvers: optionally mark specific sub-steps as required, so the step cannot pass without their approval, regardless of the threshold count.
Because thresholds can conclude a parallel step before all sub-steps have voted, a new terminal sub-step status SKIPPED is introduced to clearly distinguish sub-steps that were closed without action from those that were explicitly approved or rejected.
The current unanimous behavior is preserved as the default mode, ensuring backward compatibility with existing definitions.
Acceptance criteria
-
The parallel step edit form offers two approval modes: All sub-steps must approve (default, matches current behavior) and Custom rules.
-
In Custom rules mode, the user can configure the number of approvals required to pass and the number of rejections required to fail the step.
-
In Custom rules mode, the user can mark individual sub-steps as required directly on the canvas. A required sub-step must approve for the parallel step to pass; a rejection from any required sub-step fails the parallel step regardless of thresholds.
-
In All sub-steps must approve mode, threshold inputs and required-approver controls are disabled and not editable.
-
Threshold values are validated so the configured rules can always be reached given the number of eligible sub-steps.
-
A new sub-step status
SKIPPEDis introduced. It is a terminal status applied to sub-steps that did not receive a decision before the parent parallel step concluded because the configured threshold was already met. -
Sub-steps in
SKIPPEDstatus are accompanied by askipReasonfield. Initial value:THRESHOLD_MET. The field is modeled as an extensible enum to accommodate future skip reasons (e.g. admin skip, conditional skip) without introducing additional statuses. -
SKIPPEDsub-steps are rendered with a dedicated, neutral icon. The row text is visually de-emphasized to signal passive closure. A tooltip explains the reason (e.g. "Skipped — voting threshold was reached without this step"), with PL and EN translations. -
The approval history and comments distinguish
SKIPPEDsub-steps from approvals and rejections, including the skip reason. -
Within complex (nested or sequential) definitions, votes recorded in a parallel step affect only that step's outcome and do not directly conclude the entire approval definition.
-
Existing parallel step definitions continue to behave exactly as before, with no manual migration required from end users. No existing sub-step records are retroactively transitioned to
SKIPPED. -
The parallel step header displays a short summary of the active configuration (e.g., All must approve or 3 to pass · 2 to fail · 2 required).
Out of scope
-
Nested parallel groups (not currently supported in the product).
-
Additional skip reasons beyond
THRESHOLD_MET(the enum is designed to be extensible, but no other reasons are implemented in this ticket).
Notes:
UI proposition:
You'll need to add the parallel step data to the database - we need to maintain information about the number of required votes. Let's add a step name and a color selection. We should be backward compatible with the currently existing definitions - if there's no entry in the new table, use the default values.
Skipped steps within a parallel step should be marked with a gray icon with a "-" and a tooltip indicating that it was skipped because the group step threshold was met without that step.
For the parallel step in the UI, add its name and information about the threshold set/achieved within it in the tooltip.
Also, add a new step status: SKIPPED.
Also consider the possibility of adding nested parallel steps in the future (one level of nesting is possible) - there's a separate ticket for that later.