v1.0

Approval Workflow System

Multi-step approval workflows with role-based and user-specific verification.


Overview

The Approval Workflow System enables you to create multi-step approval processes for any entity in your application (e.g., leave requests, expenses, purchase orders). Each step can be verified by a specific role or user.

Key Features


Database Schema

TablePurpose
approval_definitionsWorkflow templates (name, entity_type, description)
approval_definition_stepsSteps within a workflow (order, verifier_type, verifier_id, label)
approval_requestsActive workflow instances (status, current_step, entity reference)
approval_interactionsAudit log of all actions (approve/reject with comments)

Setup Multi-Level Verification

To establish a multi-level approval process (e.g., User -> Manager -> HR), you need to define Approval Rules. The system uses these rules to generate the required steps when a workflow starts.

Configuration via Admin UI (Web GUI)

You can configure approval workflows directly from the Admin Panel without writing code. The system allows you to define multi-step processes dynamically.

  1. Navigate to Admin > Workflows > Create Workflow (/admin/workflows/create).
  2. Select the Entity Type (e.g., "Leave Request") and give it a name.
  3. Use the "Add Step" button to define the approval hierarchy:
    • Step 1: Select "Role" -> "Manager". Label it "Manager Approval".
    • Step 2: Select "Role" -> "HR". Label it "HR Verification".
    • Step 3: Select "User" -> "CEO" (optional). Label it "Final Sign-off".
  4. Click Create Workflow to save.

The system automatically saves these definitions to the approval_definitions table and uses them whenever a new request is started for that entity type. You can view and manage existing workflows at /admin/workflows.

How it works

  1. When startWorkflow() is called, the system fetches all rules for the given `permissionId`.
  2. It creates Approval Steps for each rule, ordered by `sortOrder`.
  3. Step 1 becomes PENDING. Steps 2+ map to BLOCKED or waiting status.
  4. When Level 1 approves, Level 2 becomes PENDING automatically.

Usage

1. Create a Workflow Definition (Admin UI)

Navigate to /admin/workflows/create and define:

2. Start a Workflow (Code)

use App\Domain\Approval\Services\ApprovalService;

$approvalService = new ApprovalService();

// When a leave request is submitted
$requestId = $approvalService->startWorkflow(
    entityType: 'leave_request',
    entityId: $leaveRequest->id,
    requesterId: auth()->id()
);

if ($requestId) {
    // Workflow started, request is now pending
}

3. View Pending Approvals

Users can view items waiting for their approval at /admin/approvals

// Get pending items for current user
$pending = $approvalService->getPendingItems($userId, $roleIds);

4. Approve or Reject

// Approve (moves to next step or marks as approved)
$approvalService->approve($requestId, $userId, 'Looks good!');

// Reject (marks entire request as rejected)
$approvalService->reject($requestId, $userId, 'Budget exceeded');

Service Methods

MethodDescription
startWorkflow($entityType, $entityId, $requesterId)Initiates a new approval request based on the workflow definition for the entity type
getPendingItems($userId, $roleIds)Returns pending requests where the user (or their roles) is the current step verifier
approve($requestId, $userId, $comment)Approves the current step. Advances to next step or marks as fully approved.
reject($requestId, $userId, $comment)Rejects the request. Marks status as 'rejected'.

Admin Routes

RouteDescriptionPermission
/admin/workflowsList all workflow definitionsworkflows.manage
/admin/workflows/createCreate new workflowworkflows.manage
/admin/workflows/testCreate test workflow and requestworkflows.manage
/admin/approvalsView pending approvals for current userapprovals.view
/admin/approvals/actionApprove/Reject action endpointapprovals.view

Integration Example

To integrate with an existing entity (e.g., Leave Request):

// In LeaveRequestService or Controller after creating a leave request:

class LeaveRequestService
{
    private ApprovalService $approvalService;
    
    public function submitLeaveRequest(LeaveRequest $request): int
    {
        // Save the leave request
        $leaveId = $this->leaveRepo->save($request);
        
        // Start approval workflow
        $this->approvalService->startWorkflow(
            entityType: 'leave_request',
            entityId: $leaveId,
            requesterId: $request->userId
        );
        
        return $leaveId;
    }
}
Tip: Make sure to create a workflow definition for the entity type (e.g., "leave_request") in the admin panel before starting workflows.
ESC

Start typing to search the documentation