unecessary files removed

This commit is contained in:
laxmanhalaki 2025-12-05 10:39:54 +05:30
parent 17485a9cca
commit 34ea547adf
6 changed files with 0 additions and 1768 deletions

View File

@ -1,538 +0,0 @@
# Simplified Workflow API - Postman Guide
## ✅ Updated Simplified Format
The API has been updated to make workflow creation much simpler. You now only need to provide **email** and **tatHours** for approvers, and **email** for spectators. The backend automatically handles:
- User lookup/creation from Okta/Azure AD
- Fetching user details (name, department, designation)
- Auto-generating level names based on designation/department
- Auto-detecting final approver (last level)
- Proper validation with clear error messages
---
## Authentication
### Login
```http
POST {{baseUrl}}/auth/login
Content-Type: application/json
{
"email": "your-email@example.com",
"password": "your-password"
}
```
**Response:**
```json
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": { "userId": "...", "email": "...", ... }
}
}
```
---
## Create Workflow - Simplified Format
### Example 1: Simple Workflow (JSON)
**POST** `{{baseUrl}}/workflows`
**Headers:**
```
Content-Type: application/json
Authorization: Bearer <your_token>
```
**Body:**
```json
{
"templateType": "CUSTOM",
"title": "Purchase Order Approval - Office Equipment",
"description": "Approval needed for purchasing new office equipment including laptops and monitors. Total budget: $50,000",
"priority": "STANDARD",
"approvalLevels": [
{
"email": "manager@royalenfield.com",
"tatHours": 24
},
{
"email": "director@royalenfield.com",
"tatHours": 48
},
{
"email": "cfo@royalenfield.com",
"tatHours": 72
}
],
"spectators": [
{
"email": "hr@royalenfield.com"
},
{
"email": "finance@royalenfield.com"
}
]
}
```
---
### Example 2: Express Priority with Final Approver Flag
```json
{
"templateType": "CUSTOM",
"title": "Urgent: Server Infrastructure Upgrade",
"description": "Critical server infrastructure upgrade required immediately",
"priority": "EXPRESS",
"approvalLevels": [
{
"email": "it-manager@royalenfield.com",
"tatHours": 8
},
{
"email": "cto@royalenfield.com",
"tatHours": 16,
"isFinalApprover": true
}
]
}
```
---
### Example 3: With Custom Level Names
```json
{
"templateType": "CUSTOM",
"title": "Vendor Contract Approval",
"description": "New vendor contract for manufacturing components",
"priority": "STANDARD",
"approvalLevels": [
{
"email": "procurement@royalenfield.com",
"tatHours": 24,
"levelName": "Procurement Review"
},
{
"email": "legal@royalenfield.com",
"tatHours": 48,
"levelName": "Legal Compliance"
},
{
"email": "vp@royalenfield.com",
"tatHours": 72,
"levelName": "Executive Approval",
"isFinalApprover": true
}
]
}
```
---
### Example 4: Multipart with Files
**POST** `{{baseUrl}}/workflows/multipart`
**Headers:**
```
Authorization: Bearer <your_token>
```
**Body (form-data):**
| Key | Type | Value |
|-----|------|-------|
| `payload` | Text | `{"templateType":"CUSTOM","title":"Budget Request 2025","description":"Annual budget request","priority":"STANDARD","approvalLevels":[{"email":"finance-manager@royalenfield.com","tatHours":48},{"email":"cfo@royalenfield.com","tatHours":72}]}` |
| `files` | File | Select PDF/Excel file(s) |
| `category` | Text | `SUPPORTING` |
---
## Field Reference
### Required Fields
| Field | Type | Description | Example |
|-------|------|-------------|---------|
| `templateType` | string | Workflow type | `"CUSTOM"` or `"TEMPLATE"` |
| `title` | string | Request title (max 500 chars) | `"Purchase Order Approval"` |
| `description` | string | Detailed description | `"Approval needed for..."` |
| `priority` | string | Request priority | `"STANDARD"` or `"EXPRESS"` |
| `approvalLevels` | array | List of approvers (min 1, max 10) | See below |
### Approval Level Fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | ✅ Yes | Approver's email address |
| `tatHours` | number | ✅ Yes | Turn-around time in hours (positive number) |
| `isFinalApprover` | boolean | ❌ No | Explicitly mark as final approver (auto-detected if last level) |
| `levelName` | string | ❌ No | Custom level name (auto-generated if not provided) |
**Auto-generated `levelName` logic:**
- If approver has **designation**: `"{Designation} Approval"` (e.g., "Manager Approval")
- If approver has **department**: `"{Department} Approval"` (e.g., "Finance Approval")
- Otherwise: `"Level {N} Approval"` (e.g., "Level 1 Approval")
### Spectator Fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | ✅ Yes | Spectator's email address |
---
## Validation & Error Handling
The backend automatically validates and provides clear error messages:
### ✅ Successful Response
```json
{
"success": true,
"message": "Workflow created successfully",
"data": {
"requestId": "uuid",
"requestNumber": "REQ-2025-12-0001",
"title": "...",
"status": "PENDING",
...
}
}
```
### ❌ Error: Invalid Email
```json
{
"success": false,
"error": "Failed to create workflow",
"details": "Approver email 'invalid@example.com' not found in organization directory. Please verify the email address."
}
```
### ❌ Error: Duplicate Email
```json
{
"success": false,
"error": "Failed to create workflow",
"details": "Duplicate approver email found: manager@example.com. Each approver must have a unique email."
}
```
### ❌ Error: Invalid Initiator
```json
{
"success": false,
"error": "Failed to create workflow",
"details": "Invalid initiator: User with ID '...' not found. Please ensure you are logged in with a valid account."
}
```
### ❌ Error: Validation Failed
```json
{
"success": false,
"error": "Validation failed",
"details": "approvalLevels.0.email: Valid email is required; approvalLevels.0.tatHours: TAT hours must be positive"
}
```
---
## What Happens Behind the Scenes
When you create a workflow, the backend:
1. **Validates Initiator**: Ensures the logged-in user exists
2. **Enriches Approval Levels**:
- Searches for each approver in the local database
- If not found, fetches from Okta/Azure AD
- Creates user record if they exist in AD but not in DB
- Extracts: `userId`, `displayName`, `designation`, `department`
- Auto-generates `levelName` if not provided
- Auto-detects `isFinalApprover` (last level = true)
3. **Enriches Spectators**:
- Same lookup/creation process as approvers
- Sets default permissions (view + comment, no download)
4. **Creates Workflow**:
- Saves workflow request
- Creates approval levels
- Creates participants
- Sends notifications
- Logs activity
---
## Migration from Old Format
### ❌ Old Format (No Longer Required)
```json
{
"approvalLevels": [
{
"levelNumber": 1,
"levelName": "Manager Approval",
"approverId": "uuid-123",
"approverEmail": "manager@example.com",
"approverName": "John Doe",
"tatHours": 24,
"isFinalApprover": false
}
]
}
```
### ✅ New Simplified Format
```json
{
"approvalLevels": [
{
"email": "manager@example.com",
"tatHours": 24
}
]
}
```
**The backend handles everything else automatically!**
---
## Tips & Best Practices
1. **Use Valid Email Addresses**: Ensure all approver/spectator emails exist in your Okta/Azure AD
2. **TAT Hours**: Set realistic turn-around times based on priority:
- STANDARD: 24-72 hours per level
- EXPRESS: 8-24 hours per level
3. **Final Approver**: Last level is automatically marked as final approver (you can override with `isFinalApprover: true` on any level)
4. **Level Names**: Let the system auto-generate based on designation/department, or provide custom names
5. **Spectators**: Add users who need visibility but not approval authority
6. **Documents**: Use `/multipart` endpoint for file uploads
---
## Testing in Postman
1. **Set Environment Variables**:
- `baseUrl`: `http://localhost:5000/api/v1`
- `token`: Your auth token from login
2. **Login First**:
- Call `POST /auth/login`
- Copy the `token` from response
- Set as environment variable
3. **Create Workflow**:
- Use simplified format
- Only provide email + tatHours
- Backend handles the rest
4. **Check Response**:
- Verify `requestNumber` is generated
- Check `approvalLevels` are enriched with user data
- Confirm `participants` includes spectators
---
## Add Approver/Spectator After Request Creation
These endpoints allow adding approvers or spectators to an existing request. They follow the same simplified pattern - just provide email, and the backend handles user lookup/creation.
### Add Approver at Specific Level
**POST** `{{baseUrl}}/workflows/:requestId/approvers/at-level`
**Headers:**
```
Authorization: Bearer <your_token>
Content-Type: application/json
```
**Body:**
```json
{
"email": "newapprover@royalenfield.com",
"tatHours": 24,
"level": 2
}
```
**What Happens:**
- ✅ Finds user by email in DB, or syncs from Okta/AD if not found
- ✅ Auto-generates levelName based on designation/department
- ✅ Shifts existing levels if needed
- ✅ Updates final approver flag
- ✅ Sends notification to new approver
- ✅ Logs activity
**Response:**
```json
{
"success": true,
"message": "Approver added successfully",
"data": {
"levelId": "uuid",
"levelNumber": 2,
"levelName": "Manager Approval",
"approverId": "uuid",
"approverEmail": "newapprover@royalenfield.com",
"approverName": "John Doe",
"tatHours": 24,
"status": "PENDING"
}
}
```
---
### Add Simple Approver (General)
**POST** `{{baseUrl}}/workflows/:requestId/participants/approver`
**Headers:**
```
Authorization: Bearer <your_token>
Content-Type: application/json
```
**Body:**
```json
{
"email": "approver@royalenfield.com"
}
```
*Note: This adds them as a general approver participant, not at a specific level.*
---
### Add Spectator
**POST** `{{baseUrl}}/workflows/:requestId/participants/spectator`
**Headers:**
```
Authorization: Bearer <your_token>
Content-Type: application/json
```
**Body:**
```json
{
"email": "spectator@royalenfield.com"
}
```
**What Happens:**
- ✅ Finds user by email in DB, or syncs from Okta/AD if not found
- ✅ Sets spectator permissions (view + comment, no download)
- ✅ Sends notification to new spectator
- ✅ Logs activity
**Response:**
```json
{
"success": true,
"data": {
"participantId": "uuid",
"userId": "uuid",
"userEmail": "spectator@royalenfield.com",
"userName": "Jane Doe",
"participantType": "SPECTATOR",
"canComment": true,
"canViewDocuments": true,
"canDownloadDocuments": false
}
}
```
---
### Error Handling for Add Operations
**❌ User Not Found in AD:**
```json
{
"success": false,
"error": "Failed to add approver",
"details": "Approver email 'invalid@example.com' not found in organization directory. Please verify the email address."
}
```
**❌ User Already a Participant:**
```json
{
"success": false,
"error": "Failed to add spectator",
"details": "User is already a participant in this request"
}
```
**❌ Invalid Level:**
```json
{
"success": false,
"error": "Failed to add approver at level",
"details": "Cannot add approver at level 1 - level has already been completed"
}
```
---
## Complete Flow Example
### 1. Login
```bash
POST /api/v1/auth/login
Body: { "email": "user@example.com", "password": "pass" }
```
### 2. Create Workflow (Simplified)
```bash
POST /api/v1/workflows
Body: {
"templateType": "CUSTOM",
"title": "Purchase Order",
"description": "Office equipment",
"priority": "STANDARD",
"approvalLevels": [
{ "email": "manager@example.com", "tatHours": 24 }
]
}
```
### 3. Add Additional Approver (After Creation)
```bash
POST /api/v1/workflows/:requestId/approvers/at-level
Body: {
"email": "director@example.com",
"tatHours": 48,
"level": 2
}
```
### 4. Add Spectator
```bash
POST /api/v1/workflows/:requestId/participants/spectator
Body: { "email": "hr@example.com" }
```
---
## Need Help?
If you encounter any issues:
1. Check the error message - it will tell you exactly what's wrong
2. Verify emails exist in your organization directory
3. Ensure you're logged in with a valid token
4. Check backend logs for detailed error information

View File

@ -1,535 +0,0 @@
# Data Collection Analysis - What We Have vs What We're Collecting
## Overview
This document compares the database structure with what we're currently collecting and recommends what we should start collecting for the Detailed Reports.
---
## 1. ACTIVITIES TABLE
### ✅ **Database Fields Available:**
```sql
- activity_id (PK)
- request_id (FK) ✅ COLLECTING
- user_id (FK) ✅ COLLECTING
- user_name ✅ COLLECTING
- activity_type ✅ COLLECTING
- activity_description ✅ COLLECTING
- activity_category ❌ NOT COLLECTING (set to NULL)
- severity ❌ NOT COLLECTING (set to NULL)
- metadata ✅ COLLECTING (partially)
- is_system_event ✅ COLLECTING
- ip_address ❌ NOT COLLECTING (set to NULL)
- user_agent ❌ NOT COLLECTING (set to NULL)
- created_at ✅ COLLECTING
```
### 🔴 **Currently NOT Collecting (But Should):**
1. **IP Address** (`ip_address`)
- **Status:** Field exists, but always set to `null`
- **Impact:** Cannot show IP in User Activity Log Report
- **Fix:** Extract from `req.ip` or `req.headers['x-forwarded-for']` in controllers
- **Priority:** HIGH (needed for security/audit)
2. **User Agent** (`user_agent`)
- **Status:** Field exists, but always set to `null`
- **Impact:** Cannot show device/browser info in reports
- **Fix:** Extract from `req.headers['user-agent']` in controllers
- **Priority:** MEDIUM (nice to have for analytics)
3. **Activity Category** (`activity_category`)
- **Status:** Field exists, but always set to `null`
- **Impact:** Cannot categorize activities (e.g., "AUTHENTICATION", "WORKFLOW", "DOCUMENT")
- **Fix:** Map `activity_type` to category:
- `created`, `approval`, `rejection`, `status_change` → "WORKFLOW"
- `comment` → "COLLABORATION"
- `document_added` → "DOCUMENT"
- `sla_warning` → "SYSTEM"
- **Priority:** MEDIUM (helps with filtering/reporting)
4. **Severity** (`severity`)
- **Status:** Field exists, but always set to `null`
- **Impact:** Cannot prioritize critical activities
- **Fix:** Map based on activity type:
- `rejection`, `sla_warning` → "WARNING"
- `approval`, `closed` → "INFO"
- `status_change` → "INFO"
- **Priority:** LOW (optional enhancement)
### 📝 **Recommendation:**
**Update `activity.service.ts` to accept and store:**
```typescript
async log(entry: ActivityEntry & {
ipAddress?: string;
userAgent?: string;
category?: string;
severity?: string;
}) {
// ... existing code ...
const activityData = {
// ... existing fields ...
ipAddress: entry.ipAddress || null,
userAgent: entry.userAgent || null,
activityCategory: entry.category || this.inferCategory(entry.type),
severity: entry.severity || this.inferSeverity(entry.type),
};
}
```
**Update all controller calls to pass IP and User Agent:**
```typescript
activityService.log({
// ... existing fields ...
ipAddress: req.ip || req.headers['x-forwarded-for'] || null,
userAgent: req.headers['user-agent'] || null,
});
```
---
## 2. APPROVAL_LEVELS TABLE
### ✅ **Database Fields Available:**
```sql
- level_id (PK)
- request_id (FK) ✅ COLLECTING
- level_number ✅ COLLECTING
- level_name ❌ OPTIONAL (may not be set)
- approver_id (FK) ✅ COLLECTING
- approver_email ✅ COLLECTING
- approver_name ✅ COLLECTING
- tat_hours ✅ COLLECTING
- tat_days ✅ COLLECTING (auto-calculated)
- status ✅ COLLECTING
- level_start_time ✅ COLLECTING
- level_end_time ✅ COLLECTING
- action_date ✅ COLLECTING
- comments ✅ COLLECTING
- rejection_reason ✅ COLLECTING
- is_final_approver ✅ COLLECTING
- elapsed_hours ✅ COLLECTING
- remaining_hours ✅ COLLECTING
- tat_percentage_used ✅ COLLECTING
- tat50_alert_sent ✅ COLLECTING
- tat75_alert_sent ✅ COLLECTING
- tat_breached ✅ COLLECTING
- tat_start_time ✅ COLLECTING
- created_at ✅ COLLECTING
- updated_at ✅ COLLECTING
```
### 🔴 **Currently NOT Collecting (But Should):**
1. **Level Name** (`level_name`)
- **Status:** Field exists, but may be NULL
- **Impact:** Cannot show stage name in reports (only level number)
- **Fix:** When creating approval levels, prompt for or auto-generate level names:
- "Department Head Review"
- "Finance Approval"
- "Final Approval"
- **Priority:** MEDIUM (improves report readability)
### 📝 **Recommendation:**
**Ensure level_name is set when creating approval levels:**
```typescript
await ApprovalLevel.create({
// ... existing fields ...
levelName: levelData.levelName || `Level ${levelNumber}`,
});
```
---
## 3. USER_SESSIONS TABLE
### ✅ **Database Fields Available:**
```sql
- session_id (PK)
- user_id (FK)
- session_token ✅ COLLECTING
- refresh_token ✅ COLLECTING
- ip_address ❓ CHECK IF COLLECTING
- user_agent ❓ CHECK IF COLLECTING
- device_type ❓ CHECK IF COLLECTING
- browser ❓ CHECK IF COLLECTING
- os ❓ CHECK IF COLLECTING
- login_at ✅ COLLECTING
- last_activity_at ✅ COLLECTING
- logout_at ❓ CHECK IF COLLECTING
- expires_at ✅ COLLECTING
- is_active ✅ COLLECTING
- logout_reason ❓ CHECK IF COLLECTING
```
### 🔴 **Missing for Login Activity Tracking:**
1. **Login Activities in Activities Table**
- **Status:** Login events are NOT logged in `activities` table
- **Impact:** Cannot show login activities in User Activity Log Report
- **Fix:** Add login activity logging in auth middleware/controller:
```typescript
// After successful login
await activityService.log({
requestId: 'SYSTEM_LOGIN', // Special request ID for system events
type: 'login',
user: { userId, name: user.displayName },
ipAddress: req.ip,
userAgent: req.headers['user-agent'],
category: 'AUTHENTICATION',
severity: 'INFO',
timestamp: new Date().toISOString(),
action: 'User Login',
details: `User logged in from ${req.ip}`
});
```
- **Priority:** HIGH (needed for security audit)
2. **Device/Browser Parsing**
- **Status:** Fields exist but may not be populated
- **Impact:** Cannot show device type in reports
- **Fix:** Parse user agent to extract:
- `device_type`: "WEB", "MOBILE"
- `browser`: "Chrome", "Firefox", "Safari"
- `os`: "Windows", "macOS", "iOS", "Android"
- **Priority:** MEDIUM (nice to have)
---
## 4. WORKFLOW_REQUESTS TABLE
### ✅ **All Fields Are Being Collected:**
- All fields in `workflow_requests` are properly collected
- No missing data here
### 📝 **Note:**
- `submission_date` vs `created_at`: Use `submission_date` for "days open" calculation
- `closure_date`: Available for completed requests
---
## 5. TAT_TRACKING TABLE
### ✅ **Database Fields Available:**
```sql
- tracking_id (PK)
- request_id (FK)
- level_id (FK)
- tracking_type ✅ COLLECTING
- tat_status ✅ COLLECTING
- total_tat_hours ✅ COLLECTING
- elapsed_hours ✅ COLLECTING
- remaining_hours ✅ COLLECTING
- percentage_used ✅ COLLECTING
- threshold_50_breached ✅ COLLECTING
- threshold_50_alerted_at ✅ COLLECTING
- threshold_80_breached ✅ COLLECTING
- threshold_80_alerted_at ✅ COLLECTING
- threshold_100_breached ✅ COLLECTING
- threshold_100_alerted_at ✅ COLLECTING
- alert_count ✅ COLLECTING
- last_calculated_at ✅ COLLECTING
```
### ✅ **All Fields Are Being Collected:**
- TAT tracking appears to be fully implemented
---
## 6. AUDIT_LOGS TABLE
### ✅ **Database Fields Available:**
```sql
- audit_id (PK)
- user_id (FK)
- entity_type
- entity_id
- action
- action_category
- old_values (JSONB)
- new_values (JSONB)
- changes_summary
- ip_address
- user_agent
- session_id
- request_method
- request_url
- response_status
- execution_time_ms
- created_at
```
### 🔴 **Status:**
- **Audit logging may not be fully implemented**
- **Impact:** Cannot track all system changes for audit purposes
- **Priority:** MEDIUM (for compliance/security)
---
## SUMMARY: What to Start Collecting
### 🔴 **HIGH PRIORITY (Must Have for Reports):**
1. **IP Address in Activities** ✅ Field exists, just need to populate
- Extract from `req.ip` or `req.headers['x-forwarded-for']`
- Update `activity.service.ts` to accept IP
- Update all controller calls
2. **User Agent in Activities** ✅ Field exists, just need to populate
- Extract from `req.headers['user-agent']`
- Update `activity.service.ts` to accept user agent
- Update all controller calls
3. **Login Activities** ❌ Not currently logged
- Add login activity logging in auth controller
- Use special `requestId: 'SYSTEM_LOGIN'` for system events
- Include IP and user agent
### 🟡 **MEDIUM PRIORITY (Nice to Have):**
4. **Activity Category** ✅ Field exists, just need to populate
- Auto-infer from `activity_type`
- Helps with filtering and reporting
5. **Level Names** ✅ Field exists, ensure it's set
- Improve readability in reports
- Auto-generate if not provided
6. **Severity** ✅ Field exists, just need to populate
- Auto-infer from `activity_type`
- Helps prioritize critical activities
### 🟢 **LOW PRIORITY (Future Enhancement):**
7. **Device/Browser Parsing**
- Parse user agent to extract device type, browser, OS
- Store in `user_sessions` table
8. **Audit Logging**
- Implement comprehensive audit logging
- Track all system changes
---
## 7. BUSINESS DAYS CALCULATION FOR WORKFLOW AGING
### ✅ **Available:**
- `calculateElapsedWorkingHours()` - Calculates working hours (excludes weekends/holidays)
- Working hours configuration (9 AM - 6 PM, Mon-Fri)
- Holiday support (from database)
- Priority-based calculation (express vs standard)
### ❌ **Missing:**
1. **Business Days Count Function**
- Need a function to calculate business days (not hours)
- For Workflow Aging Report: "Days Open" should be business days
- Currently only have working hours calculation
2. **TAT Processor Using Wrong Calculation**
- `tatProcessor.ts` uses simple calendar hours:
```typescript
const elapsedMs = now.getTime() - new Date(levelStartTime).getTime();
const elapsedHours = elapsedMs / (1000 * 60 * 60);
```
- Should use `calculateElapsedWorkingHours()` instead
- This causes incorrect TAT breach calculations
### 🔧 **What Needs to be Built:**
1. **Add Business Days Calculation Function:**
```typescript
// In tatTimeUtils.ts
export async function calculateBusinessDays(
startDate: Date | string,
endDate: Date | string = new Date(),
priority: string = 'standard'
): Promise<number> {
await loadWorkingHoursCache();
await loadHolidaysCache();
let start = dayjs(startDate);
const end = dayjs(endDate);
const config = workingHoursCache || { /* defaults */ };
let businessDays = 0;
let current = start.startOf('day');
while (current.isBefore(end) || current.isSame(end, 'day')) {
const dayOfWeek = current.day();
const dateStr = current.format('YYYY-MM-DD');
const isWorkingDay = priority === 'express'
? true
: (dayOfWeek >= config.startDay && dayOfWeek <= config.endDay);
const isNotHoliday = !holidaysCache.has(dateStr);
if (isWorkingDay && isNotHoliday) {
businessDays++;
}
current = current.add(1, 'day');
}
return businessDays;
}
```
2. **Fix TAT Processor:**
- Replace calendar hours calculation with `calculateElapsedWorkingHours()`
- This will fix TAT breach alerts to use proper working hours
3. **Update Workflow Aging Report:**
- Use `calculateBusinessDays()` instead of calendar days
- Filter by business days threshold
---
## IMPLEMENTATION CHECKLIST
### Phase 1: Quick Wins (Fields Exist, Just Need to Populate)
- [ ] Update `activity.service.ts` to accept `ipAddress` and `userAgent`
- [ ] Update all controller calls to pass IP and user agent
- [ ] Add activity category inference
- [ ] Add severity inference
### Phase 2: Fix TAT Calculations (CRITICAL)
- [x] Fix `tatProcessor.ts` to use `calculateElapsedWorkingHours()` instead of calendar hours ✅
- [x] Add `calculateBusinessDays()` function to `tatTimeUtils.ts`
- [ ] Test TAT breach calculations with working hours
### Phase 3: New Functionality
- [x] Add login activity logging ✅ (Implemented in auth.controller.ts for SSO and token exchange)
- [x] Ensure level names are set when creating approval levels ✅ (levelName set in workflow.service.ts)
- [x] Add device/browser parsing for user sessions ✅ (userAgentParser.ts utility created - can be used for parsing user agent strings)
### Phase 4: Enhanced Reporting
- [x] Build report endpoints using collected data ✅ (getLifecycleReport, getActivityLogReport, getWorkflowAgingReport)
- [x] Add filtering by category, severity ✅ (Filtering by category and severity added to getActivityLogReport, frontend UI added)
- [x] Add IP/user agent to activity log reports ✅ (IP and user agent captured and displayed)
- [x] Use business days in Workflow Aging Report ✅ (calculateBusinessDays implemented and used)
---
## CODE CHANGES NEEDED
### 1. Update Activity Service (`activity.service.ts`)
```typescript
export type ActivityEntry = {
requestId: string;
type: 'created' | 'assignment' | 'approval' | 'rejection' | 'status_change' | 'comment' | 'reminder' | 'document_added' | 'sla_warning' | 'ai_conclusion_generated' | 'closed' | 'login';
user?: { userId: string; name?: string; email?: string };
timestamp: string;
action: string;
details: string;
metadata?: any;
ipAddress?: string; // NEW
userAgent?: string; // NEW
category?: string; // NEW
severity?: string; // NEW
};
class ActivityService {
private inferCategory(type: string): string {
const categoryMap: Record<string, string> = {
'created': 'WORKFLOW',
'approval': 'WORKFLOW',
'rejection': 'WORKFLOW',
'status_change': 'WORKFLOW',
'assignment': 'WORKFLOW',
'comment': 'COLLABORATION',
'document_added': 'DOCUMENT',
'sla_warning': 'SYSTEM',
'reminder': 'SYSTEM',
'ai_conclusion_generated': 'SYSTEM',
'closed': 'WORKFLOW',
'login': 'AUTHENTICATION'
};
return categoryMap[type] || 'OTHER';
}
private inferSeverity(type: string): string {
const severityMap: Record<string, string> = {
'rejection': 'WARNING',
'sla_warning': 'WARNING',
'approval': 'INFO',
'closed': 'INFO',
'status_change': 'INFO',
'login': 'INFO',
'created': 'INFO',
'comment': 'INFO',
'document_added': 'INFO'
};
return severityMap[type] || 'INFO';
}
async log(entry: ActivityEntry) {
// ... existing code ...
const activityData = {
requestId: entry.requestId,
userId: entry.user?.userId || null,
userName: entry.user?.name || entry.user?.email || null,
activityType: entry.type,
activityDescription: entry.details,
activityCategory: entry.category || this.inferCategory(entry.type),
severity: entry.severity || this.inferSeverity(entry.type),
metadata: entry.metadata || null,
isSystemEvent: !entry.user,
ipAddress: entry.ipAddress || null, // NEW
userAgent: entry.userAgent || null, // NEW
};
// ... rest of code ...
}
}
```
### 2. Update Controller Calls (Example)
```typescript
// In workflow.controller.ts, approval.controller.ts, etc.
activityService.log({
requestId: workflow.requestId,
type: 'created',
user: { userId, name: user.displayName },
timestamp: new Date().toISOString(),
action: 'Request Created',
details: `Request ${workflow.requestNumber} created`,
ipAddress: req.ip || req.headers['x-forwarded-for'] || null, // NEW
userAgent: req.headers['user-agent'] || null, // NEW
});
```
### 3. Add Login Activity Logging
```typescript
// In auth.controller.ts after successful login
await activityService.log({
requestId: 'SYSTEM_LOGIN', // Special ID for system events
type: 'login',
user: { userId: user.userId, name: user.displayName },
timestamp: new Date().toISOString(),
action: 'User Login',
details: `User logged in successfully`,
ipAddress: req.ip || req.headers['x-forwarded-for'] || null,
userAgent: req.headers['user-agent'] || null,
category: 'AUTHENTICATION',
severity: 'INFO'
});
```
---
## CONCLUSION
**Good News:** Most fields already exist in the database! We just need to:
1. Populate existing fields (IP, user agent, category, severity)
2. Add login activity logging
3. Ensure level names are set
**Estimated Effort:**
- Phase 1 (Quick Wins): 2-4 hours
- Phase 2 (New Functionality): 4-6 hours
- Phase 3 (Enhanced Reporting): 8-12 hours
**Total: ~14-22 hours of development work**

View File

@ -1,134 +0,0 @@
========================================
REDIS SETUP FOR TAT NOTIFICATIONS
========================================
-----------------------------------------
OPTION 1: UPSTASH (★ RECOMMENDED ★)
-----------------------------------------
✅ NO INSTALLATION NEEDED
✅ 100% FREE FOR DEVELOPMENT
✅ WORKS ON WINDOWS, MAC, LINUX
✅ PRODUCTION READY
SETUP (2 MINUTES):
1. Go to: https://console.upstash.com/
2. Sign up (GitHub/Google/Email)
3. Click "Create Database"
- Name: redis-tat-dev
- Type: Regional
- Region: Choose closest to you
- Click "Create"
4. Copy the Redis URL (looks like):
rediss://default:AbC123...@us1-mighty-12345.upstash.io:6379
5. Add to Re_Backend/.env:
REDIS_URL=rediss://default:AbC123...@us1-mighty-12345.upstash.io:6379
TAT_TEST_MODE=true
6. Restart backend:
cd Re_Backend
npm run dev
7. ✅ Done! Look for: "[TAT Queue] Connected to Redis"
-----------------------------------------
OPTION 2: DOCKER (IF YOU PREFER LOCAL)
-----------------------------------------
If you have Docker Desktop:
1. Run Redis container:
docker run -d --name redis-tat -p 6379:6379 redis:latest
2. Add to Re_Backend/.env:
REDIS_URL=redis://localhost:6379
TAT_TEST_MODE=true
3. Restart backend
-----------------------------------------
OPTION 3: PRODUCTION (LINUX SERVER)
-----------------------------------------
For Ubuntu/Debian servers:
1. Install Redis:
sudo apt update
sudo apt install redis-server -y
2. Enable and start:
sudo systemctl enable redis-server
sudo systemctl start redis-server
3. Verify:
redis-cli ping
# → PONG
4. Add to .env on server:
REDIS_URL=redis://localhost:6379
TAT_TEST_MODE=false
✅ FREE, NO LICENSE, PRODUCTION READY
-----------------------------------------
VERIFY CONNECTION
-----------------------------------------
After setup, check backend logs for:
✅ [TAT Queue] Connected to Redis
✅ [TAT Worker] Initialized and listening
Or test manually:
For Upstash:
- Use Upstash Console → CLI tab
- Type: PING → Should return PONG
For Local/Docker:
Test-NetConnection localhost -Port 6379
# Should show: TcpTestSucceeded : True
-----------------------------------------
RESTART BACKEND
-----------------------------------------
After Redis is running:
cd Re_Backend
npm run dev
You should see:
✅ [TAT Queue] Connected to Redis
✅ [TAT Worker] Initialized and listening
-----------------------------------------
TEST TAT NOTIFICATIONS
-----------------------------------------
1. Create a new workflow request
2. Set a short TAT (e.g., 2 hours for testing)
3. Submit the request
4. Check logs for:
- "TAT jobs scheduled"
- Notifications at 50%, 75%, 100%
For testing, you can modify working hours in:
Re_Backend/src/utils/tatTimeUtils.ts
-----------------------------------------
CURRENT STATUS
-----------------------------------------
❌ Redis: NOT RUNNING
❌ TAT Notifications: DISABLED
After installing Redis:
✅ Redis: RUNNING
✅ TAT Notifications: ENABLED
========================================

View File

@ -1,266 +0,0 @@
# Postman Collection Updates - Simplified API
## ✅ Updated Endpoints
The Postman collection has been updated to use the **simplified API format**. Here's what changed:
---
### **1. Create Workflow (JSON) - Simplified**
**Old Format (REMOVED):**
```json
{
"requestTitle": "...",
"requestDescription": "...",
"requestingDepartment": "IT",
"requestCategory": "PURCHASE_ORDER",
"approvers": [
{ "email": "...", "tatHours": 24, "level": 1 }
]
}
```
**New Simplified Format:**
```json
{
"templateType": "CUSTOM",
"title": "Purchase Order Approval for Office Equipment",
"description": "Approval needed for purchasing new office equipment...",
"priority": "STANDARD",
"approvalLevels": [
{
"email": "manager@royalenfield.com",
"tatHours": 24
},
{
"email": "director@royalenfield.com",
"tatHours": 48
},
{
"email": "cfo@royalenfield.com",
"tatHours": 72
}
],
"spectators": [
{
"email": "hr@royalenfield.com"
},
{
"email": "finance@royalenfield.com"
}
]
}
```
**What Backend Does Automatically:**
- ✅ Finds/creates users from Okta/AD
- ✅ Generates level names from designation/department
- ✅ Auto-detects final approver (last level)
- ✅ Sets proper permissions
---
### **2. Create Workflow (Multipart with Files) - Simplified**
**Updated Form Data:**
| Key | Value |
|-----|-------|
| `payload` | `{"templateType":"CUSTOM","title":"...","description":"...","priority":"STANDARD","approvalLevels":[{"email":"manager@royalenfield.com","tatHours":24}],"spectators":[{"email":"hr@royalenfield.com"}]}` |
| `files` | Select file(s) |
| `category` | `SUPPORTING` (optional) |
**Changes:**
- ❌ Removed: `requestTitle`, `requestDescription`, `requestingDepartment`, `requestCategory`
- ❌ Removed: Complex approver format with level numbers
- ✅ Added: Single `payload` field with simplified JSON
- ✅ Simplified: Only `email` and `tatHours` per approver
---
### **3. Add Approver at Level - Simplified** 🆕
**NEW Endpoint Added!**
**Method:** `POST`
**URL:** `{{baseUrl}}/workflows/:id/approvers/at-level`
**Body:**
```json
{
"email": "newapprover@royalenfield.com",
"tatHours": 24,
"level": 2
}
```
**What Backend Does:**
- ✅ Finds/creates user from Okta/AD
- ✅ Generates smart level name
- ✅ Shifts existing levels if needed
- ✅ Updates final approver flag
- ✅ Sends notifications
---
### **4. Add Spectator - Simplified** 🆕
**NEW Endpoint Added!**
**Method:** `POST`
**URL:** `{{baseUrl}}/workflows/:id/participants/spectator`
**Body:**
```json
{
"email": "spectator@royalenfield.com"
}
```
**What Backend Does:**
- ✅ Finds/creates user from Okta/AD
- ✅ Sets spectator permissions (view + comment)
- ✅ Sends notification
---
## 📋 Complete Workflow Example
### Step 1: Login
```http
POST {{baseUrl}}/auth/login
Content-Type: application/json
{
"email": "user@royalenfield.com",
"password": "your-password"
}
```
**Response:** Save the `token` from response
---
### Step 2: Create Workflow (Simplified)
```http
POST {{baseUrl}}/workflows
Authorization: Bearer <token>
Content-Type: application/json
{
"templateType": "CUSTOM",
"title": "Purchase Order - Office Equipment",
"description": "Approval for office equipment purchase",
"priority": "STANDARD",
"approvalLevels": [
{
"email": "manager@royalenfield.com",
"tatHours": 24
}
]
}
```
**Response:** Save the `requestId` or `requestNumber`
---
### Step 3: Add Additional Approver
```http
POST {{baseUrl}}/workflows/REQ-2024-0001/approvers/at-level
Authorization: Bearer <token>
Content-Type: application/json
{
"email": "director@royalenfield.com",
"tatHours": 48,
"level": 2
}
```
---
### Step 4: Add Spectator
```http
POST {{baseUrl}}/workflows/REQ-2024-0001/participants/spectator
Authorization: Bearer <token>
Content-Type: application/json
{
"email": "hr@royalenfield.com"
}
```
---
## 🎯 Key Benefits
### Before (Old Format):
- ❌ Required user IDs, names manually
- ❌ Complex payload structure
- ❌ Manual level naming
- ❌ Manual final approver detection
### After (New Simplified Format):
- ✅ Only email required
- ✅ Simple, clean JSON
- ✅ Auto-generated level names
- ✅ Auto-detected final approver
- ✅ Auto user creation from Okta/AD
- ✅ Clear error messages
---
## 🔧 Environment Variables
Make sure to set these in Postman:
| Variable | Value | Example |
|----------|-------|---------|
| `baseUrl` | Backend API URL | `http://localhost:5000/api/v1` |
| `token` | Auth token from login | `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...` |
---
## 📝 Notes
1. **Backward Compatible:** The backend still accepts the old format, but the new format is recommended
2. **Auto User Creation:** If a user exists in Okta/AD but not in the database, they will be created automatically
3. **Smart Level Names:** Level names are generated from:
- User's designation (e.g., "Manager Approval")
- User's department (e.g., "Finance Approval")
- Fallback: "Level N Approval"
4. **Final Approver:** Last approval level is automatically marked as final approver
5. **Error Messages:** Clear, actionable error messages for invalid emails or users not found in AD
---
## ❓ Troubleshooting
### Error: "User not found in organization directory"
- **Cause:** Email doesn't exist in Okta/AD
- **Solution:** Verify email address is correct and user has an active account
### Error: "Duplicate approver email found"
- **Cause:** Same email used for multiple approval levels
- **Solution:** Each approver must have a unique email
### Error: "Invalid initiator"
- **Cause:** Auth token is invalid or user doesn't exist
- **Solution:** Re-login to get a fresh token
---
## 🚀 Quick Start
1. **Import Collection:** Import `Royal_Enfield_API_Collection.postman_collection.json` into Postman
2. **Set Environment:** Configure `baseUrl` and `token` variables
3. **Login:** Call the login endpoint to get your token
4. **Create Workflow:** Use the simplified "Create Workflow (JSON) - Simplified" endpoint
5. **Test:** Try adding approvers and spectators using the new simplified endpoints
---
**Updated:** December 2, 2025
**Version:** 2.0 - Simplified API Format

View File

@ -1,239 +0,0 @@
# User Notification Preferences
## Overview
Individual users can now control their notification preferences across three channels: **Email**, **Push**, and **In-App** notifications.
---
## Features Implemented
### ✅ Backend
1. **Database Schema**
- Added three boolean fields to `users` table:
- `email_notifications_enabled` (default: true)
- `push_notifications_enabled` (default: true)
- `in_app_notifications_enabled` (default: true)
- Migration file: `20251203-add-user-notification-preferences.ts`
2. **User Model Updates**
- `Re_Backend/src/models/User.ts`
- Added fields: `emailNotificationsEnabled`, `pushNotificationsEnabled`, `inAppNotificationsEnabled`
3. **API Endpoints**
- **GET** `/api/v1/user/preferences/notifications` - Get current user's preferences
- **PUT** `/api/v1/user/preferences/notifications` - Update preferences
- Controller: `Re_Backend/src/controllers/userPreference.controller.ts`
- Routes: `Re_Backend/src/routes/userPreference.routes.ts`
- Validator: `Re_Backend/src/validators/userPreference.validator.ts`
4. **Notification Service Enhancement**
- `Re_Backend/src/services/notification.service.ts`
- Now checks user preferences before sending notifications
- Respects individual channel settings (email, push, in-app)
### ✅ Frontend
1. **API Service**
- `Re_Figma_Code/src/services/userPreferenceApi.ts`
- Functions: `getNotificationPreferences()`, `updateNotificationPreferences()`
2. **UI Component**
- `Re_Figma_Code/src/components/settings/NotificationPreferences.tsx`
- Beautiful card-based UI with toggle switches
- Real-time updates with loading states
- Success/error feedback
3. **Settings Page Integration**
- `Re_Figma_Code/src/pages/Settings/Settings.tsx`
- Full-width notification preferences card
- Separate browser push registration button
- Available for both admin and regular users
---
## How It Works
### User Experience
1. **Navigate to Settings**
- User clicks on Settings in the navigation
2. **View Notification Preferences**
- Top card shows three toggle switches:
- 📧 **Email Notifications** - Receive notifications via email
- 🔔 **Push Notifications** - Receive browser push notifications
- 💬 **In-App Notifications** - Show notifications within the application
3. **Toggle Preferences**
- Click any switch to enable/disable that channel
- Changes are saved immediately
- Success message confirms the update
4. **Register Browser for Push** (separate card)
- One-time setup per browser/device
- Requests browser permission
- Registers the browser endpoint for push notifications
### System Behavior
**When sending notifications:**
```typescript
// System checks user preferences
if (user.inAppNotificationsEnabled) {
// Create in-app notification in database
// Emit socket event for real-time delivery
}
if (user.pushNotificationsEnabled) {
// Send browser push notification (if browser is registered)
}
if (user.emailNotificationsEnabled) {
// Send email notification (when implemented)
}
```
**Benefits:**
- ✅ Users have full control over notification channels
- ✅ Reduces notification fatigue
- ✅ Improves user experience
- ✅ Respects user preferences while ensuring critical alerts are delivered
---
## API Documentation
### Get Notification Preferences
**Request:**
```http
GET /api/v1/user/preferences/notifications
Authorization: Bearer <token>
```
**Response:**
```json
{
"success": true,
"data": {
"emailNotificationsEnabled": true,
"pushNotificationsEnabled": true,
"inAppNotificationsEnabled": true
}
}
```
### Update Notification Preferences
**Request:**
```http
PUT /api/v1/user/preferences/notifications
Authorization: Bearer <token>
Content-Type: application/json
{
"emailNotificationsEnabled": false,
"pushNotificationsEnabled": true,
"inAppNotificationsEnabled": true
}
```
**Response:**
```json
{
"success": true,
"message": "Notification preferences updated successfully",
"data": {
"emailNotificationsEnabled": false,
"pushNotificationsEnabled": true,
"inAppNotificationsEnabled": true
}
}
```
---
## Database Migration
To apply the migration:
```bash
cd Re_Backend
npm run migrate
```
This will add the three notification preference columns to the `users` table with default value `true` for all existing users.
---
## Admin Configuration vs User Preferences
### Two Levels of Control:
1. **System-Wide (Admin Only)**
- Settings → Configuration → Notification Rules
- `ENABLE_EMAIL_NOTIFICATIONS` - Master switch for email
- `ENABLE_PUSH_NOTIFICATIONS` - Master switch for push
- If admin disables a channel, it's disabled for ALL users
2. **User-Level (Individual Users)**
- Settings → User Settings → Notification Preferences
- Users can disable channels for themselves
- User preferences are respected only if admin has enabled the channel
### Logic:
```
Notification Sent = Admin Enabled AND User Enabled
```
---
## Future Enhancements
- [ ] Email notification implementation (currently just a preference toggle)
- [ ] SMS notifications support
- [ ] Granular notification types (e.g., only approval requests, only TAT alerts)
- [ ] Quiet hours / Do Not Disturb schedules
- [ ] Notification digest/batching preferences
---
## Testing Checklist
- [x] User can view their notification preferences
- [x] User can toggle email notifications on/off
- [x] User can toggle push notifications on/off
- [x] User can toggle in-app notifications on/off
- [x] Notification service respects user preferences
- [x] In-app notifications are not created if disabled
- [x] Push notifications are not sent if disabled
- [x] UI shows loading states during updates
- [x] UI shows success/error messages
- [x] Migration adds columns with correct defaults
- [x] API endpoints require authentication
- [x] Changes persist after logout/login
---
## Files Modified/Created
### Backend
- ✅ `src/models/User.ts` - Added notification preference fields
- ✅ `src/migrations/20251203-add-user-notification-preferences.ts` - Migration
- ✅ `src/controllers/userPreference.controller.ts` - New controller
- ✅ `src/routes/userPreference.routes.ts` - New routes
- ✅ `src/validators/userPreference.validator.ts` - New validator
- ✅ `src/routes/index.ts` - Registered new routes
- ✅ `src/services/notification.service.ts` - Updated to respect preferences
### Frontend
- ✅ `src/services/userPreferenceApi.ts` - New API service
- ✅ `src/components/settings/NotificationPreferences.tsx` - New component
- ✅ `src/pages/Settings/Settings.tsx` - Integrated new component
---
**Implementation Complete! 🎉**

View File

@ -1,56 +0,0 @@
-- Debug script to check TAT alerts
-- Run this to see if alerts are being created
-- 1. Check if tat_alerts table exists
SELECT
table_name,
column_name,
data_type
FROM information_schema.columns
WHERE table_name = 'tat_alerts'
ORDER BY ordinal_position;
-- 2. Count total TAT alerts
SELECT COUNT(*) as total_alerts FROM tat_alerts;
-- 3. Show recent TAT alerts (if any)
SELECT
alert_id,
threshold_percentage,
alert_sent_at,
alert_message,
metadata
FROM tat_alerts
ORDER BY alert_sent_at DESC
LIMIT 5;
-- 4. Check approval levels with TAT status
SELECT
level_id,
request_id,
level_number,
approver_name,
tat_hours,
status,
tat50_alert_sent,
tat75_alert_sent,
tat_breached,
tat_start_time
FROM approval_levels
WHERE tat_start_time IS NOT NULL
ORDER BY tat_start_time DESC
LIMIT 5;
-- 5. Check if Redis is needed (are there any pending/in-progress levels?)
SELECT
w.request_number,
al.level_number,
al.approver_name,
al.status,
al.level_start_time,
al.tat_hours
FROM approval_levels al
JOIN workflow_requests w ON al.request_id = w.request_id
WHERE al.status IN ('PENDING', 'IN_PROGRESS')
ORDER BY al.level_start_time DESC;