Summary
The StateGraph-specific human-approval mechanism in flowdrop_stategraph is deprecated in
favor of the general human-in-the-loop (HITL) interrupt system in flowdrop_interrupt. All
ApprovalGate classes will be removed in FlowDrop 2.0.0.
The interrupt system provides the same pause-for-human-decision capability with persistent
storage, a REST API for resolving requests, playground UI integration, dedicated
permissions, and native gateway branching — and it already works under the StateGraph
orchestrator.
Deprecated
┌──────────────────────────────────────────┬──────────────────────────────────────────┐
│ Deprecated │ Replacement │
├──────────────────────────────────────────┼──────────────────────────────────────────┤
│ approval_gate node plugin │ confirmation node (simple │
│ (ApprovalGateNode) │ approve/reject) or form_input node │
│ │ (approval with notes/structured input) │
├──────────────────────────────────────────┼──────────────────────────────────────────┤
│ Drupal\flowdrop_stategraph\ApprovalGate\ │ Drupal\flowdrop_interrupt\Service\Interr │
│ ApprovalGateInterface │ uptManagerInterface │
├──────────────────────────────────────────┼──────────────────────────────────────────┤
│ Drupal\flowdrop_stategraph\ApprovalGate\ │ │
│ ApprovalGateHandler + service flowdrop_s │ flowdrop_interrupt.manager service │
│ tategraph.approval_gate_handler │ │
├──────────────────────────────────────────┼──────────────────────────────────────────┤
│ Drupal\flowdrop_stategraph\ApprovalGate\ │ Drupal\flowdrop_interrupt\Enum\Interrupt │
│ ApprovalStatus │ Status │
├──────────────────────────────────────────┼──────────────────────────────────────────┤
│ Drupal\flowdrop_stategraph\Exception\App │ Drupal\flowdrop_interrupt\Exception\Inte │
│ rovalRequiredException │ rruptRequiredException │
├──────────────────────────────────────────┼──────────────────────────────────────────┤
│ ApprovalGateRequestedEvent / │ flowdrop_interrupt interrupt lifecycle │
│ ApprovalGateApprovedEvent / │ events │
│ ApprovalGateRejectedEvent │ │
└──────────────────────────────────────────┴──────────────────────────────────────────┘
Workflow authors
Existing workflows containing an approval_gate node keep working throughout 1.x — and, as
a side effect of this change, become resolvable for the first time: the node now pauses
through the interrupt system, so pending approvals appear in the interrupt API
(/api/flowdrop/interrupts/...) and playground UI.
Migrate before 2.0.0 by replacing the node:
Before (deprecated):
{
"id": "gate",
"type": "approval_gate",
"config": {
"message": "Approve publishing this content?"
}
}
After:
{
"id": "gate",
"type": "confirmation",
"config": {
"message": "Approve publishing this content?",
"confirm_label": "Approve",
"cancel_label": "Reject"
}
}
Output mapping: approved → confirmed; approved_by/rejected_by → user_id; approved_at →
response_time. The confirmation node additionally emits gateway branch output, so
approve/reject routing no longer needs a separate gateway node.
For approvals that collect notes or structured data, use the form_input node with a JSON
Schema.
Module developers
Before (deprecated):
$handler = \Drupal::service('flowdrop_stategraph.approval_gate_handler');
$status = $handler->getStatus($requestId);
if ($status === ApprovalStatus::Approved) {
// ...
}
After:
$manager = \Drupal::service('flowdrop_interrupt.manager');
$interrupt = $manager->getInterrupt($interruptId);
if ($interrupt->getStatus() === InterruptStatus::Resolved) {
// ...
}
Code catching ApprovalRequiredException should catch InterruptExceptionInterface (or
InterruptRequiredException) instead — all pipeline-based orchestrators throw it uniformly.
Event subscribers on the ApprovalGate events should move to the interrupt lifecycle
events.
Note: the in-memory ApprovalGateHandler never persisted requests across requests, so no
stored data exists and no data migration is needed.