Skip to content

[Workflow] Approval Engine — Leave / Claim / Payment via n8n + PulseBox #23

@weilies

Description

@weilies

Context

Approval workflows (Leave Request, Claim, Payment Request) are the most complex feature on the roadmap. This issue specifies the architecture — using n8n PRO as the routing engine and PulseBox as the data/UI layer. No new workflow designer is built — PulseBox provides the data model, status management, and inbox UI; n8n handles routing logic.


Core Principle

PulseBox collection = the form/entity. n8n = the routing brain. They communicate via webhooks + REST API.


Data Model Additions

Status field type enhancement

Collections with approval workflows use a `status` field with locked transitions — not all status changes are allowed from UI directly. Transitions are driven by n8n callbacks.

Add `workflow_enabled` and `workflow_config` to collection metadata:
```json
{
"workflow_enabled": true,
"workflow_config": {
"n8n_workflow_id": "abc123",
"status_field": "status",
"status_transitions": {
"draft": ["submit"],
"pending_l1": [],
"pending_l2": [],
"approved": [],
"rejected": []
},
"submittable_statuses": ["draft"],
"terminal_statuses": ["approved", "rejected"]
}
}
```

`workflow_instances` table

```sql
create table workflow_instances (
id uuid primary key default gen_random_uuid(),
collection_id uuid not null references collections(id),
item_id uuid not null,
tenant_id uuid not null references tenants(id),
current_status text not null,
current_approver_id uuid references auth.users(id),
n8n_execution_id text,
submitted_at timestamptz,
completed_at timestamptz,
created_at timestamptz default now(),
updated_at timestamptz default now()
);
```

`workflow_events` table (audit trail)

```sql
create table workflow_events (
id uuid primary key default gen_random_uuid(),
instance_id uuid not null references workflow_instances(id),
event_type text not null, -- submitted | approved_l1 | approved_l2 | rejected | delegated | escalated
actor_id uuid references auth.users(id),
comment text,
metadata jsonb,
created_at timestamptz default now()
);
```


Flow

```

  1. Requester fills form in PulseBox (Leave Request collection item)

  2. Hits "Submit" → status changes to "pending_l1"
    → Supabase DB trigger fires: POST n8n webhook { item_id, collection_slug, tenant_id, submitter_id }

  3. n8n workflow:
    → reads item data via PulseBox API (GET /api/collections/leave-requests/items/{id})
    → determines approver (from collection data, org hierarchy, or config)
    → sends notification to approver (email / Lark message)
    → waits for approval webhook (n8n "Wait" node)

  4. Approver opens PulseBox Approver Inbox → clicks Approve/Reject
    → PulseBox: POST /api/automata/workflow/[instance_id]/respond { decision, comment }
    → Server action: validate approver, advance status, resume n8n wait node

  5. n8n resumes:
    → If multi-level: advance to L2, notify next approver, wait again
    → If final: mark approved/rejected, POST back to PulseBox
    → PulseBox updates item status to "approved" or "rejected"
    → Creates workflow_events record
    ```


UI Changes Required

1. Submit button on collection item

When `workflow_enabled: true` and item is in a submittable status:

  • Show "Submit for Approval" button (distinct from Save)
  • Confirmation dialog: "Submit this Leave Request for approval?"
  • After submit: status locked from manual edit

2. Approver Inbox

Route: `/dashboard/inbox`

  • Lists all items where current user is the pending approver
  • Columns: Type, Requester, Submitted, Summary, Days pending, Actions
  • Quick approve/reject from row (opens dialog for comment)
  • Click row → opens item detail with full form (read-only) + approval action panel

3. Requester status tracking

  • On item detail: show timeline of events (submitted, L1 approved, L2 pending, etc.)
  • "Recall" button if status is pending and not yet actioned

n8n Workflow Strategy

Next Novas vibe-codes approval workflows per use case:

  • `next-novas.leave-approval-2l` — 2-level leave approval
  • `next-novas.claim-approval-1l` — 1-level claim approval
  • `next-novas.payment-approval-3l` — 3-level payment approval

These are published as platform apps (via #19 App Store), installed by tenants, and linked to their specific collections.

Tenants configure via Automata:

  • Which collection this workflow applies to
  • Who the L1/L2 approvers are (role or specific user)
  • Escalation timeout (e.g. 48h → auto-escalate)
  • Notification template (email subject, body)

Acceptance Criteria

  • workflow_instances + workflow_events tables created with RLS
  • Submit button appears on workflow-enabled collections
  • Submit action changes status + fires n8n webhook
  • Approver inbox shows pending items
  • Approve/reject action resumes n8n wait node
  • Workflow event timeline visible on item detail
  • TypeScript clean

Note

This is a Phase 5+ feature — do not start until #18, #19, #20 are complete and stable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementImprovement to existing feature

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions