Change record status: 
Project: 
Introduced in branch: 
1.6.0
Introduced in version: 
1.x
Description: 

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.

Impacts: 
Site builders, administrators, editors
Module developers