Re_Backend/SKIP_AND_ADD_APPROVER.md

752 lines
19 KiB
Markdown

# 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:**
1. **Skip Approver** - Skip non-responding approvers and move to next level
2. **Add Approver at Specific Level** - Insert new approver at any position
3. **Automatic Level Shifting** - Existing approvers are automatically renumbered
4. **Smart Validation** - Cannot modify completed levels (approved/rejected/skipped)
5. **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:**
```sql
-- 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:
```sql
status ENUM('PENDING', 'IN_PROGRESS', 'APPROVED', 'REJECTED', 'SKIPPED')
```
### **Example Data:**
```sql
-- 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:**
```json
{
"reason": "Approver on vacation - deadline approaching"
}
```
**Response:**
```json
{
"success": true,
"message": "Approver skipped successfully",
"data": {
"levelId": "...",
"levelNumber": 2,
"status": "SKIPPED",
"skippedAt": "2025-11-05T10:30:00Z"
}
}
```
**Logic:**
1. ✅ Mark level as `SKIPPED`
2. ✅ Cancel TAT jobs for skipped level
3. ✅ Activate next level (move to level+1)
4. ✅ Schedule TAT jobs for next level
5. ✅ Notify next approver
6. ✅ 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:**
```json
{
"email": "john@example.com",
"tatHours": 48,
"level": 3
}
```
**Response:**
```json
{
"success": true,
"message": "Approver added successfully",
"data": {
"levelId": "...",
"levelNumber": 3,
"approverName": "John Doe",
"tatHours": 48,
"status": "PENDING"
}
}
```
**Logic:**
1. ✅ Find user by email
2. ✅ Validate target level (must be after completed levels)
3. ✅ Shift existing levels at and after target level (+1)
4. ✅ Create new approval level at target position
5. ✅ Add as participant (APPROVER type)
6. ✅ If new level is current level, schedule TAT jobs
7. ✅ Notify new approver
8. ✅ 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:**
```typescript
// 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:**
```typescript
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:**
1. **Current Levels Display** - Shows all existing levels with status badges
2. **Level Selector** - Dropdown with available levels (after completed)
3. **TAT Hours Input** - Number input for TAT (1-720 hours)
4. **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:
```tsx
{/* 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:**
```bash
# Initiator skips Mike
POST /api/v1/workflows/REQ-2025-001/approvals/LEVEL-ID-2/skip
Body: { "reason": "Approver on extended leave" }
```
**Backend Processing:**
```typescript
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:**
```bash
# 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:**
```typescript
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: `pending` or `in-review`
- ❌ Hidden for `approved`, `rejected`, `skipped`, or `waiting`
- ✅ Orange/amber styling to indicate caution
- ✅ Requires reason via prompt
**Button Appearance:**
```tsx
┌───────────────────────────────────────────┐
Level 2: Mike (In Review)
TAT: 24h Elapsed: 15h
[ Skip This Approver]
Skip if approver is unavailable...
└───────────────────────────────────────────┘
```
---
### **AddApproverModal - Enhanced UI:**
**Sections:**
1. **Current Levels** - Scrollable list showing all existing levels with status
2. **Level Selector** - Dropdown with available levels (grayed out completed levels)
3. **TAT Input** - Hours input with validation (1-720)
4. **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:**
```typescript
// 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:**
```typescript
// 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**
```bash
# 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**
```bash
# 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**
```bash
# 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:**
1. `Re_Backend/src/migrations/add_is_skipped_to_approval_levels.sql` - Database migration
2. `Re_Backend/src/services/workflow.service.ts` - Skip and add approver logic
3. `Re_Backend/src/routes/workflow.routes.ts` - API endpoints
### **Frontend:**
4. `Re_Figma_Code/src/services/workflowApi.ts` - API client methods
5. `Re_Figma_Code/src/components/participant/AddApproverModal/AddApproverModal.tsx` - Enhanced modal
6. `Re_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
1.**Flexibility** - Handle real-world workflow changes
2.**No Bottlenecks** - Skip unavailable approvers
3.**Dynamic Addition** - Add approvers mid-workflow
4.**Data Integrity** - Cannot modify completed levels
5.**Audit Trail** - Full history of all changes
6.**Automatic Notifications** - All affected parties notified
7.**TAT Accuracy** - Time tracking updated correctly
8.**User-Friendly** - Intuitive UI with clear feedback
The approval workflow is now fully dynamic and can adapt to changing business needs! 🚀