diff --git a/API_SIMPLIFIED_FORMAT.md b/API_SIMPLIFIED_FORMAT.md deleted file mode 100644 index 9e5ab31..0000000 --- a/API_SIMPLIFIED_FORMAT.md +++ /dev/null @@ -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 -``` - -**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 -``` - -**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 -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 -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 -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 - diff --git a/Data_Collection_Analysis.md b/Data_Collection_Analysis.md deleted file mode 100644 index 8544e93..0000000 --- a/Data_Collection_Analysis.md +++ /dev/null @@ -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 { - 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 = { - '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 = { - '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** - diff --git a/INSTALL_REDIS.txt b/INSTALL_REDIS.txt deleted file mode 100644 index 6e47b38..0000000 --- a/INSTALL_REDIS.txt +++ /dev/null @@ -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 - -======================================== - diff --git a/POSTMAN_COLLECTION_UPDATES.md b/POSTMAN_COLLECTION_UPDATES.md deleted file mode 100644 index d360275..0000000 --- a/POSTMAN_COLLECTION_UPDATES.md +++ /dev/null @@ -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 -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 -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 -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 - diff --git a/USER_NOTIFICATION_PREFERENCES.md b/USER_NOTIFICATION_PREFERENCES.md deleted file mode 100644 index 72ae7a5..0000000 --- a/USER_NOTIFICATION_PREFERENCES.md +++ /dev/null @@ -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 -``` - -**Response:** -```json -{ - "success": true, - "data": { - "emailNotificationsEnabled": true, - "pushNotificationsEnabled": true, - "inAppNotificationsEnabled": true - } -} -``` - -### Update Notification Preferences - -**Request:** -```http -PUT /api/v1/user/preferences/notifications -Authorization: Bearer -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! 🎉** - diff --git a/debug_tat_alerts.sql b/debug_tat_alerts.sql deleted file mode 100644 index fa0ee52..0000000 --- a/debug_tat_alerts.sql +++ /dev/null @@ -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; -