npm package: @netpad/netpad-ext-approval-gate
Description: Human-in-the-loop approval workflow extension for NetPad
Author: NetPad Team
Latest version: 1.0.3

# @netpad/netpad-ext-approval-gate

Human-in-the-loop approval workflow extension for NetPad.

## Overview

This extension provides an **Approval Gate** workflow node that pauses workflow execution until a human approves, rejects, or takes other action. Perfect for:

- 💰 **Expense approvals** — Route spending requests to managers
- 🔐 **Access requests** — Get sign-off before granting permissions  
- 📝 **Content review** — Approve blog posts, marketing materials
- 👤 **HR workflows** — Hiring approvals, PTO requests
- ⚙️ **Configuration changes** — Approve production deployments

## Features

### Multiple Approver Strategies

| Strategy | Description |
|----------|-------------|
| **Any** | First approver to decide completes the request |
| **All** | Every designated approver must approve |
| **Majority** | More than 50% must approve |
| **Sequential** | Approvers must act in order (Manager → Director → VP) |

### Configurable Timeouts

Set automatic actions when approvers don't respond:

- **Auto-Approve** — Proceed if no response
- **Auto-Reject** — Decline if no response
- **Escalate** — Route to a higher authority
- **Expire** — Cancel the request

### Notification Channels

- ✉️ **Email** — Send approval request emails with direct action links
- 🔗 **Webhook** — Integrate with Slack, Teams, or custom systems
- 🔔 **In-App** — Dashboard shows pending approvals (coming soon)

### Full Audit Trail

Every action is logged:
- Who created the request
- Who was notified
- When reminders were sent
- Who made decisions (with comments)
- Final outcome and timing

## Installation

```bash
npm install @netpad/netpad-ext-approval-gate
```

Or with yarn:

```bash
yarn add @netpad/netpad-ext-approval-gate
```

## Quick Start

### 1. Register the Extension

```typescript
// In src/lib/extensions/loader.ts
import approvalGateExtension from '@netpad/netpad-ext-approval-gate';

const extensions = [
  approvalGateExtension,
  // ... other extensions
];

export default extensions;
```

### 2. Use in a Workflow

Once registered, the **Approval Gate** node appears in the workflow editor palette under the **Logic** category.

#### Basic Expense Approval Workflow

```
[Form Trigger: Expense Report]
         ↓
[Approval Gate]
  • Title: "Expense: {{formData.description}}"
  • Category: Expense
  • Approver: {{formData.managerEmail}}
  • Timeout: 72 hours → Escalate
         ↓
    ┌────┴────┐
    ↓         ↓
[Approved] [Rejected]
    ↓         ↓
[Process]  [Notify
 Payment]   Requester]
```

### 3. Handle Decisions via API

When an approver makes a decision:

```typescript
// POST /api/ext/approval-gate/requests/APR-2026-ABC123/decide
{
  "decision": "approve",
  "comments": "Looks good, approved for Q4 budget."
}
```

## Node Configuration

### Basic Settings

| Field | Type | Description |
|-------|------|-------------|
| `title` | text | Request title (supports `{{variables}}`) |
| `description` | textarea | Additional context for approvers |
| `category` | select | General, Expense, Access, Content, HR, Config |
| `priority` | select | Low, Medium, High, Critical |

### Approver Settings

| Field | Type | Description |
|-------|------|-------------|
| `approverType` | select | How to determine approvers |
| `staticApprovers` | textarea | Email addresses (one per line) |
| `approverRole` | text | Role name for role-based lookup |
| `dynamicApproverExpression` | expression | Expression resolving to email(s) |
| `approverStrategy` | select | Any, All, Majority, Sequential |

### Timeout Settings

| Field | Type | Description |
|-------|------|-------------|
| `timeoutEnabled` | boolean | Enable automatic timeout |
| `timeoutHours` | number | Hours before timeout (default: 72) |
| `timeoutAction` | select | What to do on timeout |
| `escalateTo` | text | Email for escalation |

### Notification Settings

| Field | Type | Description |
|-------|------|-------------|
| `sendEmailNotification` | boolean | Send email to approvers |
| `sendWebhookNotification` | boolean | Send webhook on events |
| `webhookUrl` | text | Webhook endpoint URL |

### Data Settings

| Field | Type | Description |
|-------|------|-------------|
| `includeFormData` | boolean | Show form submission to approvers |
| `includePreviousNodeData` | boolean | Include previous node outputs |
| `customFieldsExpression` | json | Custom fields as JSON |

## Output Handles

The node has five output handles for routing based on decision:

| Handle | Description |
|--------|-------------|
| `approved` | Request was approved |
| `rejected` | Request was rejected |
| `escalated` | Request was escalated to another approver |
| `expired` | Request timed out |
| `info-requested` | Approver requested more information |

## API Endpoints

The extension registers these API endpoints under `/api/ext/approval-gate/`:

### GET /api/ext/approval-gate/pending

Get pending approvals for the current user.

```typescript
// Response
{
  "success": true,
  "approvals": [...],
  "total": 5,
  "stats": {
    "pending": 5,
    "overdue": 1,
    "decidedToday": 3
  }
}
```

### GET /api/ext/approval-gate/requests/:requestId

Get details of a specific approval request.

### POST /api/ext/approval-gate/requests/:requestId/decide

Record a decision on an approval request.

```typescript
// Request
{
  "decision": "approve" | "reject" | "escalate" | "request-info" | "delegate",
  "comments": "Optional comments",
  "conditions": "Optional conditions for conditional approval",
  "delegateTo": "email@example.com",
  "delegateReason": "Out of office"
}
```

### GET /api/ext/approval-gate/stats

Get approval statistics for the organization.

## Webhook Payload

When webhook notifications are enabled, this payload is sent:

```json
{
  "event": "approval_request_created",
  "timestamp": "2026-01-23T14:30:00Z",
  "request": {
    "requestId": "APR-2026-ABC123",
    "title": "Expense Report: Q4 Marketing",
    "category": "expense",
    "priority": "high",
    "status": "pending",
    "requester": {
      "name": "Jane Smith",
      "email": "jane@company.com"
    }
  },
  "links": {
    "view": "https://app.netpad.io/approve/...",
    "approve": "https://app.netpad.io/approve/.../approve",
    "reject": "https://app.netpad.io/approve/.../reject"
  }
}
```

## Examples

### Dynamic Approver from Form Data

```
Approver Type: Dynamic
Expression: {{formData.managerEmail}}
```

### Multi-Level Approval Chain

Create two Approval Gate nodes in sequence:

```
[Approval Gate 1: Manager]
  Strategy: Any
         ↓ (approved)
[Approval Gate 2: Finance Director]
  Strategy: Any
         ↓ (approved)
[Process Payment]
```

### Conditional Approval with Amount Threshold

```
[Switch Node]
  If amount > $5000: → [Senior Approval Gate]
  Otherwise: → [Standard Approval Gate]
```

### Slack Notification Integration

```
Webhook URL: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX
```

The webhook payload can be used with Slack's Incoming Webhooks to post approval requests to a channel.

## Roadmap

### v1.1 (Planned)
- [ ] Conditional approvals (approve with conditions)
- [ ] Bulk approve/reject from dashboard
- [ ] Mobile push notifications
- [ ] Approval templates

### v1.2 (Planned)
- [ ] Multi-level approval chains (built-in)
- [ ] Out-of-office auto-delegation
- [ ] SLA reporting dashboard
- [ ] Custom approval forms

### Future
- [ ] AI-assisted decision suggestions
- [ ] Risk scoring
- [ ] External approvers (non-NetPad users)
- [ ] Blockchain audit trail

## License

MIT

## Contributing

Contributions are welcome! Please read our contributing guidelines before submitting a PR.

## Support

- 📚 [Documentation](https://docs.netpad.io/extensions/approval-gate)
- 💬 [Discord Community](https://discord.gg/netpad)
- 🐛 [Issue Tracker](https://github.com/mrlynn/netpad-3/issues)