19 KiB
Skip Approver & Dynamic Approver Addition
Overview
This feature allows initiators and approvers to manage approval workflows dynamically when approvers are unavailable or additional approval is needed.
Key Features:
- Skip Approver - Skip non-responding approvers and move to next level
- Add Approver at Specific Level - Insert new approver at any position
- Automatic Level Shifting - Existing approvers are automatically renumbered
- Smart Validation - Cannot modify completed levels (approved/rejected/skipped)
- TAT Management - New approvers get their own TAT, jobs scheduled automatically
Use Cases
Use Case 1: Approver on Leave
Scenario:
Level 1: Sarah (Approved) ✅
Level 2: Mike (Pending) ⏳ ← On vacation, not responding
Level 3: Lisa (Waiting) ⏸️
Solution:
Initiator clicks "Skip This Approver" on Level 2
→ Mike is marked as SKIPPED
→ Level 3 (Lisa) becomes active
→ Lisa receives notification
→ TAT jobs cancelled for Mike, scheduled for Lisa
Result:
Level 1: Sarah (Approved) ✅
Level 2: Mike (Skipped) ⏭️ ← Skipped
Level 3: Lisa (In Review) ⏳ ← Now active
Use Case 2: Add Additional Reviewer
Scenario:
Level 1: Sarah (Approved) ✅
Level 2: Mike (In Review) ⏳
Level 3: Lisa (Waiting) ⏸️
Need: Add Finance Manager (John) between Mike and Lisa
Solution:
Click "Add Approver"
→ Email: john@example.com
→ TAT: 48 hours
→ Level: 3 (between Mike and Lisa)
→ Submit
Result:
Level 1: Sarah (Approved) ✅
Level 2: Mike (In Review) ⏳ ← Still at level 2
Level 3: John (Waiting) ⏸️ ← NEW! Inserted here
Level 4: Lisa (Waiting) ⏸️ ← Shifted from 3 to 4
Use Case 3: Replace Skipped Approver
Scenario:
Level 1: Sarah (Approved) ✅
Level 2: Mike (Skipped) ⏭️
Level 3: Lisa (In Review) ⏳
Need: Add replacement for Mike at level 2
Solution:
Click "Add Approver"
→ Email: john@example.com
→ TAT: 24 hours
→ Level: 2 (Mike's old position)
→ Submit
Result:
Level 1: Sarah (Approved) ✅
Level 2: John (Waiting) ⏸️ ← NEW! Inserted at level 2
Level 3: Mike (Skipped) ⏭️ ← Shifted from 2 to 3
Level 4: Lisa (In Review) ⏳ ← Shifted from 3 to 4
Database Schema
New Fields in approval_levels Table:
-- Migration: add_is_skipped_to_approval_levels.sql
ALTER TABLE approval_levels
ADD COLUMN is_skipped BOOLEAN DEFAULT FALSE,
ADD COLUMN skipped_at TIMESTAMP,
ADD COLUMN skipped_by UUID REFERENCES users(user_id),
ADD COLUMN skip_reason TEXT;
Status Enum Update:
Already includes SKIPPED status:
status ENUM('PENDING', 'IN_PROGRESS', 'APPROVED', 'REJECTED', 'SKIPPED')
Example Data:
-- Level 2 was skipped
SELECT
level_number,
approver_name,
status,
is_skipped,
skipped_at,
skip_reason
FROM approval_levels
WHERE request_id = 'xxx';
-- Results:
-- 1 | Sarah | APPROVED | FALSE | NULL | NULL
-- 2 | Mike | SKIPPED | TRUE | 2025-11-05 | On vacation
-- 3 | Lisa | PENDING | FALSE | NULL | NULL
API Endpoints
1. Skip Approver
Endpoint:
POST /api/v1/workflows/:id/approvals/:levelId/skip
Request Body:
{
"reason": "Approver on vacation - deadline approaching"
}
Response:
{
"success": true,
"message": "Approver skipped successfully",
"data": {
"levelId": "...",
"levelNumber": 2,
"status": "SKIPPED",
"skippedAt": "2025-11-05T10:30:00Z"
}
}
Logic:
- ✅ Mark level as
SKIPPED - ✅ Cancel TAT jobs for skipped level
- ✅ Activate next level (move to level+1)
- ✅ Schedule TAT jobs for next level
- ✅ Notify next approver
- ✅ Log activity
Validation:
- ❌ Cannot skip already approved/rejected/skipped levels
- ❌ Cannot skip future levels (only current level)
- ✅ Only INITIATOR or APPROVER can skip
2. Add Approver at Specific Level
Endpoint:
POST /api/v1/workflows/:id/approvers/at-level
Request Body:
{
"email": "john@example.com",
"tatHours": 48,
"level": 3
}
Response:
{
"success": true,
"message": "Approver added successfully",
"data": {
"levelId": "...",
"levelNumber": 3,
"approverName": "John Doe",
"tatHours": 48,
"status": "PENDING"
}
}
Logic:
- ✅ Find user by email
- ✅ Validate target level (must be after completed levels)
- ✅ Shift existing levels at and after target level (+1)
- ✅ Create new approval level at target position
- ✅ Add as participant (APPROVER type)
- ✅ If new level is current level, schedule TAT jobs
- ✅ Notify new approver
- ✅ Log activity
Validation:
- ❌ User must exist in system
- ❌ User cannot be existing participant
- ❌ Level must be after completed levels (approved/rejected/skipped)
- ✅ Automatic level shifting for existing approvers
Level Shifting Logic
Example: Add at Level 3
Before:
Level 1: Sarah (Approved) ✅
Level 2: Mike (In Review) ⏳
Level 3: Lisa (Waiting) ⏸️
Level 4: Tom (Waiting) ⏸️
Action:
Add John at Level 3 with 48h TAT
Backend Processing:
// Step 1: Get levels to shift (levelNumber >= 3)
levelsToShift = [Lisa (Level 3), Tom (Level 4)]
// Step 2: Shift each level
Lisa: Level 3 → Level 4
Tom: Level 4 → Level 5
// Step 3: Insert new approver
John: Create at Level 3
// Step 4: Update workflow.totalLevels
totalLevels: 4 → 5
After:
Level 1: Sarah (Approved) ✅
Level 2: Mike (In Review) ⏳
Level 3: John (Waiting) ⏸️ ← NEW!
Level 4: Lisa (Waiting) ⏸️ ← Shifted from 3
Level 5: Tom (Waiting) ⏸️ ← Shifted from 4
Frontend Implementation
AddApproverModal Enhancements:
New Props:
interface AddApproverModalProps {
open: boolean;
onClose: () => void;
onConfirm: (email: string, tatHours: number, level: number) => Promise<void>;
currentLevels?: ApprovalLevelInfo[]; // ✅ NEW!
}
interface ApprovalLevelInfo {
levelNumber: number;
approverName: string;
status: string;
tatHours: number;
}
UI Components:
- Current Levels Display - Shows all existing levels with status badges
- Level Selector - Dropdown with available levels (after completed)
- TAT Hours Input - Number input for TAT (1-720 hours)
- Email Search - Existing @ mention search
Example Modal:
┌─────────────────────────────────────────────────┐
│ Add Approver │
├─────────────────────────────────────────────────┤
│ Current Approval Levels │
│ ┌─────────────────────────────────────────────┐ │
│ │ [1] Sarah 50h TAT [✓] approved │ │
│ │ [2] Mike 24h TAT [⏳] pending │ │
│ │ [3] Lisa 36h TAT [⏸] waiting │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ Approval Level * │
│ [Select: Level 2 (will shift existing Level 2)] │
│ │
│ TAT (Turn Around Time) * │
│ [48] hours │
│ │
│ Email Address * │
│ [@john or john@example.com] │
│ │
│ [Cancel] [Add at Level 2] │
└─────────────────────────────────────────────────┘
RequestDetail Skip Button:
Added to Workflow tab for each pending/in-review level:
{/* Skip Approver Button - Only for active levels */}
{(isActive || step.status === 'pending') && !isCompleted && !isRejected && (
<Button
variant="outline"
size="sm"
className="w-full border-orange-300 text-orange-700 hover:bg-orange-50"
onClick={() => {
const reason = prompt('Provide reason for skipping:');
if (reason !== null) {
handleSkipApprover(step.levelId, reason);
}
}}
>
<AlertCircle className="w-4 h-4 mr-2" />
Skip This Approver
</Button>
)}
Validation Rules
Skip Approver Validation:
| Rule | Validation | Error Message |
|---|---|---|
| Already completed | ❌ Cannot skip APPROVED level | "Cannot skip approver - level is already APPROVED" |
| Already rejected | ❌ Cannot skip REJECTED level | "Cannot skip approver - level is already REJECTED" |
| Already skipped | ❌ Cannot skip SKIPPED level | "Cannot skip approver - level is already SKIPPED" |
| Future level | ❌ Cannot skip level > currentLevel | "Cannot skip future approval levels" |
| Authorization | ✅ Only INITIATOR or APPROVER | 403 Forbidden |
Add Approver Validation:
| Rule | Validation | Error Message |
|---|---|---|
| User exists | ✅ User must exist in system | "User not found with this email" |
| Already participant | ❌ Cannot add existing participant | "User is already a participant" |
| Level range | ❌ Level must be ≥ (completed levels + 1) | "Cannot add at level X. Minimum is Y" |
| TAT hours | ✅ 1 ≤ hours ≤ 720 | "TAT hours must be between 1 and 720" |
| Email format | ✅ Valid email format | "Please enter a valid email" |
| Authorization | ✅ Only INITIATOR or APPROVER | 403 Forbidden |
Examples
Example 1: Skip Current Approver
Initial State:
Request: REQ-2025-001
Current Level: 2
Level 1: Sarah (APPROVED) ✅
Level 2: Mike (IN_PROGRESS) ⏳ ← Taking too long
Level 3: Lisa (PENDING) ⏸️
Action:
# Initiator skips Mike
POST /api/v1/workflows/REQ-2025-001/approvals/LEVEL-ID-2/skip
Body: { "reason": "Approver on extended leave" }
Backend Processing:
1. Get Level 2 (Mike) → Status: IN_PROGRESS ✅
2. Validate: Not already completed ✅
3. Update Level 2:
- status: 'SKIPPED'
- is_skipped: TRUE
- skipped_at: NOW()
- skipped_by: initiator userId
- skip_reason: "Approver on extended leave"
4. Cancel TAT jobs for Level 2
5. Get Level 3 (Lisa)
6. Activate Level 3:
- status: 'IN_PROGRESS'
- levelStartTime: NOW()
- tatStartTime: NOW()
7. Schedule TAT jobs for Level 3
8. Update workflow.currentLevel = 3
9. Notify Lisa
10. Log activity: "Level 2 approver (Mike) was skipped"
Final State:
Request: REQ-2025-001
Current Level: 3
Level 1: Sarah (APPROVED) ✅
Level 2: Mike (SKIPPED) ⏭️ ← Skipped!
Level 3: Lisa (IN_PROGRESS) ⏳ ← Now active!
Example 2: Add Approver Between Levels
Initial State:
Request: REQ-2025-001
Current Level: 2
Level 1: Sarah (APPROVED) ✅
Level 2: Mike (IN_PROGRESS) ⏳
Level 3: Lisa (PENDING) ⏸️
Action:
# Add John at Level 3 (between Mike and Lisa)
POST /api/v1/workflows/REQ-2025-001/approvers/at-level
Body: {
"email": "john@example.com",
"tatHours": 48,
"level": 3
}
Backend Processing:
1. Find user: john@example.com ✅
2. Validate: Not existing participant ✅
3. Validate: Level 3 ≥ minLevel (2) ✅
4. Get levels to shift: [Lisa (Level 3)]
5. Shift Lisa:
- Level 3 → Level 4
- levelName: "Level 4"
6. Create new Level 3:
- levelNumber: 3
- approverId: John's userId
- approverEmail: john@example.com
- tatHours: 48
- status: PENDING (not current level)
7. Update workflow.totalLevels: 3 → 4
8. Add John to participants (APPROVER type)
9. Notify John
10. Log activity: "John added as approver at Level 3 with TAT of 48 hours"
Final State:
Request: REQ-2025-001
Current Level: 2
Level 1: Sarah (APPROVED) ✅
Level 2: Mike (IN_PROGRESS) ⏳ ← Still working
Level 3: John (PENDING) ⏸️ ← NEW! Will review after Mike
Level 4: Lisa (PENDING) ⏸️ ← Shifted from 3 to 4
Example 3: Complex Scenario - Skip and Add
Initial State:
Level 1: Sarah (APPROVED) ✅
Level 2: Mike (APPROVED) ✅
Level 3: David (IN_PROGRESS) ⏳ ← Taking too long
Level 4: Lisa (PENDING) ⏸️
Level 5: Tom (PENDING) ⏸️
Action 1: Skip David
Result:
Level 1: Sarah (APPROVED) ✅
Level 2: Mike (APPROVED) ✅
Level 3: David (SKIPPED) ⏭️
Level 4: Lisa (IN_PROGRESS) ⏳ ← Now active
Level 5: Tom (PENDING) ⏸️
Action 2: Add John at Level 4 (before Tom)
Result:
Level 1: Sarah (APPROVED) ✅
Level 2: Mike (APPROVED) ✅
Level 3: David (SKIPPED) ⏭️
Level 4: Lisa (IN_PROGRESS) ⏳
Level 5: John (PENDING) ⏸️ ← NEW!
Level 6: Tom (PENDING) ⏸️ ← Shifted
UI/UX
RequestDetail - Workflow Tab:
Skip Button Visibility:
- ✅ Shows for levels with status:
pendingorin-review - ❌ Hidden for
approved,rejected,skipped, orwaiting - ✅ Orange/amber styling to indicate caution
- ✅ Requires reason via prompt
Button Appearance:
┌───────────────────────────────────────────┐
│ Level 2: Mike (In Review) │
│ TAT: 24h • Elapsed: 15h │
│ │
│ [⚠ Skip This Approver] │
│ Skip if approver is unavailable... │
└───────────────────────────────────────────┘
AddApproverModal - Enhanced UI:
Sections:
- Current Levels - Scrollable list showing all existing levels with status
- Level Selector - Dropdown with available levels (grayed out completed levels)
- TAT Input - Hours input with validation (1-720)
- Email Search - @ mention search (existing)
Features:
- ✅ Auto-selects first available level
- ✅ Shows which existing level will be shifted
- ✅ Visual indicators for completed vs pending levels
- ✅ Prevents selecting invalid levels
- ✅ Real-time validation
Activity Log Examples
Skip Approver Log:
Action: Approver Skipped
Details: Level 2 approver (Mike Johnson) was skipped by Sarah Smith.
Reason: Approver on extended leave
Timestamp: 2025-11-05 10:30:00
User: Sarah Smith (Initiator)
Add Approver Log:
Action: Added new approver
Details: John Doe (john@example.com) has been added as approver at
Level 3 with TAT of 48 hours by Sarah Smith
Timestamp: 2025-11-05 11:15:00
User: Sarah Smith (Initiator)
Notifications
Skip Approver Notifications:
To Next Approver:
Title: Request Escalated
Body: Previous approver was skipped. Request REQ-2025-001 is now
awaiting your approval.
Add Approver Notifications:
To New Approver:
Title: New Request Assignment
Body: You have been added as Level 3 approver to request REQ-2025-001:
New Office Location Approval
TAT Handling
Skip Approver:
// Skipped level's TAT jobs are cancelled
await tatSchedulerService.cancelTatJobs(requestId, skippedLevelId);
// Next level's TAT jobs are scheduled
await tatSchedulerService.scheduleTatJobs(
requestId,
nextLevelId,
nextApproverId,
nextLevelTatHours,
now,
workflowPriority
);
Add Approver:
// If new approver is at current level, schedule TAT immediately
if (newLevel === currentLevel) {
await tatSchedulerService.scheduleTatJobs(
requestId,
newLevelId,
newApproverId,
tatHours,
now,
workflowPriority
);
}
// Otherwise, jobs will be scheduled when level becomes active
Testing Scenarios
Test 1: Skip Current Approver
# 1. Create workflow with 3 approvers
# 2. Level 1 approves
# 3. Level 2 receives notification
# 4. Level 2 doesn't respond for extended time
# 5. Initiator clicks "Skip This Approver"
# 6. Provide reason: "On vacation"
# 7. Verify:
# ✅ Level 2 status = SKIPPED
# ✅ Level 3 status = IN_PROGRESS
# ✅ Level 3 receives notification
# ✅ TAT jobs scheduled for Level 3
# ✅ Activity logged
Test 2: Add Approver at Middle Level
# 1. Workflow has 3 levels
# 2. Level 1 approved
# 3. Click "Add Approver"
# 4. Select Level 2 (between current levels)
# 5. Enter TAT: 48
# 6. Enter email: new@example.com
# 7. Submit
# 8. Verify:
# ✅ Old Level 2 becomes Level 3
# ✅ Old Level 3 becomes Level 4
# ✅ New approver at Level 2
# ✅ totalLevels increased by 1
# ✅ New approver receives notification
Test 3: Cannot Add Before Completed Level
# 1. Workflow: Level 1 (Approved), Level 2 (Pending)
# 2. Try to add at Level 1
# 3. Modal shows: "Minimum allowed level is 2"
# 4. Level 1 is grayed out in selector
# 5. Cannot submit ✅
Files Modified
Backend:
Re_Backend/src/migrations/add_is_skipped_to_approval_levels.sql- Database migrationRe_Backend/src/services/workflow.service.ts- Skip and add approver logicRe_Backend/src/routes/workflow.routes.ts- API endpoints
Frontend:
Re_Figma_Code/src/services/workflowApi.ts- API client methodsRe_Figma_Code/src/components/participant/AddApproverModal/AddApproverModal.tsx- Enhanced modalRe_Figma_Code/src/pages/RequestDetail/RequestDetail.tsx- Skip button and handlers
Summary
| Feature | Description | Benefit |
|---|---|---|
| Skip Approver | Mark approver as skipped, move to next | Handle unavailable approvers |
| Add at Level | Insert approver at specific position | Flexible workflow modification |
| Auto Shifting | Existing levels automatically renumbered | No manual level management |
| Smart Validation | Cannot modify completed levels | Data integrity |
| TAT Management | Jobs cancelled/scheduled automatically | Accurate time tracking |
| Activity Logging | All actions tracked in audit trail | Full transparency |
| Notifications | Affected users notified automatically | Keep everyone informed |
Benefits
- ✅ Flexibility - Handle real-world workflow changes
- ✅ No Bottlenecks - Skip unavailable approvers
- ✅ Dynamic Addition - Add approvers mid-workflow
- ✅ Data Integrity - Cannot modify completed levels
- ✅ Audit Trail - Full history of all changes
- ✅ Automatic Notifications - All affected parties notified
- ✅ TAT Accuracy - Time tracking updated correctly
- ✅ User-Friendly - Intuitive UI with clear feedback
The approval workflow is now fully dynamic and can adapt to changing business needs! 🚀