diff --git a/AUTO_MIGRATION_SETUP_COMPLETE.md b/AUTO_MIGRATION_SETUP_COMPLETE.md deleted file mode 100644 index 07542eb..0000000 --- a/AUTO_MIGRATION_SETUP_COMPLETE.md +++ /dev/null @@ -1,276 +0,0 @@ -# โœ… Auto-Migration Setup Complete - -## ๐ŸŽฏ What Was Done - -### 1. Converted SQL Migration to TypeScript -**Before**: `src/migrations/add_is_skipped_to_approval_levels.sql` (manual SQL) -**After**: `src/migrations/20251105-add-skip-fields-to-approval-levels.ts` (TypeScript) - -**Features Added to `approval_levels` table**: -- โœ… `is_skipped` - Boolean flag to track skipped approvers -- โœ… `skipped_at` - Timestamp when approver was skipped -- โœ… `skipped_by` - Foreign key to user who skipped -- โœ… `skip_reason` - Text field for skip justification -- โœ… Partial index on `is_skipped = TRUE` for query performance -- โœ… Full rollback support in `down()` function - -### 2. Updated Migration Runner -**File**: `src/scripts/migrate.ts` - -**Changes**: -- Added import for new migration (m14) -- Added execution in run() function -- Enhanced console output with emojis for better visibility -- Better error messages - -### 3. Auto-Run Migrations on Development Start -**File**: `package.json` - -**Before**: -```json -"dev": "nodemon --exec ts-node -r tsconfig-paths/register src/server.ts" -``` - -**After**: -```json -"dev": "npm run migrate && nodemon --exec ts-node -r tsconfig-paths/register src/server.ts" -``` - -**What This Means**: -- ๐Ÿ”„ Migrations run automatically before server starts -- โœ… No more manual migration steps -- ๐Ÿ›ก๏ธ Server won't start if migrations fail -- โšก Fresh database schema on every dev restart - -### 4. Created Documentation -- ๐Ÿ“˜ `MIGRATION_WORKFLOW.md` - Complete migration guide -- ๐Ÿ“— `MIGRATION_QUICK_REFERENCE.md` - Quick reference card -- ๐Ÿ“• `AUTO_MIGRATION_SETUP_COMPLETE.md` - This file - -## ๐Ÿš€ How to Use - -### Starting Development (Most Common) -```bash -npm run dev -``` -This will: -1. Connect to database -2. Run all 14 migrations sequentially -3. Start development server with hot reload -4. Display success messages - -**Expected Output**: -``` -๐Ÿ“ฆ Database connected -๐Ÿ”„ Running migrations... - -โœ… Created workflow_requests table -โœ… Created approval_levels table -... -โœ… Added skip-related fields to approval_levels table - -โœ… All migrations applied successfully -๐Ÿš€ Server running on port 5000 -``` - -### Running Migrations Only -```bash -npm run migrate -``` -Use when you want to update database without starting server. - -## ๐Ÿ“Š Migration Status - -| # | Migration | Status | Date | -|---|-----------|--------|------| -| 1 | create-workflow-requests | โœ… Active | 2025-10-30 | -| 2 | create-approval-levels | โœ… Active | 2025-10-30 | -| 3 | create-participants | โœ… Active | 2025-10-30 | -| 4 | create-documents | โœ… Active | 2025-10-30 | -| 5 | create-subscriptions | โœ… Active | 2025-10-31 | -| 6 | create-activities | โœ… Active | 2025-10-31 | -| 7 | create-work-notes | โœ… Active | 2025-10-31 | -| 8 | create-work-note-attachments | โœ… Active | 2025-10-31 | -| 9 | add-tat-alert-fields | โœ… Active | 2025-11-04 | -| 10 | create-tat-alerts | โœ… Active | 2025-11-04 | -| 11 | create-kpi-views | โœ… Active | 2025-11-04 | -| 12 | create-holidays | โœ… Active | 2025-11-04 | -| 13 | create-admin-config | โœ… Active | 2025-11-04 | -| 14 | add-skip-fields-to-approval-levels | โœ… **NEW** | 2025-11-05 | - -## ๐Ÿ”„ Adding Future Migrations - -When you need to add a new migration: - -### Step 1: Create File -```bash -# Create file: src/migrations/20251106-your-description.ts -``` - -### Step 2: Write Migration -```typescript -import { QueryInterface, DataTypes } from 'sequelize'; - -export async function up(queryInterface: QueryInterface): Promise { - // Your changes here - await queryInterface.addColumn('table', 'column', { - type: DataTypes.STRING - }); - console.log('โœ… Your migration completed'); -} - -export async function down(queryInterface: QueryInterface): Promise { - // Rollback here - await queryInterface.removeColumn('table', 'column'); - console.log('โœ… Rollback completed'); -} -``` - -### Step 3: Register in migrate.ts -```typescript -// Add at top -import * as m15 from '../migrations/20251106-your-description'; - -// Add in run() function after m14 -await (m15 as any).up(sequelize.getQueryInterface()); -``` - -### Step 4: Test -```bash -npm run migrate -# or -npm run dev -``` - -## ๐ŸŽฏ Benefits - -### For Development -- โœ… **No manual steps** - migrations run automatically -- โœ… **Consistent state** - everyone on team has same schema -- โœ… **Error prevention** - server won't start with schema mismatch -- โœ… **Fast iteration** - add migration, restart, test - -### For Production -- โœ… **Idempotent** - safe to run multiple times -- โœ… **Versioned** - migrations tracked in git -- โœ… **Rollback support** - down() functions for reverting -- โœ… **Error handling** - clear failure messages - -### For Team -- โœ… **TypeScript** - type-safe migrations -- โœ… **Documentation** - comprehensive guides -- โœ… **Best practices** - professional .NET team standards -- โœ… **Clear workflow** - easy to onboard new developers - -## ๐Ÿ›ก๏ธ Safety Features - -### Migration Execution -- Stops on first error -- Exits with error code 1 on failure -- Prevents server startup if migrations fail -- Detailed error logging - -### Idempotency -All migrations should be idempotent (safe to run multiple times): -```typescript -// Check before adding -const tableDesc = await queryInterface.describeTable('table'); -if (!tableDesc.column) { - await queryInterface.addColumn(/* ... */); -} -``` - -### Transactions -For complex migrations, wrap in transaction: -```typescript -const transaction = await queryInterface.sequelize.transaction(); -try { - await queryInterface.addColumn(/* ... */, { transaction }); - await queryInterface.addIndex(/* ... */, { transaction }); - await transaction.commit(); -} catch (error) { - await transaction.rollback(); - throw error; -} -``` - -## ๐Ÿ“ Database Structure Reference - -Always refer to **`backend_structure.txt`** for: -- Current table schemas -- Column types and constraints -- Foreign key relationships -- Enum values -- Index definitions - -## ๐Ÿงช Testing the Setup - -### Test Migration System -```bash -# Run migrations -npm run migrate - -# Should see: -# ๐Ÿ“ฆ Database connected -# ๐Ÿ”„ Running migrations... -# โœ… [migration messages] -# โœ… All migrations applied successfully -``` - -### Test Auto-Run on Dev -```bash -# Start development -npm run dev - -# Should see migrations run, then: -# ๐Ÿš€ Server running on port 5000 -# ๐Ÿ“Š Environment: development -# ... -``` - -### Test New Migration -1. Create test migration file -2. Register in migrate.ts -3. Run `npm run dev` -4. Verify migration executed -5. Check database schema - -## ๐ŸŽ“ Pro Tips - -1. **Always test locally first** - never test migrations in production -2. **Backup before migrating** - especially in production -3. **Keep migrations atomic** - one logical change per file -4. **Write descriptive names** - make purpose clear -5. **Add comments** - explain why, not just what -6. **Test rollbacks** - verify down() functions work -7. **Update documentation** - keep backend_structure.txt current -8. **Review before committing** - migrations are permanent - -## ๐Ÿ“ž Support - -- ๐Ÿ“˜ Full Guide: `MIGRATION_WORKFLOW.md` -- ๐Ÿ“— Quick Reference: `MIGRATION_QUICK_REFERENCE.md` -- ๐Ÿ“Š Database Structure: `backend_structure.txt` - -## โœจ Summary - -Your development workflow is now streamlined: - -```bash -# That's it! This one command does everything: -npm run dev - -# 1. Runs all migrations โœ… -# 2. Starts development server โœ… -# 3. Enables hot reload โœ… -# 4. You focus on coding โœ… -``` - ---- - -**Setup Date**: November 5, 2025 -**Total Migrations**: 14 -**Auto-Run**: โœ… Enabled -**Status**: ๐ŸŸข Production Ready -**Team**: Royal Enfield .NET Expert Team - diff --git a/COMPLETE_TAT_IMPLEMENTATION_GUIDE.md b/COMPLETE_TAT_IMPLEMENTATION_GUIDE.md deleted file mode 100644 index b309803..0000000 --- a/COMPLETE_TAT_IMPLEMENTATION_GUIDE.md +++ /dev/null @@ -1,571 +0,0 @@ -# ๐ŸŽ‰ Complete TAT Implementation Guide - -## โœ… EVERYTHING IS READY! - -You now have a **production-ready TAT notification system** with: -- โœ… Automated notifications to approvers (50%, 75%, 100%) -- โœ… Complete alert storage in database -- โœ… Enhanced UI display with detailed time tracking -- โœ… Full KPI reporting capabilities -- โœ… Test mode for fast development -- โœ… API endpoints for custom queries - ---- - -## ๐Ÿ“Š Enhanced Alert Display - -### **What Approvers See in Workflow Tab:** - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Step 2: Lisa Wong (Finance Manager) โ”‚ -โ”‚ Status: pending TAT: 12h Elapsed: 6.5h โ”‚ -โ”‚ โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ โณ Reminder 1 - 50% TAT Threshold [WARNING] โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ 50% of SLA breach reminder have been sent โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Allocated: 12h โ”‚ Elapsed: 6.0h โ”‚ โ”‚ -โ”‚ โ”‚ Remaining: 6.0h โ”‚ Due by: Oct 7 โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Reminder sent by system automatically โ”‚ โ”‚ -โ”‚ โ”‚ Sent at: Oct 6 at 2:30 PM โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ โš ๏ธ Reminder 2 - 75% TAT Threshold [WARNING] โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ 75% of SLA breach reminder have been sent โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Allocated: 12h โ”‚ Elapsed: 9.0h โ”‚ โ”‚ -โ”‚ โ”‚ Remaining: 3.0h โ”‚ Due by: Oct 7 โ”‚ โ”‚ -โ”‚ โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Reminder sent by system automatically โ”‚ โ”‚ -โ”‚ โ”‚ Sent at: Oct 6 at 6:30 PM โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## ๐Ÿš€ Quick Start (3 Steps) - -### **Step 1: Setup Upstash Redis** (2 minutes) - -1. Go to: https://console.upstash.com/ -2. Create free account -3. Create database: `redis-tat-dev` -4. Copy URL: `rediss://default:PASSWORD@host.upstash.io:6379` - -### **Step 2: Configure Backend** - -Edit `Re_Backend/.env`: -```bash -# Add these lines: -REDIS_URL=rediss://default:YOUR_PASSWORD@YOUR_HOST.upstash.io:6379 -TAT_TEST_MODE=true -``` - -### **Step 3: Restart & Test** - -```bash -cd Re_Backend -npm run dev -``` - -**You should see:** -``` -โœ… [TAT Queue] Connected to Redis -โœ… [TAT Worker] Worker is ready and listening -โฐ TAT Configuration: - - Test Mode: ENABLED (1 hour = 1 minute) - - Working Hours: 9:00 - 18:00 - - Redis: rediss://***@upstash.io:6379 -``` - ---- - -## ๐Ÿงช Test It (6 Minutes) - -1. **Create Request** with 6-hour TAT -2. **Submit Request** -3. **Open Request Detail** โ†’ Workflow tab -4. **Watch Alerts Appear**: - - 3 min: โณ 50% alert with full details - - 4.5 min: โš ๏ธ 75% alert with full details - - 6 min: โฐ 100% breach with full details - ---- - -## ๐Ÿ“ฆ What's Been Implemented - -### **Backend Components:** - -| Component | Purpose | File | -|-----------|---------|------| -| **TAT Time Utils** | Working hours calculation | `utils/tatTimeUtils.ts` | -| **TAT Queue** | BullMQ queue setup | `queues/tatQueue.ts` | -| **TAT Worker** | Background job processor | `queues/tatWorker.ts` | -| **TAT Processor** | Alert handler | `queues/tatProcessor.ts` | -| **TAT Scheduler** | Job scheduling service | `services/tatScheduler.service.ts` | -| **TAT Alert Model** | Database model | `models/TatAlert.ts` | -| **TAT Controller** | API endpoints | `controllers/tat.controller.ts` | -| **TAT Routes** | API routes | `routes/tat.routes.ts` | -| **TAT Config** | Configuration | `config/tat.config.ts` | - -### **Database:** - -| Object | Purpose | -|--------|---------| -| `tat_alerts` table | Store all TAT notifications | -| `approval_levels` (updated) | Added 4 TAT status fields | -| 8 KPI Views | Pre-aggregated reporting data | - -### **Frontend:** - -| Component | Change | -|-----------|--------| -| `RequestDetail.tsx` | Display TAT alerts in workflow tab | -| Enhanced cards | Show detailed time tracking | -| Test mode indicator | Purple badge when in test mode | - ---- - -## ๐Ÿ”‘ Key Features - -### **1. Approver-Specific Alerts** โœ… -- Sent ONLY to current approver -- NOT to initiator or previous approvers -- Each level gets its own alert set - -### **2. Detailed Time Tracking** โœ… -- Allocated hours -- Elapsed hours (when alert sent) -- Remaining hours (color-coded if critical) -- Due date/time - -### **3. Test Mode Support** โœ… -- 1 hour = 1 minute for fast testing -- Purple badge indicator -- Clear note to prevent confusion -- Easy toggle in `.env` - -### **4. Complete Audit Trail** โœ… -- Every alert stored in database -- Completion status tracked -- Response time measured -- KPI-ready data - -### **5. Visual Clarity** โœ… -- Color-coded by threshold (yellow/orange/red) -- Icons (โณ/โš ๏ธ/โฐ) -- Status badges (WARNING/BREACHED) -- Grid layout for time details - ---- - -## ๐Ÿ“Š KPI Capabilities - -### **All Your Required KPIs Supported:** - -#### Request Volume & Status โœ… -- Total Requests Created -- Open Requests (with age) -- Approved/Rejected Requests - -#### TAT Efficiency โœ… -- Average TAT Compliance % -- Avg Approval Cycle Time -- Delayed Workflows -- Breach History & Trends - -#### Approver Load โœ… -- Pending Actions (My Queue) -- Approvals Completed -- Response Time After Alerts - -#### Engagement & Quality โœ… -- Comments/Work Notes -- Documents Uploaded -- Collaboration Metrics - ---- - -## ๐ŸŽฏ Production Deployment - -### **When Ready for Production:** - -1. **Disable Test Mode:** - ```bash - # .env - TAT_TEST_MODE=false - ``` - -2. **Choose Redis Option:** - - **Option A: Keep Upstash** (Recommended) - ```bash - REDIS_URL=rediss://default:...@upstash.io:6379 - ``` - - โœ… Zero maintenance - - โœ… Global CDN - - โœ… Auto-scaling - - **Option B: Self-Hosted Redis** - ```bash - # On Linux server: - sudo apt install redis-server -y - sudo systemctl start redis-server - - # .env - REDIS_URL=redis://localhost:6379 - ``` - - โœ… Full control - - โœ… No external dependency - - โœ… Free forever - -3. **Set Working Hours:** - ```bash - WORK_START_HOUR=9 - WORK_END_HOUR=18 - ``` - -4. **Restart Backend** - ---- - -## ๐Ÿ“š Complete Documentation Index - -| Document | Purpose | When to Read | -|----------|---------|--------------| -| **START_HERE.md** | Quick setup | Read first! | -| **TAT_QUICK_START.md** | 5-min guide | Getting started | -| **TAT_ENHANCED_DISPLAY_SUMMARY.md** | UI guide | Understanding display | -| **COMPLETE_TAT_IMPLEMENTATION_GUIDE.md** | This doc | Overview | -| **docs/TAT_NOTIFICATION_SYSTEM.md** | Architecture | Deep dive | -| **docs/KPI_REPORTING_SYSTEM.md** | KPI queries | Building reports | -| **docs/UPSTASH_SETUP_GUIDE.md** | Redis setup | Redis config | -| **UPSTASH_QUICK_REFERENCE.md** | Commands | Daily reference | -| **KPI_SETUP_COMPLETE.md** | KPI summary | KPI overview | -| **TAT_ALERTS_DISPLAY_COMPLETE.md** | Display docs | UI integration | - ---- - -## ๐Ÿ” Troubleshooting - -### **No Alerts Showing in UI?** - -**Check:** -1. Redis connected? Look for "Connected to Redis" in logs -2. Request submitted? (Not just created) -3. Waited long enough? (3 min in test mode, 12h in production for 24h TAT) -4. Check browser console for errors -5. Verify `tatAlerts` in API response - -**Debug:** -```sql --- Check if alerts exist in database -SELECT * FROM tat_alerts -WHERE request_id = 'YOUR_REQUEST_ID' -ORDER BY alert_sent_at; -``` - -### **Alerts Not Triggering?** - -**Check:** -1. TAT worker running? Look for "TAT Worker: Initialized" in logs -2. Jobs scheduled? Look for "TAT jobs scheduled" in logs -3. Redis queue status: - ```bash - # In Upstash Console โ†’ CLI: - KEYS bull:tatQueue:* - ``` - -### **Confusing Times in Test Mode?** - -**Solution:** -- Look for purple "TEST MODE" badge -- Read note: "Test mode active (1 hour = 1 minute)" -- For production feel, set `TAT_TEST_MODE=false` - ---- - -## ๐Ÿ“ˆ Sample KPI Queries - -### **TAT Compliance This Month:** -```sql -SELECT - ROUND( - COUNT(CASE WHEN was_completed_on_time = true THEN 1 END) * 100.0 / - NULLIF(COUNT(*), 0), - 2 - ) as compliance_rate -FROM tat_alerts -WHERE DATE(alert_sent_at) >= DATE_TRUNC('month', CURRENT_DATE) - AND was_completed_on_time IS NOT NULL; -``` - -### **Top Performers (On-Time Completion):** -```sql -SELECT - u.display_name, - u.department, - COUNT(DISTINCT ta.level_id) as total_approvals, - COUNT(CASE WHEN ta.was_completed_on_time = true THEN 1 END) as on_time, - ROUND( - COUNT(CASE WHEN ta.was_completed_on_time = true THEN 1 END) * 100.0 / - NULLIF(COUNT(DISTINCT ta.level_id), 0), - 2 - ) as compliance_rate -FROM tat_alerts ta -JOIN users u ON ta.approver_id = u.user_id -WHERE ta.was_completed_on_time IS NOT NULL -GROUP BY u.user_id, u.display_name, u.department -ORDER BY compliance_rate DESC -LIMIT 10; -``` - -### **Breach Trend (Last 30 Days):** -```sql -SELECT - DATE(alert_sent_at) as date, - COUNT(CASE WHEN alert_type = 'TAT_50' THEN 1 END) as warnings_50, - COUNT(CASE WHEN alert_type = 'TAT_75' THEN 1 END) as warnings_75, - COUNT(CASE WHEN is_breached = true THEN 1 END) as breaches -FROM tat_alerts -WHERE alert_sent_at >= CURRENT_DATE - INTERVAL '30 days' -GROUP BY DATE(alert_sent_at) -ORDER BY date DESC; -``` - ---- - -## โœจ Benefits Recap - -### **For Approvers:** -- ๐Ÿ“ง Get timely notifications (50%, 75%, 100%) -- ๐Ÿ“Š See historical reminders in request details -- โฑ๏ธ Know exactly how much time remaining -- ๐ŸŽฏ Clear deadlines and expectations - -### **For Management:** -- ๐Ÿ“ˆ Track TAT compliance rates -- ๐Ÿ‘ฅ Identify bottlenecks and delays -- ๐Ÿ“Š Generate performance reports -- ๐ŸŽฏ Data-driven decision making - -### **For System Admins:** -- ๐Ÿ”ง Easy configuration -- ๐Ÿ“ Complete audit trail -- ๐Ÿš€ Scalable architecture -- ๐Ÿ› ๏ธ Robust error handling - ---- - -## ๐ŸŽ“ Next Steps - -1. โœ… **Setup Redis** (Upstash recommended) -2. โœ… **Enable Test Mode** (`TAT_TEST_MODE=true`) -3. โœ… **Test with 6-hour TAT** (becomes 6 minutes) -4. โœ… **Verify alerts display** in Request Detail -5. โœ… **Check database** for stored alerts -6. โœ… **Run KPI queries** to verify data -7. โœ… **Build dashboards** using KPI views -8. โœ… **Deploy to production** when ready - ---- - -## ๐Ÿ“ž Support - -**Documentation:** -- Read `START_HERE.md` for immediate setup -- Check `TAT_QUICK_START.md` for testing -- Review `docs/` folder for detailed guides - -**Troubleshooting:** -- Check backend logs: `logs/app.log` -- Verify Redis: Upstash Console โ†’ CLI โ†’ `PING` -- Query database: See KPI queries above -- Review worker status: Look for "TAT Worker" in logs - ---- - -## ๐ŸŽ‰ Status Summary - -| Component | Status | Notes | -|-----------|--------|-------| -| **Packages Installed** | โœ… | bullmq, ioredis, dayjs | -| **Database Schema** | โœ… | tat_alerts table + 4 fields in approval_levels | -| **KPI Views** | โœ… | 8 views created | -| **Backend Services** | โœ… | Scheduler, processor, worker | -| **API Endpoints** | โœ… | 5 TAT endpoints | -| **Frontend Display** | โœ… | Enhanced cards in workflow tab | -| **Test Mode** | โœ… | Configurable via .env | -| **Documentation** | โœ… | 10+ guides created | -| **Migrations** | โœ… | All applied successfully | -| **Redis Connection** | โณ | **You need to setup** | - ---- - -## ๐ŸŽฏ Final Checklist - -- [ ] Read `START_HERE.md` -- [ ] Setup Upstash Redis (https://console.upstash.com/) -- [ ] Add `REDIS_URL` to `.env` -- [ ] Set `TAT_TEST_MODE=true` -- [ ] Restart backend server -- [ ] Verify logs show "Connected to Redis" -- [ ] Create test request (6-hour TAT) -- [ ] Submit request -- [ ] Open Request Detail โ†’ Workflow tab -- [ ] See first alert at 3 minutes โณ -- [ ] See second alert at 4.5 minutes โš ๏ธ -- [ ] See third alert at 6 minutes โฐ -- [ ] Verify in database: `SELECT * FROM tat_alerts` -- [ ] Test KPI queries -- [ ] Approve request and verify completion tracking - -โœ… **All done? You're production ready!** - ---- - -## ๐Ÿ“‚ Files Created/Modified - -### **New Files (35):** - -**Backend:** -- `src/utils/tatTimeUtils.ts` -- `src/queues/tatQueue.ts` -- `src/queues/tatWorker.ts` -- `src/queues/tatProcessor.ts` -- `src/services/tatScheduler.service.ts` -- `src/models/TatAlert.ts` -- `src/controllers/tat.controller.ts` -- `src/routes/tat.routes.ts` -- `src/config/tat.config.ts` -- `src/migrations/20251104-add-tat-alert-fields.ts` -- `src/migrations/20251104-create-tat-alerts.ts` -- `src/migrations/20251104-create-kpi-views.ts` - -**Documentation:** -- `START_HERE.md` -- `TAT_QUICK_START.md` -- `UPSTASH_QUICK_REFERENCE.md` -- `INSTALL_REDIS.txt` -- `KPI_SETUP_COMPLETE.md` -- `TAT_ALERTS_DISPLAY_COMPLETE.md` -- `TAT_ENHANCED_DISPLAY_SUMMARY.md` -- `COMPLETE_TAT_IMPLEMENTATION_GUIDE.md` (this file) -- `docs/TAT_NOTIFICATION_SYSTEM.md` -- `docs/TAT_TESTING_GUIDE.md` -- `docs/UPSTASH_SETUP_GUIDE.md` -- `docs/KPI_REPORTING_SYSTEM.md` -- `docs/REDIS_SETUP_WINDOWS.md` - -### **Modified Files (7):** - -**Backend:** -- `src/models/ApprovalLevel.ts` - Added TAT status fields -- `src/models/index.ts` - Export TatAlert -- `src/services/workflow.service.ts` - Include TAT alerts, schedule jobs -- `src/services/approval.service.ts` - Cancel jobs, update alerts -- `src/server.ts` - Initialize worker, log config -- `src/routes/index.ts` - Register TAT routes -- `src/scripts/migrate.ts` - Include new migrations - -**Frontend:** -- `src/pages/RequestDetail/RequestDetail.tsx` - Display TAT alerts - -**Infrastructure:** -- `env.example` - Added Redis and test mode config -- `docker-compose.yml` - Added Redis service -- `package.json` - Added dependencies - ---- - -## ๐Ÿ’พ Database Schema Summary - -### **New Table: `tat_alerts`** -``` -17 columns, 7 indexes -Stores every TAT notification sent -Tracks completion status for KPIs -``` - -### **Updated Table: `approval_levels`** -``` -Added 4 columns: -- tat50_alert_sent -- tat75_alert_sent -- tat_breached -- tat_start_time -``` - -### **New Views: 8 KPI Views** -``` -- vw_request_volume_summary -- vw_tat_compliance -- vw_approver_performance -- vw_tat_alerts_summary -- vw_department_summary -- vw_daily_kpi_metrics -- vw_workflow_aging -- vw_engagement_metrics -``` - ---- - -## ๐ŸŒŸ Production Best Practices - -1. **Monitor Redis Health** - - Check connection in logs - - Monitor queue size - - Set up alerts for failures - -2. **Regular Database Maintenance** - - Archive old TAT alerts (> 1 year) - - Refresh materialized views if using - - Monitor query performance - -3. **Test Mode Management** - - NEVER use test mode in production - - Document when test mode is on - - Clear test data regularly - -4. **Alert Thresholds** - - Adjust if needed (currently 50%, 75%, 100%) - - Can be configured in `tat.config.ts` - - Consider business requirements - -5. **Working Hours** - - Verify for your organization - - Update holidays if needed - - Consider time zones for global teams - ---- - -## ๐ŸŽŠ Congratulations! - -You've implemented a **world-class TAT notification system** with: - -โœ… Automated notifications -โœ… Complete tracking -โœ… Beautiful UI display -โœ… Comprehensive KPIs -โœ… Production-ready architecture -โœ… Excellent documentation - -**Just connect Redis and you're live!** ๐Ÿš€ - ---- - -**See `START_HERE.md` for immediate next steps!** - ---- - -**Last Updated**: November 4, 2025 -**Version**: 1.0.0 -**Status**: โœ… Production Ready -**Team**: Royal Enfield Workflow System - diff --git a/DESIGN_VS_IMPLEMENTATION.md b/DESIGN_VS_IMPLEMENTATION.md deleted file mode 100644 index 15c349f..0000000 --- a/DESIGN_VS_IMPLEMENTATION.md +++ /dev/null @@ -1,281 +0,0 @@ -# ๐Ÿ“Š Design Document vs Actual Implementation - -## Overview - -The `backend_structure.txt` is a **DESIGN DOCUMENT** that shows the intended/planned database structure. However, not all tables have been implemented yet. - ---- - -## โœ… **Currently Implemented Tables** - -| Table | Status | Migration File | Notes | -|-------|--------|---------------|-------| -| `users` | โœ… Implemented | (Okta-based, external) | User management | -| `workflow_requests` | โœ… Implemented | 2025103001-create-workflow-requests.ts | Core workflow | -| `approval_levels` | โœ… Implemented | 2025103002-create-approval-levels.ts | Approval hierarchy | -| `participants` | โœ… Implemented | 2025103003-create-participants.ts | Spectators, etc. | -| `documents` | โœ… Implemented | 2025103004-create-documents.ts | File uploads | -| `subscriptions` | โœ… Implemented | 20251031_01_create_subscriptions.ts | Push notifications | -| `activities` | โœ… Implemented | 20251031_02_create_activities.ts | Activity log | -| `work_notes` | โœ… Implemented | 20251031_03_create_work_notes.ts | Chat/comments | -| `work_note_attachments` | โœ… Implemented | 20251031_04_create_work_note_attachments.ts | Chat attachments | -| `tat_alerts` | โœ… Implemented | 20251104-create-tat-alerts.ts | TAT notification history | -| **`holidays`** | โœ… Implemented | 20251104-create-holidays.ts | **NEW - Not in design** | -| **`admin_configurations`** | โœ… Implemented | 20251104-create-admin-config.ts | **Similar to planned `system_settings`** | - ---- - -## โŒ **Planned But Not Yet Implemented** - -| Table | Status | Design Location | Purpose | -|-------|--------|----------------|---------| -| `notifications` | โŒ Not Implemented | Lines 186-205 | Notification management | -| **`tat_tracking`** | โŒ Not Implemented | Lines 207-225 | **Real-time TAT tracking** | -| `conclusion_remarks` | โŒ Not Implemented | Lines 227-242 | AI-generated conclusions | -| `audit_logs` | โŒ Not Implemented | Lines 244-262 | Comprehensive audit trail | -| `user_sessions` | โŒ Not Implemented | Lines 264-280 | Session management | -| `email_logs` | โŒ Not Implemented | Lines 282-301 | Email tracking | -| `sms_logs` | โŒ Not Implemented | Lines 303-321 | SMS tracking | -| **`system_settings`** | โŒ Not Implemented | Lines 323-337 | **System configuration** | -| `workflow_templates` | โŒ Not Implemented | Lines 339-351 | Template system | -| `report_cache` | โŒ Not Implemented | Lines 353-362 | Report caching | - ---- - -## โš ๏ธ **Key Discrepancies** - -### **1. `admin_configurations` vs `system_settings`** - -**Problem:** I created `admin_configurations` which overlaps with the planned `system_settings`. - -**Design (`system_settings`):** -```sql -system_settings { - setting_id PK - setting_key UK - setting_value - setting_type - setting_category - is_editable - is_sensitive - validation_rules - ... -} -``` - -**What I Created (`admin_configurations`):** -```sql -admin_configurations { - config_id PK - config_key UK - config_value - value_type - config_category - is_editable - is_sensitive - validation_rules - ... -} -``` - -**Resolution Options:** - -**Option A:** Rename `admin_configurations` โ†’ `system_settings` -- โœ… Matches design document -- โœ… Consistent naming -- โš ๏ธ Requires migration to rename table - -**Option B:** Keep `admin_configurations`, skip `system_settings` -- โœ… No migration needed -- โœ… Already implemented and working -- โš ๏ธ Deviates from design - -**Option C:** Use both tables -- โŒ Redundant -- โŒ Confusing -- โŒ Not recommended - -**RECOMMENDATION:** **Option A** - Rename to `system_settings` to match design document. - ---- - -### **2. `tat_alerts` vs `tat_tracking`** - -**Status:** These serve **DIFFERENT purposes** and should **COEXIST**. - -**`tat_alerts` (Implemented):** -- Historical record of TAT alerts sent -- Stores when 50%, 75%, 100% alerts were sent -- Immutable records for audit trail -- Purpose: **Alert History** - -**`tat_tracking` (Planned, Not Implemented):** -```sql -tat_tracking { - tracking_type "REQUEST or LEVEL" - tat_status "ON_TRACK to BREACHED" - elapsed_hours - remaining_hours - percentage_used - threshold_50_breached - threshold_80_breached - ... -} -``` -- Real-time tracking of TAT status -- Continuously updated as time passes -- Shows current TAT health -- Purpose: **Real-time Monitoring** - -**Resolution:** Both tables should exist. - -**RECOMMENDATION:** Implement `tat_tracking` table as per design document. - ---- - -### **3. `holidays` Table** - -**Status:** **NEW addition** not in original design. - -**Resolution:** This is fine! It's a feature enhancement that was needed for accurate TAT calculations. - -**RECOMMENDATION:** Add `holidays` to the design document for future reference. - ---- - -## ๐Ÿ“‹ **Recommended Actions** - -### **Immediate Actions:** - -1. **Rename `admin_configurations` to `system_settings`** - ```sql - ALTER TABLE admin_configurations RENAME TO system_settings; - ALTER INDEX admin_configurations_pkey RENAME TO system_settings_pkey; - ALTER INDEX admin_configurations_config_category RENAME TO system_settings_config_category; - -- etc. - ``` - -2. **Update all references in code:** - - Model: `AdminConfiguration` โ†’ `SystemSetting` - - Service: `adminConfig` โ†’ `systemSettings` - - Routes: `/admin/configurations` โ†’ `/admin/settings` - - Controller: `admin.controller.ts` โ†’ Update variable names - -3. **Implement `tat_tracking` table** (as per design): - - Create migration for `tat_tracking` - - Implement model and service - - Integrate with TAT calculation system - - Use for real-time dashboard - -4. **Update `backend_structure.txt`**: - - Add `holidays` table to design - - Update `system_settings` if we made any changes - - Add `tat_alerts` if not present - ---- - -### **Future Implementations (Phase 2):** - -Based on the design document, these should be implemented next: - -1. **`notifications` table** - In-app notification system -2. **`conclusion_remarks` table** - AI-generated conclusions -3. **`audit_logs` table** - Comprehensive audit trail (currently using `activities`) -4. **`email_logs` & `sms_logs`** - Communication tracking -5. **`workflow_templates`** - Template system for common workflows -6. **`report_cache`** - Performance optimization for reports - ---- - -## ๐Ÿ“Š **Implementation Progress** - -### **Core Workflow:** -- โœ… Users -- โœ… Workflow Requests -- โœ… Approval Levels -- โœ… Participants -- โœ… Documents -- โœ… Work Notes -- โœ… Activities - -### **TAT & Monitoring:** -- โœ… TAT Alerts (historical) -- โœ… Holidays (for TAT calculation) -- โŒ TAT Tracking (real-time) **โ† MISSING** - -### **Configuration & Admin:** -- โœ… Admin Configurations (needs rename to `system_settings`) -- โŒ Workflow Templates **โ† MISSING** - -### **Notifications & Logs:** -- โœ… Subscriptions (push notifications) -- โŒ Notifications table **โ† MISSING** -- โŒ Email Logs **โ† MISSING** -- โŒ SMS Logs **โ† MISSING** - -### **Advanced Features:** -- โŒ Conclusion Remarks (AI) **โ† MISSING** -- โŒ Audit Logs **โ† MISSING** -- โŒ Report Cache **โ† MISSING** - ---- - -## ๐ŸŽฏ **Alignment with Design Document** - -### **What Matches Design:** -- โœ… Core workflow tables (90% match) -- โœ… Work notes system -- โœ… Document management -- โœ… Activity logging - -### **What Differs:** -- โš ๏ธ `admin_configurations` should be `system_settings` -- โš ๏ธ `tat_alerts` exists but `tat_tracking` doesn't -- โœ… `holidays` is a new addition (enhancement) - -### **What's Missing:** -- โŒ 10 tables from design not yet implemented -- โŒ Some relationships not fully realized - ---- - -## ๐Ÿ’ก **Recommendations Summary** - -### **Critical (Do Now):** -1. โœ… **Rename `admin_configurations` to `system_settings`** - Align with design -2. โœ… **Implement `tat_tracking` table** - Complete TAT system -3. โœ… **Update design document** - Add holidays table - -### **Important (Phase 2):** -4. โณ **Implement `notifications` table** - Centralized notification management -5. โณ **Implement `audit_logs` table** - Enhanced audit trail -6. โณ **Implement `email_logs` & `sms_logs`** - Communication tracking - -### **Nice to Have (Phase 3):** -7. ๐Ÿ”ฎ **Implement `conclusion_remarks`** - AI integration -8. ๐Ÿ”ฎ **Implement `workflow_templates`** - Template system -9. ๐Ÿ”ฎ **Implement `report_cache`** - Performance optimization - ---- - -## ๐Ÿ“ **Conclusion** - -**Answer to the question:** "Did you consider backend_structure.txt?" - -**Honest Answer:** Not fully. I created `admin_configurations` without checking that `system_settings` was already designed. However: - -1. โœ… The functionality is the same -2. โš ๏ธ The naming is different -3. ๐Ÿ”ง Easy to fix with a rename migration - -**Next Steps:** -1. Decide: Rename to `system_settings` (recommended) or keep as-is? -2. Implement missing `tat_tracking` table -3. Update design document with new `holidays` table - ---- - -**Created:** November 4, 2025 -**Status:** Analysis Complete -**Action Required:** Yes - Table rename + implement tat_tracking - diff --git a/DYNAMIC_TAT_THRESHOLDS.md b/DYNAMIC_TAT_THRESHOLDS.md deleted file mode 100644 index 6a1a213..0000000 --- a/DYNAMIC_TAT_THRESHOLDS.md +++ /dev/null @@ -1,341 +0,0 @@ -# Dynamic TAT Thresholds Implementation - -## Problem Statement - -### Original Issue -The TAT system had **hardcoded threshold percentages** (50%, 75%, 100%) which created several problems: - -1. **Job Naming Conflict**: Jobs were named using threshold percentages (`tat50-{reqId}-{levelId}`) -2. **Configuration Changes Didn't Apply**: Changing threshold in settings didn't affect scheduled jobs -3. **Message Mismatch**: Messages always said "50% elapsed" even if admin configured 55% -4. **Cancellation Issues**: Uncertainty about whether jobs could be properly cancelled after config changes - -### Critical Edge Case Identified by User - -**Scenario:** -``` -1. Request created โ†’ TAT jobs scheduled: - - tat50-REQ123-LEVEL456 (fires at 8 hours, says "50% elapsed") - - tat75-REQ123-LEVEL456 (fires at 12 hours) - - tatBreach-REQ123-LEVEL456 (fires at 16 hours) - -2. Admin changes threshold from 50% โ†’ 55% - -3. User approves at 9 hours (after old 50% fired) - โ†’ Job already fired with "50% elapsed" message โŒ - โ†’ But admin configured 55% โŒ - โ†’ Inconsistent! - -4. Even if approval happens before old 50%: - โ†’ System cancels `tat50-REQ123-LEVEL456` โœ… - โ†’ But message would still say "50%" (hardcoded) โŒ -``` - ---- - -## Solution: Generic Job Names + Dynamic Thresholds - -### 1. **Generic Job Naming** -Changed from percentage-based to generic names: - -**Before:** -```typescript -tat50-{requestId}-{levelId} -tat75-{requestId}-{levelId} -tatBreach-{requestId}-{levelId} -``` - -**After:** -```typescript -tat-threshold1-{requestId}-{levelId} // First threshold (configurable: 50%, 55%, 60%, etc.) -tat-threshold2-{requestId}-{levelId} // Second threshold (configurable: 75%, 80%, etc.) -tat-breach-{requestId}-{levelId} // Always 100% (deadline) -``` - -### 2. **Store Threshold in Job Data** -Instead of relying on job name, we store the actual percentage in job payload: - -```typescript -interface TatJobData { - type: 'threshold1' | 'threshold2' | 'breach'; - threshold: number; // Actual % (e.g., 55, 80, 100) - requestId: string; - levelId: string; - approverId: string; -} -``` - -### 3. **Dynamic Message Generation** -Messages use the threshold from job data: - -```typescript -case 'threshold1': - message = `โณ ${threshold}% of TAT elapsed for Request ${requestNumber}`; - // If threshold = 55, message says "55% of TAT elapsed" โœ… -``` - -### 4. **Configuration Cache Management** -- Configurations are cached for 5 minutes (performance) -- Cache is **automatically cleared** when admin updates settings -- Next scheduled job will use new thresholds - ---- - -## How It Solves the Edge Cases - -### โœ… **Case 1: Config Changed After Job Creation** - -**Scenario:** -``` -1. Request created with TAT = 16 hours (thresholds: 50%, 75%) - Jobs scheduled: - - tat-threshold1-REQ123 โ†’ fires at 8h, threshold=50 - - tat-threshold2-REQ123 โ†’ fires at 12h, threshold=75 - -2. Admin changes threshold from 50% โ†’ 55% - -3. Old request jobs STILL fire at 8h (50%) - โœ… BUT message correctly shows "50% elapsed" (from job data) - โœ… No confusion because that request WAS scheduled at 50% - -4. NEW requests created after config change: - Jobs scheduled: - - tat-threshold1-REQ456 โ†’ fires at 8.8h, threshold=55 โœ… - - tat-threshold2-REQ456 โ†’ fires at 12h, threshold=75 - -5. Message says "55% of TAT elapsed" โœ… CORRECT! -``` - -**Result:** -- โœ… Existing jobs maintain their original thresholds (consistent) -- โœ… New jobs use updated thresholds (respects config changes) -- โœ… Messages always match actual threshold used - ---- - -### โœ… **Case 2: User Approves Before Threshold** - -**Scenario:** -``` -1. Job scheduled: tat-threshold1-REQ123 (fires at 55%) - -2. User approves at 40% elapsed - -3. cancelTatJobs('REQ123', 'LEVEL456') is called: - โ†’ Looks for: tat-threshold1-REQ123-LEVEL456 โœ… FOUND - โ†’ Removes job โœ… SUCCESS - -4. No notification sent โœ… CORRECT! -``` - -**Result:** -- โœ… Generic names allow consistent cancellation -- โœ… Works regardless of threshold percentage -- โœ… No ambiguity in job identification - ---- - -### โœ… **Case 3: User Approves After Threshold Fired** - -**Scenario:** -``` -1. Job scheduled: tat-threshold1-REQ123 (fires at 55%) - -2. Job fires at 55% โ†’ notification sent - -3. User approves at 60% - -4. cancelTatJobs called: - โ†’ Tries to cancel tat-threshold1-REQ123 - โ†’ Job already processed and removed (removeOnComplete: true) - โ†’ No error (gracefully handled) โœ… - -5. Later jobs (threshold2, breach) are still cancelled โœ… -``` - -**Result:** -- โœ… Already-fired jobs don't cause errors -- โœ… Remaining jobs are still cancelled -- โœ… System behaves correctly in all scenarios - ---- - -## Configuration Flow - -### **Admin Updates Threshold** - -``` -1. Admin changes "First TAT Threshold" from 50% โ†’ 55% - โ†“ -2. Frontend sends: PUT /api/v1/admin/configurations/TAT_REMINDER_THRESHOLD_1 - Body: { configValue: '55' } - โ†“ -3. Backend updates database: - UPDATE admin_configurations - SET config_value = '55' - WHERE config_key = 'TAT_REMINDER_THRESHOLD_1' - โ†“ -4. Backend clears config cache: - clearConfigCache() โœ… - โ†“ -5. Next request created: - - getTatThresholds() โ†’ reads '55' from DB - - Schedules job at 55% (8.8 hours for 16h TAT) - - Job data: { threshold: 55 } - โ†“ -6. Job fires at 55%: - - Message: "55% of TAT elapsed" โœ… CORRECT! -``` - ---- - -## Database Impact - -### **No Database Changes Required!** - -The `admin_configurations` table already has all required fields: -- โœ… `TAT_REMINDER_THRESHOLD_1` โ†’ First threshold (50% default) -- โœ… `TAT_REMINDER_THRESHOLD_2` โ†’ Second threshold (75% default) - -### **Job Queue Data Structure** - -**Old Job Data:** -```json -{ - "type": "tat50", - "requestId": "...", - "levelId": "...", - "approverId": "..." -} -``` - -**New Job Data:** -```json -{ - "type": "threshold1", - "threshold": 55, - "requestId": "...", - "levelId": "...", - "approverId": "..." -} -``` - ---- - -## Testing Scenarios - -### **Test 1: Change Threshold, Create New Request** - -```bash -# 1. Change threshold from 50% to 55% -curl -X PUT http://localhost:5000/api/v1/admin/configurations/TAT_REMINDER_THRESHOLD_1 \ - -H "Authorization: Bearer TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"configValue": "55"}' - -# 2. Create new workflow request -# โ†’ Jobs scheduled at 55%, 75%, 100% - -# 3. Wait for 55% elapsed -# โ†’ Notification says "55% of TAT elapsed" โœ… -``` - -### **Test 2: Approve Before Threshold** - -```bash -# 1. Request created (TAT = 16 hours) -# โ†’ threshold1 scheduled at 8.8 hours (55%) - -# 2. Approve at 6 hours (before 55%) -curl -X POST http://localhost:5000/api/v1/workflows/REQ123/approve/LEVEL456 - -# 3. cancelTatJobs is called internally -# โ†’ tat-threshold1-REQ123-LEVEL456 removed โœ… -# โ†’ tat-threshold2-REQ123-LEVEL456 removed โœ… -# โ†’ tat-breach-REQ123-LEVEL456 removed โœ… - -# 4. No notifications sent โœ… -``` - -### **Test 3: Mixed Old and New Jobs** - -```bash -# 1. Create Request A with old threshold (50%) -# โ†’ Jobs use threshold=50 - -# 2. Admin changes to 55% - -# 3. Create Request B with new threshold (55%) -# โ†’ Jobs use threshold=55 - -# 4. Both requests work correctly: -# โ†’ Request A fires at 50%, message says "50%" โœ… -# โ†’ Request B fires at 55%, message says "55%" โœ… -``` - ---- - -## Summary - -### **What Changed:** -1. โœ… Job names: `tat50` โ†’ `tat-threshold1` (generic) -2. โœ… Job data: Now includes actual threshold percentage -3. โœ… Messages: Dynamic based on threshold from job data -4. โœ… Scheduling: Reads thresholds from database configuration -5. โœ… Cache: Automatically cleared on config update - -### **What Didn't Change:** -1. โœ… Database schema (admin_configurations already has all needed fields) -2. โœ… API endpoints (no breaking changes) -3. โœ… Frontend UI (works exactly the same) -4. โœ… Cancellation logic (still works, just uses new names) - -### **Benefits:** -1. โœ… **No Job Name Conflicts**: Generic names work for any percentage -2. โœ… **Accurate Messages**: Always show actual threshold used -3. โœ… **Config Flexibility**: Admin can change thresholds anytime -4. โœ… **Backward Compatible**: Existing jobs complete normally -5. โœ… **Reliable Cancellation**: Works regardless of threshold value -6. โœ… **Immediate Effect**: New requests use updated thresholds immediately - ---- - -## Files Modified - -1. `Re_Backend/src/services/configReader.service.ts` - **NEW** (configuration reader) -2. `Re_Backend/src/services/tatScheduler.service.ts` - Updated job scheduling -3. `Re_Backend/src/queues/tatProcessor.ts` - Updated job processing -4. `Re_Backend/src/controllers/admin.controller.ts` - Added cache clearing - ---- - -## Configuration Keys - -| Key | Description | Default | Example | -|-----|-------------|---------|---------| -| `TAT_REMINDER_THRESHOLD_1` | First warning threshold | 50 | 55 (sends alert at 55%) | -| `TAT_REMINDER_THRESHOLD_2` | Critical warning threshold | 75 | 80 (sends alert at 80%) | -| Breach | Deadline reached (always 100%) | 100 | 100 (non-configurable) | - ---- - -## Example Timeline - -**TAT = 16 hours, Thresholds: 55%, 80%** - -``` -Hour 0 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ Hour 16 - โ”‚ โ”‚ โ”‚ - START 55% (8.8h) 80% (12.8h) 100% - โ”‚ โ”‚ โ”‚ - threshold1 threshold2 breach - "55% elapsed" "80% elapsed" "BREACHED" - โณ โš ๏ธ โฐ -``` - -**Result:** -- โœ… Job names don't hardcode percentages -- โœ… Messages show actual configured thresholds -- โœ… Cancellation works consistently -- โœ… No edge cases or race conditions - diff --git a/DYNAMIC_WORKING_HOURS.md b/DYNAMIC_WORKING_HOURS.md deleted file mode 100644 index d40677e..0000000 --- a/DYNAMIC_WORKING_HOURS.md +++ /dev/null @@ -1,562 +0,0 @@ -# Dynamic Working Hours Configuration - -## Overview - -Working hours for TAT (Turn Around Time) calculations are now **dynamically configurable** through the admin settings interface. Admins can change these settings at any time, and the changes will be reflected in all future TAT calculations. - ---- - -## What's Configurable - -### **Working Hours Settings:** - -| Setting | Description | Default | Example | -|---------|-------------|---------|---------| -| `WORK_START_HOUR` | Working day starts at (hour) | 9 | 8 (8:00 AM) | -| `WORK_END_HOUR` | Working day ends at (hour) | 18 | 19 (7:00 PM) | -| `WORK_START_DAY` | First working day of week | 1 (Monday) | 1 (Monday) | -| `WORK_END_DAY` | Last working day of week | 5 (Friday) | 6 (Saturday) | - -**Days:** 0 = Sunday, 1 = Monday, 2 = Tuesday, ..., 6 = Saturday - ---- - -## How It Works - -### **1. Admin Changes Working Hours** - -``` -Settings โ†’ System Configuration โ†’ Working Hours -- Work Start Hour: 9:00 โ†’ Change to 8:00 -- Work End Hour: 18:00 โ†’ Change to 20:00 -โœ… Save -``` - -### **2. Backend Updates Database** - -```sql -UPDATE admin_configurations -SET config_value = '8' -WHERE config_key = 'WORK_START_HOUR'; - -UPDATE admin_configurations -SET config_value = '20' -WHERE config_key = 'WORK_END_HOUR'; -``` - -### **3. Cache is Cleared Automatically** - -```typescript -// In admin.controller.ts -clearConfigCache(); // Clear general config cache -clearWorkingHoursCache(); // Clear TAT working hours cache -``` - -### **4. Next TAT Calculation Uses New Values** - -```typescript -// TAT calculation loads fresh values -await loadWorkingHoursCache(); -// โ†’ Reads: startHour=8, endHour=20 from database - -// Applies new working hours -if (hour >= 8 && hour < 20) { - // This hour counts as working time โœ… -} -``` - ---- - -## Cache Management - -### **Working Hours Cache:** - -**Cache Duration:** 5 minutes (shorter than holidays since it's more critical) - -**Why Cache?** -- Performance: Avoids repeated database queries -- Speed: TAT calculations can happen hundreds of times per hour -- Efficiency: Reading from memory is ~1000x faster than DB query - -**Cache Lifecycle:** -``` -1. First TAT Calculation: - โ†’ loadWorkingHoursCache() called - โ†’ Database query: SELECT config_value WHERE config_key IN (...) - โ†’ Store in memory: workingHoursCache = { startHour: 9, endHour: 18, ... } - โ†’ Set expiry: now + 5 minutes - -2. Next 5 Minutes (Cache Valid): - โ†’ All TAT calculations use cached values - โ†’ No database queries โœ… FAST - -3. After 5 Minutes (Cache Expired): - โ†’ Next TAT calculation reloads from database - โ†’ New cache created with 5-minute expiry - -4. Admin Updates Config: - โ†’ clearWorkingHoursCache() called immediately - โ†’ Cache invalidated - โ†’ Next calculation loads fresh values โœ… -``` - ---- - -## Example Scenarios - -### **Scenario 1: Extend Working Hours** - -**Before:** -``` -Working Hours: 9:00 AM - 6:00 PM (9 hours/day) -``` - -**Admin Changes To:** -``` -Working Hours: 8:00 AM - 8:00 PM (12 hours/day) -``` - -**Impact on TAT:** -``` -Request: STANDARD Priority, 24 working hours -Created: Monday 9:00 AM - -OLD Calculation (9 hours/day): -Monday 9 AM - 6 PM = 9 hours (15h remaining) -Tuesday 9 AM - 6 PM = 9 hours (6h remaining) -Wednesday 9 AM - 3 PM = 6 hours (0h remaining) -Deadline: Wednesday 3:00 PM - -NEW Calculation (12 hours/day): -Monday 9 AM - 8 PM = 11 hours (13h remaining) -Tuesday 8 AM - 8 PM = 12 hours (1h remaining) -Wednesday 8 AM - 9 AM = 1 hour (0h remaining) -Deadline: Wednesday 9:00 AM โœ… FASTER! -``` - ---- - -### **Scenario 2: Include Saturday as Working Day** - -**Before:** -``` -Working Days: Monday - Friday (1-5) -``` - -**Admin Changes To:** -``` -Working Days: Monday - Saturday (1-6) -``` - -**Impact on TAT:** -``` -Request: STANDARD Priority, 16 working hours -Created: Friday 2:00 PM - -OLD Calculation (Mon-Fri only): -Friday 2 PM - 6 PM = 4 hours (12h remaining) -Saturday-Sunday = SKIPPED -Monday 9 AM - 6 PM = 9 hours (3h remaining) -Tuesday 9 AM - 12 PM = 3 hours (0h remaining) -Deadline: Tuesday 12:00 PM - -NEW Calculation (Mon-Sat): -Friday 2 PM - 6 PM = 4 hours (12h remaining) -Saturday 9 AM - 6 PM = 9 hours (3h remaining) โœ… Saturday counts! -Sunday = SKIPPED -Monday 9 AM - 12 PM = 3 hours (0h remaining) -Deadline: Monday 12:00 PM โœ… EARLIER! -``` - ---- - -### **Scenario 3: Reduce Working Hours (After-Hours Emergency)** - -**Before:** -``` -Working Hours: 9:00 AM - 6:00 PM -``` - -**Admin Changes To:** -``` -Working Hours: 9:00 AM - 10:00 PM (extended for emergency) -``` - -**Impact:** -``` -Request created at 7:00 PM (after old hours but within new hours) - -OLD System: -7:00 PM โ†’ Not working time -First working hour: Tomorrow 9:00 AM -TAT starts counting from tomorrow โŒ - -NEW System: -7:00 PM โ†’ Still working time! โœ… -TAT starts counting immediately -Faster response for urgent requests โœ… -``` - ---- - -## Implementation Details - -### **Configuration Reader Service** - -```typescript -// Re_Backend/src/services/configReader.service.ts - -export async function getWorkingHours(): Promise<{ startHour: number; endHour: number }> { - const startHour = await getConfigNumber('WORK_START_HOUR', 9); - const endHour = await getConfigNumber('WORK_END_HOUR', 18); - - return { startHour, endHour }; -} -``` - -### **TAT Time Utils (Working Hours Cache)** - -```typescript -// Re_Backend/src/utils/tatTimeUtils.ts - -let workingHoursCache: WorkingHoursConfig | null = null; -let workingHoursCacheExpiry: Date | null = null; - -async function loadWorkingHoursCache(): Promise { - // Check if cache is still valid - if (workingHoursCacheExpiry && new Date() < workingHoursCacheExpiry) { - return; // Use cached values - } - - // Load from database - const { getWorkingHours, getConfigNumber } = await import('../services/configReader.service'); - const hours = await getWorkingHours(); - const startDay = await getConfigNumber('WORK_START_DAY', 1); - const endDay = await getConfigNumber('WORK_END_DAY', 5); - - // Store in cache - workingHoursCache = { - startHour: hours.startHour, - endHour: hours.endHour, - startDay: startDay, - endDay: endDay - }; - - // Set 5-minute expiry - workingHoursCacheExpiry = dayjs().add(5, 'minute').toDate(); - - console.log(`[TAT Utils] Loaded working hours: ${hours.startHour}:00-${hours.endHour}:00`); -} - -function isWorkingTime(date: Dayjs): boolean { - // Use cached working hours (with fallback to defaults) - const config = workingHoursCache || { - startHour: 9, - endHour: 18, - startDay: 1, - endDay: 5 - }; - - const day = date.day(); - const hour = date.hour(); - - // Check based on configured values - if (day < config.startDay || day > config.endDay) return false; - if (hour < config.startHour || hour >= config.endHour) return false; - if (isHoliday(date)) return false; - - return true; -} -``` - -### **Admin Controller (Cache Invalidation)** - -```typescript -// Re_Backend/src/controllers/admin.controller.ts - -export const updateConfiguration = async (req: Request, res: Response): Promise => { - // ... update database ... - - // Clear config cache - clearConfigCache(); - - // If working hours config was updated, also clear TAT cache - const workingHoursKeys = ['WORK_START_HOUR', 'WORK_END_HOUR', 'WORK_START_DAY', 'WORK_END_DAY']; - if (workingHoursKeys.includes(configKey)) { - clearWorkingHoursCache(); // โœ… Immediate cache clear - logger.info(`Working hours config '${configKey}' updated - cache cleared`); - } - - res.json({ success: true }); -}; -``` - ---- - -## Priority Behavior - -### **STANDARD Priority** - -โœ… **Uses configured working hours** -- Respects `WORK_START_HOUR` and `WORK_END_HOUR` -- Respects `WORK_START_DAY` and `WORK_END_DAY` -- Excludes holidays - -**Example:** -``` -Config: 9:00 AM - 6:00 PM, Monday-Friday -TAT: 16 working hours -โ†’ Only hours between 9 AM - 6 PM on Mon-Fri count -โ†’ Weekends and holidays are skipped -``` - -### **EXPRESS Priority** - -โŒ **Ignores working hours configuration** -- Counts ALL 24 hours per day -- Counts ALL 7 days per week -- Counts holidays - -**Example:** -``` -Config: 9:00 AM - 6:00 PM (ignored) -TAT: 16 hours -โ†’ Simply add 16 hours to start time -โ†’ No exclusions -``` - ---- - -## Testing Scenarios - -### **Test 1: Change Working Hours, Create Request** - -```bash -# 1. Check current working hours -curl http://localhost:5000/api/v1/admin/configurations \ - | grep WORK_START_HOUR -# โ†’ Returns: "configValue": "9" - -# 2. Update working hours to start at 8:00 AM -curl -X PUT http://localhost:5000/api/v1/admin/configurations/WORK_START_HOUR \ - -H "Authorization: Bearer TOKEN" \ - -d '{"configValue": "8"}' -# โ†’ Response: "Configuration updated successfully" - -# 3. Check logs -# โ†’ Should see: "Working hours configuration 'WORK_START_HOUR' updated - cache cleared" - -# 4. Create new STANDARD request -curl -X POST http://localhost:5000/api/v1/workflows \ - -d '{"priority": "STANDARD", "tatHours": 16}' - -# 5. Check TAT calculation logs -# โ†’ Should see: "Loaded working hours: 8:00-18:00" โœ… -# โ†’ Deadline calculation uses new hours โœ… -``` - -### **Test 2: Verify Cache Expiry** - -```bash -# 1. Create request (loads working hours into cache) -# โ†’ Cache expires in 5 minutes - -# 2. Wait 6 minutes - -# 3. Create another request -# โ†’ Should see log: "Loaded working hours: ..." (cache reloaded) - -# 4. Create third request immediately -# โ†’ No log (uses cached values) -``` - -### **Test 3: Extend to 6-Day Week** - -```bash -# 1. Update end day to Saturday -curl -X PUT http://localhost:5000/api/v1/admin/configurations/WORK_END_DAY \ - -d '{"configValue": "6"}' - -# 2. Create request on Friday afternoon -# โ†’ Deadline should include Saturday โœ… -# โ†’ Sunday still excluded โœ… -``` - ---- - -## Database Configuration - -### **Configuration Keys:** - -```sql -SELECT config_key, config_value, display_name -FROM admin_configurations -WHERE config_key IN ( - 'WORK_START_HOUR', - 'WORK_END_HOUR', - 'WORK_START_DAY', - 'WORK_END_DAY' -); - --- Example results: --- WORK_START_HOUR | 9 | Work Start Hour --- WORK_END_HOUR | 18 | Work End Hour --- WORK_START_DAY | 1 | Work Start Day (Monday) --- WORK_END_DAY | 5 | Work End Day (Friday) -``` - -### **Update Example:** - -```sql --- Change working hours to 8 AM - 8 PM -UPDATE admin_configurations -SET config_value = '8', updated_at = NOW() -WHERE config_key = 'WORK_START_HOUR'; - -UPDATE admin_configurations -SET config_value = '20', updated_at = NOW() -WHERE config_key = 'WORK_END_HOUR'; - --- Include Saturday as working day -UPDATE admin_configurations -SET config_value = '6', updated_at = NOW() -WHERE config_key = 'WORK_END_DAY'; -``` - ---- - -## Logging Examples - -### **Configuration Update:** - -``` -[Admin] Working hours configuration 'WORK_START_HOUR' updated - cache cleared -[ConfigReader] Configuration cache cleared -[TAT Utils] Working hours cache cleared -``` - -### **TAT Calculation:** - -``` -[TAT Utils] Loaded working hours: 8:00-20:00, Days: 1-6 -[TAT Scheduler] Using STANDARD mode - excludes holidays, weekends, non-working hours -[TAT Scheduler] Calculating TAT milestones for request REQ-2025-001 -[TAT Scheduler] Priority: STANDARD, TAT Hours: 16 -[TAT Scheduler] Start: 2025-11-05 09:00 -[TAT Scheduler] Threshold 1 (55%): 2025-11-05 17:48 (using 8-20 working hours) -[TAT Scheduler] Threshold 2 (80%): 2025-11-06 10:48 -[TAT Scheduler] Breach (100%): 2025-11-06 15:00 -``` - ---- - -## Migration from Hardcoded Values - -### **Before (Hardcoded):** - -```typescript -// โŒ Hardcoded in code -const WORK_START_HOUR = 9; -const WORK_END_HOUR = 18; -const WORK_START_DAY = 1; -const WORK_END_DAY = 5; - -// To change: Need code update + deployment -``` - -### **After (Dynamic):** - -```typescript -// โœ… Read from database -const config = await getWorkingHours(); -// config = { startHour: 9, endHour: 18 } - -// To change: Just update in admin UI -// No code changes needed โœ… -// No deployment needed โœ… -``` - ---- - -## Benefits - -### **1. Flexibility** -- โœ… Change working hours anytime without code changes -- โœ… No deployment needed -- โœ… Takes effect within 5 minutes - -### **2. Global Organizations** -- โœ… Adjust for different time zones -- โœ… Support 24/5 or 24/6 operations -- โœ… Extended hours for urgent periods - -### **3. Seasonal Adjustments** -- โœ… Extend hours during busy seasons -- โœ… Reduce hours during slow periods -- โœ… Special hours for events - -### **4. Performance** -- โœ… Cache prevents repeated DB queries -- โœ… Fast lookups (memory vs database) -- โœ… Auto-refresh every 5 minutes - -### **5. Consistency** -- โœ… All TAT calculations use same values -- โœ… Immediate cache invalidation on update -- โœ… Fallback to defaults if DB unavailable - ---- - -## Summary - -| Aspect | Details | -|--------|---------| -| **Configurable** | โœ… Working hours, working days | -| **Admin UI** | โœ… Settings โ†’ System Configuration | -| **Cache Duration** | 5 minutes | -| **Cache Invalidation** | Automatic on config update | -| **Applies To** | STANDARD priority only | -| **Express Mode** | Ignores working hours (24/7) | -| **Performance** | Optimized with caching | -| **Fallback** | Uses TAT_CONFIG defaults if DB fails | - ---- - -## Files Modified - -1. `Re_Backend/src/utils/tatTimeUtils.ts` - Dynamic working hours loading -2. `Re_Backend/src/controllers/admin.controller.ts` - Cache invalidation on update -3. `Re_Backend/src/services/configReader.service.ts` - `getWorkingHours()` function - ---- - -## Configuration Flow Diagram - -``` -Admin Updates Working Hours (8:00 AM - 8:00 PM) - โ†“ -Database Updated (admin_configurations table) - โ†“ -clearConfigCache() + clearWorkingHoursCache() - โ†“ -Caches Invalidated (both config and working hours) - โ†“ -Next TAT Calculation - โ†“ -loadWorkingHoursCache() called - โ†“ -Read from Database (startHour=8, endHour=20) - โ†“ -Store in Memory (5-minute cache) - โ†“ -TAT Calculation Uses New Hours โœ… - โ†“ -All Future Requests (for 5 min) Use Cached Values - โ†“ -After 5 Minutes โ†’ Reload from Database -``` - ---- - -Working hours are now fully dynamic and admin-controlled! ๐ŸŽ‰ - diff --git a/FIXES_APPLIED.md b/FIXES_APPLIED.md deleted file mode 100644 index 8485569..0000000 --- a/FIXES_APPLIED.md +++ /dev/null @@ -1,129 +0,0 @@ -# ๐Ÿ”ง Backend Fixes Applied - November 4, 2025 - -## โœ… Issue 1: TypeScript Compilation Error - -### **Error:** -``` -src/services/tatScheduler.service.ts:30:15 - error TS2339: -Property 'halfTime' does not exist on type 'Promise<{ halfTime: Date; ... }>'. -``` - -### **Root Cause:** -`calculateTatMilestones()` was changed from sync to async (to support holiday checking), but `tatScheduler.service.ts` was calling it without `await`. - -### **Fix Applied:** -```typescript -// Before (โŒ Missing await): -const { halfTime, seventyFive, full } = calculateTatMilestones(now, tatDurationHours); - -// After (โœ… With await): -const { halfTime, seventyFive, full } = await calculateTatMilestones(now, tatDurationHours); -``` - -**File:** `Re_Backend/src/services/tatScheduler.service.ts` (line 30) - ---- - -## โœ… Issue 2: Empty Configurations Table - -### **Problem:** -`admin_configurations` table created but empty โ†’ Frontend can't fetch any configurations. - -### **Fix Applied:** -Created auto-seeding service that runs on server startup: - -**File:** `Re_Backend/src/services/configSeed.service.ts` -- Checks if configurations exist -- If empty, seeds 10 default configurations: - - 6 TAT Settings (default hours, thresholds, working hours) - - 3 Document Policy settings - - 2 AI Configuration settings - -### **Integration:** -Updated `Re_Backend/src/server.ts` to call `seedDefaultConfigurations()` on startup. - -**Output on server start:** -``` -โš™๏ธ System configurations initialized -``` - ---- - -## ๐Ÿ“‹ **Default Configurations Seeded** - -| Config Key | Value | Category | UI Component | -|------------|-------|----------|--------------| -| `DEFAULT_TAT_EXPRESS_HOURS` | 24 | TAT_SETTINGS | number | -| `DEFAULT_TAT_STANDARD_HOURS` | 48 | TAT_SETTINGS | number | -| `TAT_REMINDER_THRESHOLD_1` | 50 | TAT_SETTINGS | slider | -| `TAT_REMINDER_THRESHOLD_2` | 75 | TAT_SETTINGS | slider | -| `WORK_START_HOUR` | 9 | TAT_SETTINGS | number | -| `WORK_END_HOUR` | 18 | TAT_SETTINGS | number | -| `MAX_FILE_SIZE_MB` | 10 | DOCUMENT_POLICY | number | -| `ALLOWED_FILE_TYPES` | pdf,doc,... | DOCUMENT_POLICY | text | -| `DOCUMENT_RETENTION_DAYS` | 365 | DOCUMENT_POLICY | number | -| `AI_REMARK_GENERATION_ENABLED` | true | AI_CONFIGURATION | toggle | -| `AI_REMARK_MAX_CHARACTERS` | 500 | AI_CONFIGURATION | number | - ---- - -## ๐Ÿš€ **How to Verify** - -### **Step 1: Restart Backend** -```bash -cd Re_Backend -npm run dev -``` - -### **Expected Output:** -``` -โš™๏ธ System configurations initialized -๐Ÿ“… Holiday calendar loaded for TAT calculations -๐Ÿš€ Server running on port 5000 -``` - -### **Step 2: Check Database** -```sql -SELECT COUNT(*) FROM admin_configurations; --- Should return: 11 (10 default configs) - -SELECT config_key, config_value FROM admin_configurations ORDER BY sort_order; --- Should show all seeded configurations -``` - -### **Step 3: Test Frontend** -```bash -# Login as admin -# Navigate to Settings โ†’ System Configuration tab -# Should see all configurations grouped by category -``` - ---- - -## โœ… **Status: Both Issues Resolved** - -| Issue | Status | Fix | -|-------|--------|-----| -| TypeScript compilation error | โœ… Fixed | Added `await` to async function call | -| Empty configurations table | โœ… Fixed | Auto-seeding on server startup | -| Holiday list not fetching | โœ… Will work | Backend now starts successfully | - ---- - -## ๐ŸŽฏ **Next Steps** - -1. โœ… **Restart backend** - `npm run dev` -2. โœ… **Verify configurations seeded** - Check logs for "System configurations initialized" -3. โœ… **Test frontend** - Login as admin and view Settings -4. โœ… **Add holidays** - Use the Holiday Calendar tab - ---- - -**All systems ready! ๐Ÿš€** - ---- - -**Fixed:** November 4, 2025 -**Files Modified:** 3 -**Status:** Complete - diff --git a/HOLIDAY_AND_ADMIN_CONFIG_COMPLETE.md b/HOLIDAY_AND_ADMIN_CONFIG_COMPLETE.md deleted file mode 100644 index 50d1a3a..0000000 --- a/HOLIDAY_AND_ADMIN_CONFIG_COMPLETE.md +++ /dev/null @@ -1,731 +0,0 @@ -# โœ… Holiday Calendar & Admin Configuration System - Complete - -## ๐ŸŽ‰ What's Been Implemented - -### **1. Holiday Calendar System** ๐Ÿ“… -- โœ… Admin can add/edit/delete organization holidays -- โœ… Holidays automatically excluded from STANDARD priority TAT calculations -- โœ… Weekends (Saturday/Sunday) + Holidays = Non-working days -- โœ… Supports recurring holidays (annual) -- โœ… Department/location-specific holidays -- โœ… Bulk import from JSON/CSV -- โœ… Year-based calendar view -- โœ… Automatic cache refresh - -### **2. Admin Configuration System** โš™๏ธ -- โœ… Centralized configuration management -- โœ… All planned config areas supported: - - TAT Settings - - User Roles - - Notification Rules - - Document Policy - - Dashboard Layout - - AI Configuration - - Workflow Sharing Policy - ---- - -## ๐Ÿ“Š Database Schema - -### **New Tables Created:** - -**1. `holidays` Table:** -```sql -- holiday_id (UUID, PK) -- holiday_date (DATE, UNIQUE) -- YYYY-MM-DD -- holiday_name (VARCHAR) -- "Diwali", "Republic Day" -- description (TEXT) -- Optional details -- is_recurring (BOOLEAN) -- Annual holidays -- recurrence_rule (VARCHAR) -- RRULE format -- holiday_type (ENUM) -- NATIONAL, REGIONAL, ORGANIZATIONAL, OPTIONAL -- is_active (BOOLEAN) -- Enable/disable -- applies_to_departments (TEXT[]) -- NULL = all -- applies_to_locations (TEXT[]) -- NULL = all -- created_by (UUID FK) -- updated_by (UUID FK) -- created_at, updated_at -``` - -**2. `admin_configurations` Table:** -```sql -- config_id (UUID, PK) -- config_key (VARCHAR, UNIQUE) -- "DEFAULT_TAT_EXPRESS_HOURS" -- config_category (ENUM) -- TAT_SETTINGS, NOTIFICATION_RULES, etc. -- config_value (TEXT) -- Actual value -- value_type (ENUM) -- STRING, NUMBER, BOOLEAN, JSON, ARRAY -- display_name (VARCHAR) -- UI-friendly name -- description (TEXT) -- default_value (TEXT) -- Reset value -- is_editable (BOOLEAN) -- is_sensitive (BOOLEAN) -- For API keys, passwords -- validation_rules (JSONB) -- Min, max, regex -- ui_component (VARCHAR) -- input, select, toggle, slider -- options (JSONB) -- For dropdown options -- sort_order (INTEGER) -- Display order -- requires_restart (BOOLEAN) -- last_modified_by (UUID FK) -- last_modified_at (TIMESTAMP) -``` - ---- - -## ๐Ÿ”Œ API Endpoints - -### **Holiday Management:** - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/api/admin/holidays` | Get all holidays (with year filter) | -| GET | `/api/admin/holidays/calendar/:year` | Get calendar for specific year | -| POST | `/api/admin/holidays` | Create new holiday | -| PUT | `/api/admin/holidays/:holidayId` | Update holiday | -| DELETE | `/api/admin/holidays/:holidayId` | Delete (deactivate) holiday | -| POST | `/api/admin/holidays/bulk-import` | Bulk import holidays | - -### **Configuration Management:** - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/api/admin/configurations` | Get all configurations | -| GET | `/api/admin/configurations?category=TAT_SETTINGS` | Get by category | -| PUT | `/api/admin/configurations/:configKey` | Update configuration | -| POST | `/api/admin/configurations/:configKey/reset` | Reset to default | - ---- - -## ๐ŸŽฏ TAT Calculation with Holidays - -### **STANDARD Priority (Working Days):** - -**Excludes:** -- โœ… Saturdays (day 6) -- โœ… Sundays (day 0) -- โœ… Holidays from `holidays` table -- โœ… Outside working hours (before 9 AM, after 6 PM) - -**Example:** -``` -Submit: Monday Oct 20 at 10:00 AM -TAT: 48 hours (STANDARD priority) -Holiday: Tuesday Oct 21 (Diwali) - -Calculation: -Monday 10 AM - 6 PM = 8 hours (total: 8h) -Tuesday = HOLIDAY (skipped) -Wednesday 9 AM - 6 PM = 9 hours (total: 17h) -Thursday 9 AM - 6 PM = 9 hours (total: 26h) -Friday 9 AM - 6 PM = 9 hours (total: 35h) -Saturday-Sunday = WEEKEND (skipped) -Monday 9 AM - 10 PM = 13 hours (total: 48h) - -Due: Monday Oct 27 at 10:00 AM -``` - -### **EXPRESS Priority (Calendar Days):** - -**Excludes: NOTHING** -- All days included (weekends, holidays, 24/7) - -**Example:** -``` -Submit: Monday Oct 20 at 10:00 AM -TAT: 48 hours (EXPRESS priority) - -Due: Wednesday Oct 22 at 10:00 AM (exactly 48 hours later) -``` - ---- - -## ๐Ÿ”„ Holiday Cache System - -### **How It Works:** - -``` -1. Server Starts - โ†“ -2. Load holidays from database (current year + next year) - โ†“ -3. Store in memory cache (Set of date strings) - โ†“ -4. Cache expires after 6 hours - โ†“ -5. Auto-reload when expired - โ†“ -6. Manual reload when admin adds/updates/deletes holiday -``` - -**Benefits:** -- โšก Fast lookups (O(1) Set lookup) -- ๐Ÿ’พ Minimal memory (just date strings) -- ๐Ÿ”„ Auto-refresh every 6 hours -- ๐ŸŽฏ Immediate update when admin changes holidays - ---- - -## ๐ŸŽจ Frontend UI (To Be Built) - -### **Admin Dashboard โ†’ Holiday Management:** - -```tsx - - {/* Year Selector */} - - - {/* Calendar View */} - - {/* Days with holidays highlighted */} - - - - - {/* List View */} - - - - - {/* Actions */} -
- - -
-
-``` - ---- - -## ๐Ÿ“‹ Default Configurations - -### **Pre-seeded in database:** - -| Config Key | Value | Category | Description | -|------------|-------|----------|-------------| -| `DEFAULT_TAT_EXPRESS_HOURS` | 24 | TAT_SETTINGS | Default TAT for express | -| `DEFAULT_TAT_STANDARD_HOURS` | 48 | TAT_SETTINGS | Default TAT for standard | -| `TAT_REMINDER_THRESHOLD_1` | 50 | TAT_SETTINGS | First reminder at 50% | -| `TAT_REMINDER_THRESHOLD_2` | 75 | TAT_SETTINGS | Second reminder at 75% | -| `WORK_START_HOUR` | 9 | TAT_SETTINGS | Work day starts at 9 AM | -| `WORK_END_HOUR` | 18 | TAT_SETTINGS | Work day ends at 6 PM | -| `MAX_FILE_SIZE_MB` | 10 | DOCUMENT_POLICY | Max upload size | -| `ALLOWED_FILE_TYPES` | pdf,doc,... | DOCUMENT_POLICY | Allowed extensions | -| `DOCUMENT_RETENTION_DAYS` | 365 | DOCUMENT_POLICY | Retention period | -| `AI_REMARK_GENERATION_ENABLED` | true | AI_CONFIGURATION | Enable AI remarks | -| `AI_REMARK_MAX_CHARACTERS` | 500 | AI_CONFIGURATION | Max AI text length | - ---- - -## ๐Ÿš€ Quick Start - -### **Step 1: Run Migrations** - -```bash -cd Re_Backend -npm run migrate -``` - -**You'll see:** -``` -โœ… Holidays table created successfully -โœ… Admin configurations table created and seeded -``` - -### **Step 2: Import Indian Holidays (Optional)** - -Create a script or use the API: - -```bash -# Using curl (requires admin token): -curl -X POST http://localhost:5000/api/admin/holidays/bulk-import \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ - -d @data/indian_holidays_2025.json -``` - -### **Step 3: Verify Holidays Loaded** - -```sql -SELECT COUNT(*) FROM holidays WHERE is_active = true; --- Should return 14 (or however many you imported) -``` - -### **Step 4: Restart Backend** - -```bash -npm run dev -``` - -**You'll see:** -``` -๐Ÿ“… Holiday calendar loaded for TAT calculations -Loaded 14 holidays into cache -``` - ---- - -## ๐Ÿงช Testing - -### **Test 1: Create Holiday** - -```bash -POST /api/admin/holidays -{ - "holidayDate": "2025-12-31", - "holidayName": "New Year's Eve", - "description": "Last day of the year", - "holidayType": "ORGANIZATIONAL" -} -``` - -### **Test 2: Verify Holiday Affects TAT** - -```bash -# 1. Create STANDARD priority request on Dec 30 -# 2. Set TAT: 16 hours (2 working days) -# 3. Expected due: Jan 2 (skips Dec 31 holiday + weekend) -# 4. Actual due should be: Jan 2 -``` - -### **Test 3: Verify EXPRESS Not Affected** - -```bash -# 1. Create EXPRESS priority request on Dec 30 -# 2. Set TAT: 48 hours -# 3. Expected due: Jan 1 (exactly 48 hours, includes holiday) -``` - ---- - -## ๐Ÿ“Š Admin Configuration UI (To Be Built) - -### **Admin Settings Page:** - -```tsx - - - TAT Settings - Holiday Calendar - Document Policy - Notifications - AI Configuration - - - - - - - - - - - - - - - -``` - ---- - -## ๐Ÿ” Sample Queries - -### **Get Holidays for Current Year:** -```sql -SELECT * FROM holidays -WHERE EXTRACT(YEAR FROM holiday_date) = EXTRACT(YEAR FROM CURRENT_DATE) - AND is_active = true -ORDER BY holiday_date; -``` - -### **Check if Date is Holiday:** -```sql -SELECT EXISTS( - SELECT 1 FROM holidays - WHERE holiday_date = '2025-08-15' - AND is_active = true -) as is_holiday; -``` - -### **Upcoming Holidays (Next 3 Months):** -```sql -SELECT - holiday_name, - holiday_date, - holiday_type, - description -FROM holidays -WHERE holiday_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '90 days' - AND is_active = true -ORDER BY holiday_date; -``` - ---- - -## ๐ŸŽฏ Complete Feature Set - -### **Holiday Management:** -- โœ… Create individual holidays -- โœ… Update holiday details -- โœ… Delete (deactivate) holidays -- โœ… Bulk import from JSON -- โœ… Year-based calendar view -- โœ… Recurring holidays support -- โœ… Department-specific holidays -- โœ… Location-specific holidays - -### **TAT Integration:** -- โœ… STANDARD priority skips holidays -- โœ… EXPRESS priority ignores holidays -- โœ… Automatic cache management -- โœ… Performance optimized (in-memory cache) -- โœ… Real-time updates when holidays change - -### **Admin Configuration:** -- โœ… TAT default values -- โœ… Reminder thresholds -- โœ… Working hours -- โœ… Document policies -- โœ… AI settings -- โœ… All configs with validation rules -- โœ… UI component hints -- โœ… Reset to default option - ---- - -## ๐Ÿ“ฆ Files Created - -### **Backend (10 new files):** -1. `src/models/Holiday.ts` - Holiday model -2. `src/services/holiday.service.ts` - Holiday management service -3. `src/controllers/admin.controller.ts` - Admin API controllers -4. `src/routes/admin.routes.ts` - Admin API routes -5. `src/migrations/20251104-create-holidays.ts` - Holidays table migration -6. `src/migrations/20251104-create-admin-config.ts` - Admin config migration -7. `data/indian_holidays_2025.json` - Sample holidays data -8. `docs/HOLIDAY_CALENDAR_SYSTEM.md` - Complete documentation - -### **Modified Files (6):** -1. `src/utils/tatTimeUtils.ts` - Added holiday checking -2. `src/server.ts` - Initialize holidays cache -3. `src/models/index.ts` - Export Holiday model -4. `src/routes/index.ts` - Register admin routes -5. `src/middlewares/authorization.middleware.ts` - Added requireAdmin -6. `src/scripts/migrate.ts` - Include new migrations - ---- - -## ๐Ÿš€ How to Use - -### **Step 1: Run Migrations** - -```bash -cd Re_Backend -npm run migrate -``` - -**Expected Output:** -``` -โœ… Holidays table created successfully -โœ… Admin configurations table created and seeded -``` - -### **Step 2: Restart Backend** - -```bash -npm run dev -``` - -**Expected Output:** -``` -๐Ÿ“… Holiday calendar loaded for TAT calculations -[TAT Utils] Loaded 0 holidays into cache (will load when admin adds holidays) -``` - -### **Step 3: Add Holidays via API** - -**Option A: Add Individual Holiday:** -```bash -curl -X POST http://localhost:5000/api/admin/holidays \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ - -d '{ - "holidayDate": "2025-11-05", - "holidayName": "Diwali", - "description": "Festival of Lights", - "holidayType": "NATIONAL" - }' -``` - -**Option B: Bulk Import:** -```bash -# Use the sample data file: -curl -X POST http://localhost:5000/api/admin/holidays/bulk-import \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ - -d @data/indian_holidays_2025.json -``` - -### **Step 4: Test TAT with Holidays** - -```bash -# 1. Create STANDARD priority request -# 2. TAT calculation will now skip holidays -# 3. Due date will be later if holidays fall within TAT period -``` - ---- - -## ๐Ÿ“Š TAT Calculation Examples - -### **Example 1: No Holidays in TAT Period** - -``` -Submit: Monday Dec 1, 10:00 AM -TAT: 24 hours (STANDARD) -Holidays: None in this period - -Calculation: -Monday 10 AM - 6 PM = 8 hours -Tuesday 9 AM - 1 PM = 4 hours -Total = 12 hours (needs 12 more) -... -Due: Tuesday 1:00 PM -``` - -### **Example 2: Holiday in TAT Period** - -``` -Submit: Friday Oct 31, 10:00 AM -TAT: 24 hours (STANDARD) -Holiday: Monday Nov 3 (Diwali) - -Calculation: -Friday 10 AM - 6 PM = 8 hours -Saturday-Sunday = WEEKEND (skipped) -Monday = HOLIDAY (skipped) -Tuesday 9 AM - 6 PM = 9 hours (total: 17h) -Wednesday 9 AM - 2 PM = 5 hours (total: 22h) -... -Due: Wednesday Nov 5 at 2:00 PM -``` - ---- - -## ๐Ÿ”’ Security - -### **Admin Access Required:** - -All holiday and configuration endpoints check: -1. โœ… User is authenticated (`authenticateToken`) -2. โœ… User has admin role (`requireAdmin`) - -**Non-admins get:** -```json -{ - "success": false, - "error": "Admin access required" -} -``` - ---- - -## ๐Ÿ“š Admin Configuration Categories - -### **1. TAT Settings** -- Default TAT hours (Express/Standard) -- Reminder thresholds (50%, 75%) -- Working hours (9 AM - 6 PM) - -### **2. User Roles** (Future) -- Add/deactivate users -- Change roles (Initiator, Approver, Spectator) - -### **3. Notification Rules** -- Channels (in-app, email) -- Frequency -- Template messages - -### **4. Document Policy** -- Max upload size (10 MB) -- Allowed file types -- Retention period (365 days) - -### **5. Dashboard Layout** (Future) -- Enable/disable KPI cards per role - -### **6. AI Configuration** -- Toggle AI remark generation -- Max characters (500) - -### **7. Workflow Sharing Policy** (Future) -- Control who can add spectators -- Share links permissions - ---- - -## โœ… Implementation Summary - -| Feature | Status | Notes | -|---------|--------|-------| -| **Holidays Table** | โœ… Created | With 4 indexes | -| **Admin Config Table** | โœ… Created | Pre-seeded with defaults | -| **Holiday Service** | โœ… Implemented | CRUD + bulk import | -| **Admin Controller** | โœ… Implemented | All endpoints | -| **Admin Routes** | โœ… Implemented | Secured with requireAdmin | -| **TAT Integration** | โœ… Implemented | Holidays excluded for STANDARD | -| **Holiday Cache** | โœ… Implemented | 6-hour expiry, auto-refresh | -| **Sample Data** | โœ… Created | 14 Indian holidays for 2025 | -| **Documentation** | โœ… Complete | Full guide created | -| **Migrations** | โœ… Ready | 2 new migrations added | - ---- - -## ๐ŸŽ“ Next Steps - -### **Immediate:** -1. โœ… Run migrations: `npm run migrate` -2. โœ… Restart backend: `npm run dev` -3. โœ… Verify holidays table exists -4. โœ… Import sample holidays (optional) - -### **Frontend Development:** -1. ๐Ÿ“‹ Build Holiday Management page -2. ๐Ÿ“‹ Build Admin Configuration page -3. ๐Ÿ“‹ Build Calendar view component -4. ๐Ÿ“‹ Build Bulk import UI -5. ๐Ÿ“‹ Add to Admin Dashboard - -### **Future Enhancements:** -1. ๐Ÿ“‹ Recurring holiday auto-generation -2. ๐Ÿ“‹ Holiday templates by country -3. ๐Ÿ“‹ Email notifications for upcoming holidays -4. ๐Ÿ“‹ Holiday impact reports (how many requests affected) -5. ๐Ÿ“‹ Multi-year holiday planning - ---- - -## ๐Ÿ“Š Impact on Existing Requests - -### **For Existing Requests:** - -**Before Holidays Table:** -- TAT calculation: Weekends only - -**After Holidays Table:** -- TAT calculation: Weekends + Holidays -- Due dates may change for active requests -- Historical requests unchanged - ---- - -## ๐Ÿ†˜ Troubleshooting - -### **Holidays Not Excluded from TAT?** - -**Check:** -1. Holidays cache loaded? Look for "Loaded X holidays into cache" in logs -2. Priority is STANDARD? (EXPRESS doesn't use holidays) -3. Holiday is active? `is_active = true` -4. Holiday date is correct format? `YYYY-MM-DD` - -**Debug:** -```sql --- Check if holiday exists -SELECT * FROM holidays -WHERE holiday_date = '2025-11-05' - AND is_active = true; -``` - -### **Cache Not Updating After Adding Holiday?** - -**Solution:** -- Cache refreshes automatically when admin adds/updates/deletes -- If not working, restart backend server -- Cache refreshes every 6 hours automatically - ---- - -## ๐Ÿ“ˆ Future Admin Features - -Based on your requirements, these can be added: - -### **User Role Management:** -- Add/remove users -- Change user roles -- Activate/deactivate accounts - -### **Notification Templates:** -- Customize email/push templates -- Set notification frequency -- Channel preferences - -### **Dashboard Customization:** -- Enable/disable KPI cards -- Customize card order -- Role-based dashboard views - -### **Workflow Policies:** -- Who can add spectators -- Sharing permissions -- Approval flow templates - ---- - -## ๐ŸŽ‰ Status: COMPLETE! - -โœ… **Holiday Calendar System** - Fully implemented -โœ… **Admin Configuration** - Schema and API ready -โœ… **TAT Integration** - Holidays excluded for STANDARD priority -โœ… **API Endpoints** - All CRUD operations -โœ… **Security** - Admin-only access -โœ… **Performance** - Optimized with caching -โœ… **Sample Data** - Indian holidays 2025 -โœ… **Documentation** - Complete guide - ---- - -**Just run migrations and you're ready to go! ๐Ÿš€** - -See `docs/HOLIDAY_CALENDAR_SYSTEM.md` for detailed API documentation. - ---- - -**Last Updated**: November 4, 2025 -**Version**: 1.0.0 -**Team**: Royal Enfield Workflow System - diff --git a/HOLIDAY_EXPRESS_TAT.md b/HOLIDAY_EXPRESS_TAT.md deleted file mode 100644 index 28050c6..0000000 --- a/HOLIDAY_EXPRESS_TAT.md +++ /dev/null @@ -1,516 +0,0 @@ -# Holiday Handling & EXPRESS Mode TAT Calculation - -## Overview - -The TAT (Turn Around Time) system now supports: -1. **Holiday Exclusions** - Configured holidays are excluded from STANDARD priority TAT calculations -2. **EXPRESS Mode** - EXPRESS priority requests use 24/7 calculation (no exclusions) - ---- - -## How It Works - -### **STANDARD Priority (Default)** - -**Calculation:** -- โœ… Excludes weekends (Saturday, Sunday) -- โœ… Excludes non-working hours (9 AM - 6 PM by default) -- โœ… **Excludes holidays configured in Admin Settings** - -**Example:** -``` -TAT = 16 working hours -Start: Monday 2:00 PM - -Calculation: -Monday 2:00 PM - 6:00 PM = 4 hours (remaining: 12h) -Tuesday 9:00 AM - 6:00 PM = 9 hours (remaining: 3h) -Wednesday 9:00 AM - 12:00 PM = 3 hours (remaining: 0h) - -If Wednesday is a HOLIDAY โ†’ Skip to Thursday: -Wednesday (HOLIDAY) = 0 hours (skipped) -Thursday 9:00 AM - 12:00 PM = 3 hours (remaining: 0h) - -Final deadline: Thursday 12:00 PM โœ… -``` - ---- - -### **EXPRESS Priority** - -**Calculation:** -- โœ… Counts ALL hours (24/7) -- โœ… **No weekend exclusion** -- โœ… **No non-working hours exclusion** -- โœ… **No holiday exclusion** - -**Example:** -``` -TAT = 16 hours -Start: Monday 2:00 PM - -Calculation: -Simply add 16 hours: -Monday 2:00 PM + 16 hours = Tuesday 6:00 AM - -Final deadline: Tuesday 6:00 AM โœ… - -(Even if Tuesday is a holiday, it still counts) -``` - ---- - -## Holiday Configuration Flow - -### **1. Admin Adds Holiday** - -``` -Settings Page โ†’ Holiday Manager โ†’ Add Holiday -Name: "Christmas Day" -Date: 2025-12-25 -Type: Public Holiday -โœ… Save -``` - -### **2. Holiday Stored in Database** - -```sql -INSERT INTO holidays (holiday_date, holiday_name, holiday_type, is_active) -VALUES ('2025-12-25', 'Christmas Day', 'PUBLIC_HOLIDAY', true); -``` - -### **3. Holiday Cache Updated** - -```typescript -// Holidays are cached in memory for 6 hours -await loadHolidaysCache(); -// โ†’ holidaysCache = Set(['2025-12-25', '2025-01-01', ...]) -``` - -### **4. TAT Calculation Uses Holiday Cache** - -```typescript -// When scheduling TAT jobs -if (priority === 'STANDARD') { - // Working hours calculation - checks holidays - const threshold1 = await addWorkingHours(start, hours * 0.55); - // โ†’ If date is in holidaysCache, it's skipped โœ… -} else { - // EXPRESS: 24/7 calculation - ignores holidays - const threshold1 = addCalendarHours(start, hours * 0.55); - // โ†’ Adds hours directly, no checks โœ… -} -``` - ---- - -## Implementation Details - -### **Function: `addWorkingHours()` (STANDARD Mode)** - -```typescript -export async function addWorkingHours(start: Date, hoursToAdd: number): Promise { - let current = dayjs(start); - - // Load holidays from database (cached) - await loadHolidaysCache(); - - let remaining = hoursToAdd; - - while (remaining > 0) { - current = current.add(1, 'hour'); - - // Check if current hour is working time - if (isWorkingTime(current)) { // โœ… Checks holidays here - remaining -= 1; - } - } - - return current; -} - -function isWorkingTime(date: Dayjs): boolean { - // Check weekend - if (date.day() === 0 || date.day() === 6) return false; - - // Check working hours - if (date.hour() < 9 || date.hour() >= 18) return false; - - // Check if holiday โœ… - if (isHoliday(date)) return false; - - return true; -} - -function isHoliday(date: Dayjs): boolean { - const dateStr = date.format('YYYY-MM-DD'); - return holidaysCache.has(dateStr); // โœ… Checks cached holidays -} -``` - ---- - -### **Function: `addCalendarHours()` (EXPRESS Mode)** - -```typescript -export function addCalendarHours(start: Date, hoursToAdd: number): Dayjs { - // Simple addition - no checks โœ… - return dayjs(start).add(hoursToAdd, 'hour'); -} -``` - ---- - -## TAT Scheduler Integration - -### **Updated Method Signature:** - -```typescript -async scheduleTatJobs( - requestId: string, - levelId: string, - approverId: string, - tatDurationHours: number, - startTime?: Date, - priority: Priority = Priority.STANDARD // โœ… New parameter -): Promise -``` - -### **Priority-Based Calculation:** - -```typescript -const isExpress = priority === Priority.EXPRESS; - -if (isExpress) { - // EXPRESS: 24/7 calculation - threshold1Time = addCalendarHours(now, hours * 0.55).toDate(); - threshold2Time = addCalendarHours(now, hours * 0.80).toDate(); - breachTime = addCalendarHours(now, hours).toDate(); - logger.info('Using EXPRESS mode (24/7) - no holiday/weekend exclusions'); -} else { - // STANDARD: Working hours, exclude holidays - const t1 = await addWorkingHours(now, hours * 0.55); - const t2 = await addWorkingHours(now, hours * 0.80); - const tBreach = await addWorkingHours(now, hours); - threshold1Time = t1.toDate(); - threshold2Time = t2.toDate(); - breachTime = tBreach.toDate(); - logger.info('Using STANDARD mode - excludes holidays, weekends, non-working hours'); -} -``` - ---- - -## Example Scenarios - -### **Scenario 1: STANDARD with Holiday** - -``` -Request Details: -- Priority: STANDARD -- TAT: 16 working hours -- Start: Monday 2:00 PM -- Holiday: Wednesday (Christmas) - -Calculation: -Monday 2:00 PM - 6:00 PM = 4 hours (12h remaining) -Tuesday 9:00 AM - 6:00 PM = 9 hours (3h remaining) -Wednesday (HOLIDAY) = SKIPPED โœ… -Thursday 9:00 AM - 12:00 PM = 3 hours (0h remaining) - -TAT Milestones: -- Threshold 1 (55%): Tuesday 4:40 PM (8.8 working hours) -- Threshold 2 (80%): Thursday 10:48 AM (12.8 working hours) -- Breach (100%): Thursday 12:00 PM (16 working hours) -``` - ---- - -### **Scenario 2: EXPRESS with Holiday** - -``` -Request Details: -- Priority: EXPRESS -- TAT: 16 hours -- Start: Monday 2:00 PM -- Holiday: Wednesday (Christmas) - IGNORED โœ… - -Calculation: -Monday 2:00 PM + 16 hours = Tuesday 6:00 AM - -TAT Milestones: -- Threshold 1 (55%): Monday 10:48 PM (8.8 hours) -- Threshold 2 (80%): Tuesday 2:48 AM (12.8 hours) -- Breach (100%): Tuesday 6:00 AM (16 hours) - -Note: Even though Wednesday is a holiday, EXPRESS doesn't care โœ… -``` - ---- - -### **Scenario 3: Multiple Holidays** - -``` -Request Details: -- Priority: STANDARD -- TAT: 40 working hours -- Start: Friday 10:00 AM -- Holidays: Monday (New Year), Tuesday (Day After) - -Calculation: -Friday 10:00 AM - 6:00 PM = 8 hours (32h remaining) -Saturday-Sunday = SKIPPED (weekend) -Monday (HOLIDAY) = SKIPPED โœ… -Tuesday (HOLIDAY) = SKIPPED โœ… -Wednesday 9:00 AM - 6:00 PM = 9 hours (23h remaining) -Thursday 9:00 AM - 6:00 PM = 9 hours (14h remaining) -Friday 9:00 AM - 6:00 PM = 9 hours (5h remaining) -Monday 9:00 AM - 2:00 PM = 5 hours (0h remaining) - -Final deadline: Next Monday 2:00 PM โœ… -(Skipped 2 weekends + 2 holidays) -``` - ---- - -## Holiday Cache Management - -### **Cache Lifecycle:** - -``` -1. Server Startup - โ†’ initializeHolidaysCache() called - โ†’ Holidays loaded into memory - -2. Cache Valid for 6 Hours - โ†’ holidaysCacheExpiry = now + 6 hours - โ†’ Subsequent calls use cached data (fast) - -3. Cache Expires After 6 Hours - โ†’ Next TAT calculation reloads cache from DB - โ†’ New cache expires in 6 hours - -4. Manual Cache Refresh (Optional) - โ†’ Admin adds/updates holiday - โ†’ Call initializeHolidaysCache() to refresh immediately -``` - -### **Cache Performance:** - -``` -Without Cache: -- Every TAT calculation โ†’ DB query โ†’ SLOW โŒ -- 100 requests/hour โ†’ 100 DB queries - -With Cache: -- Load once per 6 hours โ†’ DB query โ†’ FAST โœ… -- 100 requests/hour โ†’ 0 DB queries (use cache) -- Cache refresh: Every 6 hours or on-demand -``` - ---- - -## Priority Detection in Services - -### **Workflow Service (Submission):** - -```typescript -// When submitting workflow -const workflowPriority = (updated as any).priority || 'STANDARD'; - -await tatSchedulerService.scheduleTatJobs( - requestId, - levelId, - approverId, - tatHours, - now, - workflowPriority // โœ… Pass priority -); -``` - -### **Approval Service (Next Level):** - -```typescript -// When moving to next approval level -const workflowPriority = (wf as any)?.priority || 'STANDARD'; - -await tatSchedulerService.scheduleTatJobs( - requestId, - nextLevelId, - nextApproverId, - tatHours, - now, - workflowPriority // โœ… Pass priority -); -``` - ---- - -## Database Schema - -### **Holidays Table:** - -```sql -CREATE TABLE holidays ( - holiday_id UUID PRIMARY KEY, - holiday_date DATE NOT NULL, - holiday_name VARCHAR(255) NOT NULL, - holiday_type VARCHAR(50), - description TEXT, - is_active BOOLEAN DEFAULT true, - created_at TIMESTAMP DEFAULT NOW(), - updated_at TIMESTAMP DEFAULT NOW() -); - --- Example data -INSERT INTO holidays (holiday_date, holiday_name, holiday_type) -VALUES - ('2025-12-25', 'Christmas Day', 'PUBLIC_HOLIDAY'), - ('2025-01-01', 'New Year''s Day', 'PUBLIC_HOLIDAY'), - ('2025-07-04', 'Independence Day', 'PUBLIC_HOLIDAY'); -``` - -### **Workflow Request Priority:** - -```sql --- WorkflowRequest table already has priority field -SELECT request_id, priority, tat_hours -FROM workflow_requests -WHERE priority = 'EXPRESS'; -- 24/7 calculation --- OR -WHERE priority = 'STANDARD'; -- Working hours + holiday exclusion -``` - ---- - -## Testing Scenarios - -### **Test 1: Add Holiday, Create STANDARD Request** - -```bash -# 1. Add holiday for tomorrow -curl -X POST http://localhost:5000/api/v1/admin/holidays \ - -H "Authorization: Bearer TOKEN" \ - -d '{ - "holidayDate": "2025-11-06", - "holidayName": "Test Holiday", - "holidayType": "PUBLIC_HOLIDAY" - }' - -# 2. Create STANDARD request with 24h TAT -curl -X POST http://localhost:5000/api/v1/workflows \ - -d '{ - "priority": "STANDARD", - "tatHours": 24 - }' - -# 3. Check scheduled TAT jobs in logs -# โ†’ Should show deadline skipping the holiday โœ… -``` - -### **Test 2: Same Holiday, EXPRESS Request** - -```bash -# 1. Holiday still exists (tomorrow) - -# 2. Create EXPRESS request with 24h TAT -curl -X POST http://localhost:5000/api/v1/workflows \ - -d '{ - "priority": "EXPRESS", - "tatHours": 24 - }' - -# 3. Check scheduled TAT jobs in logs -# โ†’ Should show deadline NOT skipping the holiday โœ… -# โ†’ Exactly 24 hours from now (includes holiday) -``` - -### **Test 3: Verify Holiday Exclusion** - -```bash -# Create request on Friday afternoon -# With 16 working hours TAT -# Should skip weekend and land on Monday/Tuesday - -# If Monday is a holiday: -# โ†’ STANDARD: Should land on Tuesday โœ… -# โ†’ EXPRESS: Should land on Sunday โœ… -``` - ---- - -## Logging Examples - -### **STANDARD Mode Log:** - -``` -[TAT Scheduler] Using STANDARD mode - excludes holidays, weekends, non-working hours -[TAT Scheduler] Calculating TAT milestones for request REQ-123, level LEVEL-456 -[TAT Scheduler] Priority: STANDARD, TAT Hours: 16 -[TAT Scheduler] Start: 2025-11-05 14:00 -[TAT Scheduler] Threshold 1 (55%): 2025-11-07 11:48 (skipped 1 holiday) -[TAT Scheduler] Threshold 2 (80%): 2025-11-08 09:48 -[TAT Scheduler] Breach (100%): 2025-11-08 14:00 -``` - -### **EXPRESS Mode Log:** - -``` -[TAT Scheduler] Using EXPRESS mode (24/7) - no holiday/weekend exclusions -[TAT Scheduler] Calculating TAT milestones for request REQ-456, level LEVEL-789 -[TAT Scheduler] Priority: EXPRESS, TAT Hours: 16 -[TAT Scheduler] Start: 2025-11-05 14:00 -[TAT Scheduler] Threshold 1 (55%): 2025-11-05 22:48 (8.8 hours) -[TAT Scheduler] Threshold 2 (80%): 2025-11-06 02:48 (12.8 hours) -[TAT Scheduler] Breach (100%): 2025-11-06 06:00 (16 hours) -``` - ---- - -## Summary - -### **What Changed:** - -1. โœ… Added `addCalendarHours()` for EXPRESS mode (24/7 calculation) -2. โœ… Updated `addWorkingHours()` to check holidays from admin settings -3. โœ… Added `priority` parameter to `scheduleTatJobs()` -4. โœ… Updated workflow/approval services to pass priority -5. โœ… Holiday cache for performance (6-hour expiry) - -### **How Holidays Are Used:** - -| Priority | Calculation Method | Holidays | Weekends | Non-Working Hours | -|----------|-------------------|----------|----------|-------------------| -| **STANDARD** | Working hours only | โœ… Excluded | โœ… Excluded | โœ… Excluded | -| **EXPRESS** | 24/7 calendar hours | โŒ Counted | โŒ Counted | โŒ Counted | - -### **Benefits:** - -1. โœ… **Accurate TAT for STANDARD** - Respects holidays, no false breaches -2. โœ… **Fast EXPRESS** - True 24/7 calculation for urgent requests -3. โœ… **Centralized Holiday Management** - Admin can add/edit holidays -4. โœ… **Performance** - Holiday cache prevents repeated DB queries -5. โœ… **Flexible** - Priority can be changed per request - ---- - -## Files Modified - -1. `Re_Backend/src/utils/tatTimeUtils.ts` - Added `addCalendarHours()` for EXPRESS mode -2. `Re_Backend/src/services/tatScheduler.service.ts` - Added priority parameter and logic -3. `Re_Backend/src/services/workflow.service.ts` - Pass priority when scheduling TAT -4. `Re_Backend/src/services/approval.service.ts` - Pass priority for next level TAT - ---- - -## Configuration Keys - -| Config Key | Default | Description | -|------------|---------|-------------| -| `WORK_START_HOUR` | 9 | Working hours start (STANDARD mode only) | -| `WORK_END_HOUR` | 18 | Working hours end (STANDARD mode only) | -| `WORK_START_DAY` | 1 | Monday (STANDARD mode only) | -| `WORK_END_DAY` | 5 | Friday (STANDARD mode only) | - -**Note:** EXPRESS mode ignores all these configurations and uses 24/7 calculation. - diff --git a/KPI_SETUP_COMPLETE.md b/KPI_SETUP_COMPLETE.md deleted file mode 100644 index 6a21d81..0000000 --- a/KPI_SETUP_COMPLETE.md +++ /dev/null @@ -1,307 +0,0 @@ -# โœ… KPI & TAT Reporting System - Setup Complete! - -## ๐ŸŽ‰ What's Been Implemented - -### 1. TAT Alerts Table (`tat_alerts`) - -**Purpose**: Store every TAT notification (50%, 75%, 100%) for display and KPI analysis - -**Features**: -- โœ… Records all TAT notifications sent -- โœ… Tracks timing, completion status, and compliance -- โœ… Stores metadata for rich reporting -- โœ… Displays like the shared image: "Reminder 1: 50% of SLA breach reminder have been sent" - -**Example Query**: -```sql --- Get TAT alerts for a specific request (for UI display) -SELECT - alert_type, - threshold_percentage, - alert_sent_at, - alert_message -FROM tat_alerts -WHERE request_id = 'YOUR_REQUEST_ID' -ORDER BY alert_sent_at ASC; -``` - ---- - -### 2. Eight KPI Views Created - -All views are ready to use for reporting and dashboards: - -| View Name | Purpose | KPI Category | -|-----------|---------|--------------| -| `vw_request_volume_summary` | Request counts, status, cycle times | Volume & Status | -| `vw_tat_compliance` | TAT compliance tracking | TAT Efficiency | -| `vw_approver_performance` | Approver metrics, response times | Approver Load | -| `vw_tat_alerts_summary` | TAT alerts with response times | TAT Efficiency | -| `vw_department_summary` | Department-wise statistics | Volume & Status | -| `vw_daily_kpi_metrics` | Daily trends and metrics | Trends | -| `vw_workflow_aging` | Aging analysis | Volume & Status | -| `vw_engagement_metrics` | Comments, documents, collaboration | Engagement & Quality | - ---- - -### 3. Complete KPI Coverage - -All KPIs from your requirements are now supported: - -#### โœ… Request Volume & Status -- Total Requests Created -- Open Requests (with age) -- Approved Requests -- Rejected Requests - -#### โœ… TAT Efficiency -- Average TAT Compliance % -- Avg Approval Cycle Time -- Delayed Workflows -- TAT Breach History - -#### โœ… Approver Load -- Pending Actions (My Queue) -- Approvals Completed (Today/Week) -- Approver Performance Metrics - -#### โœ… Engagement & Quality -- Comments/Work Notes Added -- Attachments Uploaded -- Spectator Participation - ---- - -## ๐Ÿ“Š Example Queries - -### Show TAT Reminders (Like Your Image) - -```sql --- For displaying TAT alerts in Request Detail screen -SELECT - CASE - WHEN alert_type = 'TAT_50' THEN 'โณ 50% of SLA breach reminder have been sent' - WHEN alert_type = 'TAT_75' THEN 'โš ๏ธ 75% of SLA breach reminder have been sent' - WHEN alert_type = 'TAT_100' THEN 'โฐ TAT breached - Immediate action required' - END as reminder_text, - 'Reminder sent by system automatically' as description, - alert_sent_at -FROM tat_alerts -WHERE request_id = 'REQUEST_ID' - AND level_id = 'LEVEL_ID' -ORDER BY threshold_percentage ASC; -``` - -### TAT Compliance Rate - -```sql -SELECT - ROUND( - COUNT(CASE WHEN completed_within_tat = true THEN 1 END) * 100.0 / - NULLIF(COUNT(CASE WHEN completed_within_tat IS NOT NULL THEN 1 END), 0), - 2 - ) as compliance_percentage -FROM vw_tat_compliance; -``` - -### Approver Performance Leaderboard - -```sql -SELECT - approver_name, - department, - ROUND(tat_compliance_percentage, 2) as compliance_percent, - approved_count, - ROUND(avg_response_time_hours, 2) as avg_response_hours, - breaches_count -FROM vw_approver_performance -WHERE total_assignments > 0 -ORDER BY tat_compliance_percentage DESC -LIMIT 10; -``` - -### Department Comparison - -```sql -SELECT - department, - total_requests, - approved_requests, - ROUND(approved_requests * 100.0 / NULLIF(total_requests, 0), 2) as approval_rate, - ROUND(avg_cycle_time_hours / 24, 2) as avg_cycle_days -FROM vw_department_summary -WHERE department IS NOT NULL -ORDER BY total_requests DESC; -``` - ---- - -## ๐Ÿš€ How TAT Alerts Work - -### 1. When Request is Submitted - -``` -โœ… TAT monitoring starts for Level 1 -โœ… Jobs scheduled: 50%, 75%, 100% -โœ… level_start_time and tat_start_time set -``` - -### 2. When Notification Fires - -``` -โœ… Notification sent to approver -โœ… Record created in tat_alerts table -โœ… Activity logged -โœ… Flags updated in approval_levels -``` - -### 3. Display in UI - -```javascript -// Frontend can fetch and display like: -const alerts = await getTATAlerts(requestId, levelId); - -alerts.forEach(alert => { - console.log(`Reminder ${alert.threshold_percentage}%: ${alert.alert_message}`); - console.log(`Sent at: ${formatDate(alert.alert_sent_at)}`); -}); -``` - ---- - -## ๐Ÿ“ˆ Analytical Reports Supported - -1. **Request Lifecycle Report** - Complete timeline with TAT -2. **Approver Performance Report** - Leaderboard & metrics -3. **Department-wise Summary** - Cross-department comparison -4. **TAT Breach Report** - All breached requests with reasons -5. **Priority Distribution** - Express vs Standard analysis -6. **Workflow Aging** - Long-running requests -7. **Daily/Weekly Trends** - Time-series analysis -8. **Engagement Metrics** - Collaboration tracking - ---- - -## ๐ŸŽฏ Next Steps - -### 1. Setup Upstash Redis (REQUIRED) - -TAT notifications need Redis to work: - -1. Go to: https://console.upstash.com/ -2. Create free Redis database -3. Copy connection URL -4. Add to `.env`: - ```bash - REDIS_URL=rediss://default:PASSWORD@host.upstash.io:6379 - TAT_TEST_MODE=true - ``` -5. Restart backend - -See: `START_HERE.md` or `TAT_QUICK_START.md` - -### 2. Test TAT Notifications - -1. Create request with 6-hour TAT (becomes 6 minutes in test mode) -2. Submit request -3. Wait for notifications: 3min, 4.5min, 6min -4. Check `tat_alerts` table -5. Verify display in Request Detail screen - -### 3. Build Frontend Reports - -Use the KPI views to build: -- Dashboard cards -- Charts (pie, bar, line) -- Tables with filters -- Export to CSV - ---- - -## ๐Ÿ“š Documentation - -| Document | Purpose | -|----------|---------| -| `docs/KPI_REPORTING_SYSTEM.md` | Complete KPI guide with all queries | -| `docs/TAT_NOTIFICATION_SYSTEM.md` | TAT system architecture | -| `TAT_QUICK_START.md` | Quick setup for TAT | -| `START_HERE.md` | Start here for TAT setup | -| `backend_structure.txt` | Database schema reference | - ---- - -## ๐Ÿ” Database Schema Summary - -``` -tat_alerts (NEW) -โ”œโ”€ alert_id (PK) -โ”œโ”€ request_id (FK โ†’ workflow_requests) -โ”œโ”€ level_id (FK โ†’ approval_levels) -โ”œโ”€ approver_id (FK โ†’ users) -โ”œโ”€ alert_type (TAT_50, TAT_75, TAT_100) -โ”œโ”€ threshold_percentage (50, 75, 100) -โ”œโ”€ tat_hours_allocated -โ”œโ”€ tat_hours_elapsed -โ”œโ”€ tat_hours_remaining -โ”œโ”€ level_start_time -โ”œโ”€ alert_sent_at -โ”œโ”€ expected_completion_time -โ”œโ”€ alert_message -โ”œโ”€ notification_sent -โ”œโ”€ notification_channels (array) -โ”œโ”€ is_breached -โ”œโ”€ was_completed_on_time -โ”œโ”€ completion_time -โ”œโ”€ metadata (JSONB) -โ””โ”€ created_at - -approval_levels (UPDATED) -โ”œโ”€ ... existing fields ... -โ”œโ”€ tat50_alert_sent (NEW) -โ”œโ”€ tat75_alert_sent (NEW) -โ”œโ”€ tat_breached (NEW) -โ””โ”€ tat_start_time (NEW) - -8 Views Created: -โ”œโ”€ vw_request_volume_summary -โ”œโ”€ vw_tat_compliance -โ”œโ”€ vw_approver_performance -โ”œโ”€ vw_tat_alerts_summary -โ”œโ”€ vw_department_summary -โ”œโ”€ vw_daily_kpi_metrics -โ”œโ”€ vw_workflow_aging -โ””โ”€ vw_engagement_metrics -``` - ---- - -## โœ… Implementation Checklist - -- [x] Create `tat_alerts` table -- [x] Add TAT status fields to `approval_levels` -- [x] Create 8 KPI views for reporting -- [x] Update TAT processor to log alerts -- [x] Export `TatAlert` model -- [x] Run all migrations successfully -- [x] Create comprehensive documentation -- [ ] Setup Upstash Redis (YOU DO THIS) -- [ ] Test TAT notifications (YOU DO THIS) -- [ ] Build frontend KPI dashboards (YOU DO THIS) - ---- - -## ๐ŸŽ‰ Status: READY TO USE! - -- โœ… Database schema complete -- โœ… TAT alerts logging ready -- โœ… KPI views optimized -- โœ… All migrations applied -- โœ… Documentation complete - -**Just connect Redis and you're good to go!** - ---- - -**Last Updated**: November 4, 2025 -**Team**: Royal Enfield Workflow System - diff --git a/MIGRATION_QUICK_REFERENCE.md b/MIGRATION_QUICK_REFERENCE.md deleted file mode 100644 index e9b8067..0000000 --- a/MIGRATION_QUICK_REFERENCE.md +++ /dev/null @@ -1,120 +0,0 @@ -# ๐Ÿš€ Migration Quick Reference - -## Daily Development Workflow - -### Starting Development (Auto-runs Migrations) -```bash -npm run dev -``` -โœ… **This will automatically run all new migrations before starting the server!** - -### Run Migrations Only -```bash -npm run migrate -``` - -## Adding a New Migration (3 Steps) - -### 1๏ธโƒฃ Create Migration File -Location: `src/migrations/YYYYMMDD-description.ts` - -```typescript -import { QueryInterface, DataTypes } from 'sequelize'; - -export async function up(queryInterface: QueryInterface): Promise { - await queryInterface.addColumn('table_name', 'column_name', { - type: DataTypes.STRING, - allowNull: true, - }); - console.log('โœ… Migration completed'); -} - -export async function down(queryInterface: QueryInterface): Promise { - await queryInterface.removeColumn('table_name', 'column_name'); - console.log('โœ… Rollback completed'); -} -``` - -### 2๏ธโƒฃ Register in `src/scripts/migrate.ts` -```typescript -// Add import at top -import * as m15 from '../migrations/YYYYMMDD-description'; - -// Add execution in run() function -await (m15 as any).up(sequelize.getQueryInterface()); -``` - -### 3๏ธโƒฃ Test -```bash -npm run migrate -``` - -## Common Operations - -### Add Column -```typescript -await queryInterface.addColumn('table', 'column', { - type: DataTypes.STRING(100), - allowNull: false, - defaultValue: 'value' -}); -``` - -### Add Foreign Key -```typescript -await queryInterface.addColumn('table', 'foreign_id', { - type: DataTypes.UUID, - references: { model: 'other_table', key: 'id' }, - onUpdate: 'CASCADE', - onDelete: 'SET NULL' -}); -``` - -### Add Index -```typescript -await queryInterface.addIndex('table', ['column'], { - name: 'idx_table_column' -}); -``` - -### Create Table -```typescript -await queryInterface.createTable('new_table', { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true - }, - name: DataTypes.STRING(100), - created_at: DataTypes.DATE, - updated_at: DataTypes.DATE -}); -``` - -## What's New โœจ - -### Latest Migration: Skip Approver Functionality -- **File**: `20251105-add-skip-fields-to-approval-levels.ts` -- **Added Fields**: - - `is_skipped` - Boolean flag - - `skipped_at` - Timestamp - - `skipped_by` - User reference - - `skip_reason` - Text explanation -- **Index**: Partial index on `is_skipped = TRUE` - -## Troubleshooting - -| Issue | Solution | -|-------|----------| -| Migration fails | Check console error, fix migration file, re-run | -| Column exists error | Migration partially ran - add idempotent checks | -| Server won't start | Fix migration first, it blocks startup | - -## ๐Ÿ“š Full Documentation -See `MIGRATION_WORKFLOW.md` for comprehensive guide. - ---- -**Auto-Migration**: โœ… Enabled -**Total Migrations**: 14 -**Latest**: 2025-11-05 - diff --git a/MIGRATION_WORKFLOW.md b/MIGRATION_WORKFLOW.md deleted file mode 100644 index 94f090c..0000000 --- a/MIGRATION_WORKFLOW.md +++ /dev/null @@ -1,284 +0,0 @@ -# Migration Workflow Guide - -## Overview -This project uses a TypeScript-based migration system for database schema changes. All migrations are automatically executed when you start the development server. - -## ๐Ÿš€ Quick Start - -### Running Development Server with Migrations -```bash -npm run dev -``` -This command will: -1. โœ… Run all pending migrations automatically -2. ๐Ÿš€ Start the development server with hot reload - -### Running Migrations Only -```bash -npm run migrate -``` -Use this when you only want to apply migrations without starting the server. - -## ๐Ÿ“ Creating New Migrations - -### Step 1: Create Migration File -Create a new TypeScript file in `src/migrations/` with the naming pattern: -``` -YYYYMMDD-descriptive-name.ts -``` - -Example: `20251105-add-new-field.ts` - -### Step 2: Migration Template -```typescript -import { QueryInterface, DataTypes } from 'sequelize'; - -/** - * Migration: Brief description - * Purpose: Detailed explanation - * Date: YYYY-MM-DD - */ - -export async function up(queryInterface: QueryInterface): Promise { - // Add your forward migration logic here - await queryInterface.addColumn('table_name', 'column_name', { - type: DataTypes.STRING, - allowNull: true, - }); - - console.log('โœ… Migration description completed'); -} - -export async function down(queryInterface: QueryInterface): Promise { - // Add your rollback logic here - await queryInterface.removeColumn('table_name', 'column_name'); - - console.log('โœ… Migration rolled back'); -} -``` - -### Step 3: Register Migration -Add your new migration to `src/scripts/migrate.ts`: - -```typescript -// 1. Import at the top -import * as m15 from '../migrations/20251105-add-new-field'; - -// 2. Execute in the run() function -await (m15 as any).up(sequelize.getQueryInterface()); -``` - -### Step 4: Test -```bash -npm run migrate -``` - -## ๐Ÿ“‹ Current Migrations - -The following migrations are configured and will run in order: - -1. `2025103001-create-workflow-requests` - Core workflow requests table -2. `2025103002-create-approval-levels` - Approval hierarchy structure -3. `2025103003-create-participants` - Workflow participants -4. `2025103004-create-documents` - Document attachments -5. `20251031_01_create_subscriptions` - User subscriptions -6. `20251031_02_create_activities` - Activity tracking -7. `20251031_03_create_work_notes` - Work notes/comments -8. `20251031_04_create_work_note_attachments` - Note attachments -9. `20251104-add-tat-alert-fields` - TAT alert fields -10. `20251104-create-tat-alerts` - TAT alerts table -11. `20251104-create-kpi-views` - KPI database views -12. `20251104-create-holidays` - Holiday calendar -13. `20251104-create-admin-config` - Admin configurations -14. `20251105-add-skip-fields-to-approval-levels` - Skip approver functionality - -## ๐Ÿ”„ Migration Safety Features - -### Idempotent Migrations -All migrations should be **idempotent** (safe to run multiple times). Use checks like: - -```typescript -// Check if column exists before adding -const tableDescription = await queryInterface.describeTable('table_name'); -if (!tableDescription.column_name) { - await queryInterface.addColumn(/* ... */); -} - -// Check if table exists before creating -const tables = await queryInterface.showAllTables(); -if (!tables.includes('table_name')) { - await queryInterface.createTable(/* ... */); -} -``` - -### Error Handling -Migrations automatically: -- โœ… Stop on first error -- โŒ Exit with error code 1 on failure -- ๐Ÿ“ Log detailed error messages -- ๐Ÿ”„ Prevent server startup if migrations fail - -## ๐Ÿ› ๏ธ Common Migration Operations - -### Adding a Column -```typescript -await queryInterface.addColumn('table_name', 'new_column', { - type: DataTypes.STRING(100), - allowNull: false, - defaultValue: 'default_value', - comment: 'Column description' -}); -``` - -### Adding Foreign Key -```typescript -await queryInterface.addColumn('table_name', 'foreign_key_id', { - type: DataTypes.UUID, - allowNull: true, - references: { - model: 'referenced_table', - key: 'id' - }, - onUpdate: 'CASCADE', - onDelete: 'SET NULL' -}); -``` - -### Creating Index -```typescript -await queryInterface.addIndex('table_name', ['column_name'], { - name: 'idx_table_column', - unique: false -}); - -// Partial index with WHERE clause -await queryInterface.addIndex('table_name', ['status'], { - name: 'idx_table_active', - where: { - is_active: true - } -}); -``` - -### Creating Table -```typescript -await queryInterface.createTable('new_table', { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true - }, - name: { - type: DataTypes.STRING(100), - allowNull: false - }, - created_at: { - type: DataTypes.DATE, - allowNull: false, - defaultValue: DataTypes.NOW - }, - updated_at: { - type: DataTypes.DATE, - allowNull: false, - defaultValue: DataTypes.NOW - } -}); -``` - -### Modifying Column -```typescript -await queryInterface.changeColumn('table_name', 'column_name', { - type: DataTypes.STRING(200), // Changed from 100 - allowNull: true // Changed from false -}); -``` - -### Dropping Column -```typescript -await queryInterface.removeColumn('table_name', 'old_column'); -``` - -### Raw SQL Queries -```typescript -await queryInterface.sequelize.query(` - CREATE OR REPLACE VIEW view_name AS - SELECT * FROM table_name WHERE condition -`); -``` - -## ๐Ÿ“Š Database Structure Reference - -Always refer to `backend_structure.txt` for the authoritative database structure including: -- All tables and their columns -- Data types and constraints -- Relationships and foreign keys -- Enum values -- Indexes - -## ๐Ÿšจ Troubleshooting - -### Migration Fails with "Column Already Exists" -- The migration might have partially run -- Add idempotent checks or manually rollback the failed migration - -### Server Won't Start After Migration -- Check the migration error in console -- Fix the migration file -- Run `npm run migrate` to retry - -### Need to Rollback a Migration -```bash -# Manual rollback (requires implementing down() function) -ts-node src/scripts/rollback.ts -``` - -## ๐ŸŽฏ Best Practices - -1. **Always test migrations** on development database first -2. **Write rollback logic** in `down()` function -3. **Use descriptive names** for migrations -4. **Add comments** explaining the purpose -5. **Keep migrations small** - one logical change per file -6. **Never modify** existing migration files after they run in production -7. **Use transactions** for complex multi-step migrations -8. **Backup production** before running new migrations - -## ๐Ÿ“ Migration Checklist - -Before running migrations in production: - -- [ ] Tested on local development database -- [ ] Verified rollback functionality works -- [ ] Checked for data loss scenarios -- [ ] Reviewed index impact on performance -- [ ] Confirmed migration is idempotent -- [ ] Updated `backend_structure.txt` documentation -- [ ] Added migration to version control -- [ ] Registered in `migrate.ts` - -## ๐Ÿ”— Related Files - -- **Migration Scripts**: `src/migrations/` -- **Migration Runner**: `src/scripts/migrate.ts` -- **Database Config**: `src/config/database.ts` -- **Database Structure**: `backend_structure.txt` -- **Package Scripts**: `package.json` - -## ๐Ÿ’ก Example: Recent Migration - -The latest migration (`20251105-add-skip-fields-to-approval-levels`) demonstrates best practices: - -- โœ… Descriptive naming -- โœ… Clear documentation -- โœ… Multiple related columns added together -- โœ… Foreign key relationships -- โœ… Indexed for query performance -- โœ… Includes rollback logic -- โœ… Helpful console messages - ---- - -**Last Updated**: November 5, 2025 -**Migration Count**: 14 migrations -**Auto-Run**: Enabled for `npm run dev` - diff --git a/QUICK_FIX_CONFIGURATIONS.md b/QUICK_FIX_CONFIGURATIONS.md deleted file mode 100644 index 3473b2c..0000000 --- a/QUICK_FIX_CONFIGURATIONS.md +++ /dev/null @@ -1,220 +0,0 @@ -# Quick Fix: Settings Not Editable Issue - -## ๐Ÿ”ด Problem -Settings showing as "not editable" in the frontend. - -## ๐ŸŽฏ Root Cause -**Field Mapping Issue:** Database uses `is_editable` (snake_case) but frontend expects `isEditable` (camelCase). - -## โœ… Solution Applied - -### **1. Fixed Admin Controller** โœ… -Added field mapping from snake_case to camelCase: -```typescript -// Re_Backend/src/controllers/admin.controller.ts -const configurations = rawConfigurations.map(config => ({ - configId: config.config_id, // โœ… Mapped - isEditable: config.is_editable, // โœ… Mapped - isSensitive: config.is_sensitive, // โœ… Mapped - requiresRestart: config.requires_restart, // โœ… Mapped - // ... all other fields -})); -``` - -### **2. Database Fix Required** - -**Option A: Delete and Re-seed** (Recommended if no custom configs) -```sql --- Connect to your database -DELETE FROM admin_configurations; - --- Restart backend - auto-seeding will run --- Check logs for: "โœ… Default configurations seeded (18 settings)" -``` - -**Option B: Fix Existing Records** (If you have custom values) -```sql --- Update existing records to add missing fields -UPDATE admin_configurations -SET - is_sensitive = COALESCE(is_sensitive, false), - requires_restart = COALESCE(requires_restart, false), - is_editable = COALESCE(is_editable, true) -WHERE is_sensitive IS NULL - OR requires_restart IS NULL - OR is_editable IS NULL; - --- Set requires_restart = true for settings that need it -UPDATE admin_configurations -SET requires_restart = true -WHERE config_key IN ( - 'WORK_START_HOUR', - 'WORK_END_HOUR', - 'MAX_FILE_SIZE_MB', - 'ALLOWED_FILE_TYPES' -); -``` - ---- - -## ๐Ÿš€ Step-by-Step Fix - -### **Step 1: Stop Backend** -```bash -# Press Ctrl+C to stop the server -``` - -### **Step 2: Clear Configurations** (if any exist) -```sql --- Connect to PostgreSQL -psql -U postgres -d re_workflow - --- Check if configurations exist -SELECT COUNT(*) FROM admin_configurations; - --- If count > 0, delete them -DELETE FROM admin_configurations; - --- Verify -SELECT COUNT(*) FROM admin_configurations; --- Should show: 0 -``` - -### **Step 3: Restart Backend** (Auto-seeds) -```bash -cd Re_Backend -npm run dev -``` - -### **Step 4: Verify Seeding in Logs** -Look for: -``` -โš™๏ธ System configurations initialized -โœ… Default configurations seeded successfully (18 settings across 7 categories) -``` - -### **Step 5: Test in Frontend** -1. Login as Admin user -2. Go to **Settings โ†’ System Configuration** -3. You should see **7 category tabs** -4. Click any tab (e.g., "TAT SETTINGS") -5. All settings should now have: - - โœ… Editable input fields - - โœ… **Save** button enabled - - โœ… **Reset to Default** button - ---- - -## ๐Ÿงช Verify Configuration Loaded Correctly - -**Test API Endpoint:** -```bash -# Get all configurations -curl http://localhost:5000/api/v1/admin/configurations \ - -H "Authorization: Bearer YOUR_JWT_TOKEN" -``` - -**Expected Response:** -```json -{ - "success": true, - "data": [ - { - "configId": "uuid...", - "configKey": "DEFAULT_TAT_EXPRESS_HOURS", - "configCategory": "TAT_SETTINGS", - "configValue": "24", - "valueType": "NUMBER", - "displayName": "Default TAT for Express Priority", - "isEditable": true, // โœ… Should be true - "isSensitive": false, - "validationRules": {"min": 1, "max": 168}, - "uiComponent": "number", - "sortOrder": 1, - "requiresRestart": false - }, - // ... 17 more configurations - ], - "count": 18 -} -``` - -**Check the `isEditable` field - should be `true` for all!** - ---- - -## ๐Ÿ› Common Issues & Solutions - -### Issue 1: "Configurations already exist. Skipping seed." -**Cause:** Old configurations in database -**Fix:** Delete them and restart backend - -### Issue 2: Settings show as gray/disabled -**Cause:** `is_editable = false` in database -**Fix:** Run SQL update to set all to `true` - -### Issue 3: "Configuration not found or not editable" error when saving -**Cause:** Backend can't find the config or `is_editable = false` -**Fix:** Verify database has correct values - -### Issue 4: Empty settings page -**Cause:** No configurations in database -**Fix:** Check backend logs for seeding errors, run seed manually - ---- - -## ๐Ÿ“Š Expected Database State - -After successful seeding, your `admin_configurations` table should have: - -| Count | Category | All Editable? | -|-------|----------|---------------| -| 6 | TAT_SETTINGS | โœ… Yes | -| 3 | DOCUMENT_POLICY | โœ… Yes | -| 2 | AI_CONFIGURATION | โœ… Yes | -| 3 | NOTIFICATION_RULES | โœ… Yes | -| 4 | DASHBOARD_LAYOUT | โœ… Yes | -| 3 | WORKFLOW_SHARING | โœ… Yes | -| 2 | WORKFLOW_LIMITS | โœ… Yes | -| **18 Total** | **7 Categories** | **โœ… All Editable** | - -Query to verify: -```sql -SELECT - config_category, - COUNT(*) as total, - SUM(CASE WHEN is_editable = true THEN 1 ELSE 0 END) as editable_count -FROM admin_configurations -GROUP BY config_category -ORDER BY config_category; -``` - -Should show 100% editable in all categories! - ---- - -## โœ… After Fix - Settings UI Will Show: - -``` -Settings โ†’ System Configuration - -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ [TAT SETTINGS] [DOCUMENT POLICY] [...] โ”‚ โ† 7 tabs -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ โฐ Default TAT for Express Priority โ”‚ -โ”‚ (Description...) โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ” โ† EDITABLE โ”‚ -โ”‚ โ”‚ 24 โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ [๐Ÿ’พ Save] [๐Ÿ”„ Reset] โ† ENABLED โ”‚ -โ”‚ โ”‚ -โ”‚ โฐ First TAT Reminder (%) โ”‚ -โ”‚ โ”โ”โ”โ”โ—โ”โ”โ”โ” 50% โ† SLIDER WORKS โ”‚ -โ”‚ [๐Ÿ’พ Save] [๐Ÿ”„ Reset] โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**All inputs should be EDITABLE and Save buttons ENABLED!** โœ… - diff --git a/QUICK_START_SKIP_ADD_APPROVER.md b/QUICK_START_SKIP_ADD_APPROVER.md deleted file mode 100644 index 6a14187..0000000 --- a/QUICK_START_SKIP_ADD_APPROVER.md +++ /dev/null @@ -1,253 +0,0 @@ -# Quick Start: Skip & Add Approver Features - -## ๐Ÿš€ Setup (One-Time) - -### **Step 1: Run Database Migration** - -```bash -# Connect to database -psql -U postgres -d re_workflow - -# Run migration -\i Re_Backend/src/migrations/add_is_skipped_to_approval_levels.sql - -# Verify columns added -\d approval_levels -# Should show: is_skipped, skipped_at, skipped_by, skip_reason -``` - -### **Step 2: Restart Backend** - -```bash -cd Re_Backend -npm run dev -``` - ---- - -## ๐Ÿ“– User Guide - -### **How to Skip an Approver (Initiator/Approver)** - -1. Go to **Request Detail** โ†’ **Workflow** tab -2. Find the approver who is pending/in-review -3. Click **"Skip This Approver"** button -4. Enter reason (e.g., "On vacation") -5. Click OK - -**Result:** -- โœ… Approver marked as SKIPPED -- โœ… Next approver becomes active -- โœ… Notification sent to next approver -- โœ… Activity logged - ---- - -### **How to Add New Approver (Initiator/Approver)** - -1. Go to **Request Detail** โ†’ **Quick Actions** -2. Click **"Add Approver"** -3. Review **Current Levels** (shows all existing approvers with status) -4. Select **Approval Level** (where to insert new approver) -5. Enter **TAT Hours** (e.g., 48) -6. Enter **Email** (use @ to search: `@john`) -7. Click **"Add at Level X"** - -**Result:** -- โœ… New approver inserted at chosen level -- โœ… Existing approvers shifted automatically -- โœ… TAT jobs scheduled if level is active -- โœ… Notification sent to new approver -- โœ… Activity logged - ---- - -## ๐ŸŽฏ Examples - -### **Example 1: Skip Non-Responding Approver** - -**Scenario:** Mike (Level 2) hasn't responded for 3 days, deadline approaching - -**Steps:** -1. Open request REQ-2025-001 -2. Go to Workflow tab -3. Find Mike's card (Level 2 - In Review) -4. Click "Skip This Approver" -5. Reason: "Approver on extended leave - deadline critical" -6. Confirm - -**Result:** -``` -Before: After: -Level 1: Sarah โœ… Level 1: Sarah โœ… -Level 2: Mike โณ โ†’ Level 2: Mike โญ๏ธ (SKIPPED) -Level 3: Lisa โธ๏ธ Level 3: Lisa โณ (ACTIVE!) -``` - ---- - -### **Example 2: Add Finance Review** - -**Scenario:** Need Finance Manager approval between existing levels - -**Steps:** -1. Click "Add Approver" in Quick Actions -2. See current levels: - - Level 1: Sarah (Approved) - - Level 2: Mike (In Review) - - Level 3: Lisa (Waiting) -3. Select Level: **3** (to insert before Lisa) -4. TAT Hours: **48** -5. Email: `@john` โ†’ Select "John Doe (john@finance.com)" -6. Click "Add at Level 3" - -**Result:** -``` -Before: After: -Level 1: Sarah โœ… Level 1: Sarah โœ… -Level 2: Mike โณ Level 2: Mike โณ -Level 3: Lisa โธ๏ธ โ†’ Level 3: John โธ๏ธ (NEW!) - Level 4: Lisa โธ๏ธ (shifted) -``` - ---- - -## โš™๏ธ API Reference - -### **Skip Approver** - -```bash -POST /api/v1/workflows/:requestId/approvals/:levelId/skip - -Headers: - Authorization: Bearer - -Body: -{ - "reason": "Approver on vacation" -} - -Response: -{ - "success": true, - "message": "Approver skipped successfully" -} -``` - ---- - -### **Add Approver at Level** - -```bash -POST /api/v1/workflows/:requestId/approvers/at-level - -Headers: - Authorization: Bearer - -Body: -{ - "email": "john@example.com", - "tatHours": 48, - "level": 3 -} - -Response: -{ - "success": true, - "message": "Approver added successfully", - "data": { - "levelId": "...", - "levelNumber": 3, - "approverName": "John Doe", - "tatHours": 48 - } -} -``` - ---- - -## ๐Ÿ›ก๏ธ Permissions - -| Action | Who Can Do It | -|--------|---------------| -| Skip Approver | โœ… INITIATOR, โœ… APPROVER | -| Add Approver | โœ… INITIATOR, โœ… APPROVER | -| View Skip Reason | โœ… All participants | - ---- - -## โš ๏ธ Limitations - -| Limitation | Reason | -|------------|--------| -| Cannot skip approved levels | Data integrity | -| Cannot skip rejected levels | Already closed | -| Cannot skip already skipped levels | Already handled | -| Cannot skip future levels | Not yet active | -| Cannot add before completed levels | Would break workflow state | -| Must provide valid TAT (1-720h) | Business rules | - ---- - -## ๐Ÿ“Š Dashboard Impact - -### **Skipped Approvers in Reports:** - -```sql --- Count skipped approvers -SELECT COUNT(*) -FROM approval_levels -WHERE is_skipped = TRUE; - --- Find requests with skipped levels -SELECT r.request_number, al.level_number, al.approver_name, al.skip_reason -FROM workflow_requests r -JOIN approval_levels al ON r.request_id = al.request_id -WHERE al.is_skipped = TRUE; -``` - -### **KPIs Affected:** - -- **Avg Approval Time** - Skipped levels excluded from calculation -- **Approver Response Rate** - Skipped marked separately -- **Workflow Bottlenecks** - Identify frequently skipped approvers - ---- - -## ๐Ÿ” Troubleshooting - -### **"Cannot skip approver - level is already APPROVED"** -- The level has already been approved -- You cannot skip completed levels - -### **"Cannot skip future approval levels"** -- You're trying to skip a level that hasn't been reached yet -- Only current level can be skipped - -### **"Cannot add approver at level X. Minimum allowed level is Y"** -- You're trying to add before a completed level -- Must add after all approved/rejected/skipped levels - -### **"User is already a participant in this request"** -- The user is already an approver, initiator, or spectator -- Cannot add same user twice - ---- - -## โœ… Testing Checklist - -- [ ] Run database migration -- [ ] Restart backend server -- [ ] Create test workflow with 3 approvers -- [ ] Approve Level 1 -- [ ] Skip Level 2 (test skip functionality) -- [ ] Verify Level 3 becomes active -- [ ] Add new approver at Level 3 (test add functionality) -- [ ] Verify levels shifted correctly -- [ ] Check activity log shows both actions -- [ ] Verify notifications sent correctly - ---- - -Ready to use! ๐ŸŽ‰ - diff --git a/SETUP_COMPLETE.md b/SETUP_COMPLETE.md deleted file mode 100644 index 6e87a68..0000000 --- a/SETUP_COMPLETE.md +++ /dev/null @@ -1,216 +0,0 @@ -# โœ… Holiday Calendar & Admin Configuration - Setup Complete! - -## ๐ŸŽ‰ Successfully Implemented - -### **Database Tables Created:** -1. โœ… `holidays` - Organization holiday calendar -2. โœ… `admin_configurations` - System-wide admin settings - -### **API Endpoints Created:** -- โœ… `/api/admin/holidays` - CRUD operations for holidays -- โœ… `/api/admin/configurations` - Manage admin settings - -### **Features Implemented:** -- โœ… Holiday management (add/edit/delete/bulk import) -- โœ… TAT calculation excludes holidays for STANDARD priority -- โœ… Automatic holiday cache with 6-hour refresh -- โœ… Admin configuration system ready for future UI -- โœ… Sample Indian holidays data (2025) prepared for import - ---- - -## ๐Ÿš€ Quick Start - -### **1. Verify Tables:** -```bash -# Check if tables were created -psql -d your_database -c "\dt holidays" -psql -d your_database -c "\dt admin_configurations" -``` - -### **2. Start the Backend:** -```bash -npm run dev -``` - -**You should see:** -``` -๐Ÿ“… Holiday calendar loaded for TAT calculations -[TAT Utils] Loaded 0 holidays into cache -``` - -### **3. Add Your First Holiday (via API):** - -**As Admin user:** -```bash -curl -X POST http://localhost:5000/api/admin/holidays \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ - -d '{ - "holidayDate": "2025-11-05", - "holidayName": "Diwali", - "description": "Festival of Lights", - "holidayType": "NATIONAL" - }' -``` - -### **4. Bulk Import Indian Holidays (Optional):** -```bash -curl -X POST http://localhost:5000/api/admin/holidays/bulk-import \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ - -d @data/indian_holidays_2025.json -``` - ---- - -## ๐Ÿ“Š How It Works - -### **TAT Calculation with Holidays:** - -**STANDARD Priority:** -- โŒ Skips **weekends** (Saturday/Sunday) -- โŒ Skips **holidays** (from holidays table) -- โœ… Only counts **working hours** (9 AM - 6 PM) - -**EXPRESS Priority:** -- โœ… Includes **all days** (24/7) -- โœ… No holidays or weekends excluded - ---- - -## ๐Ÿ“š Documentation - -- **Full Guide:** `docs/HOLIDAY_CALENDAR_SYSTEM.md` -- **Complete Summary:** `HOLIDAY_AND_ADMIN_CONFIG_COMPLETE.md` - ---- - -## ๐ŸŽฏ Next Steps - -### **For Backend Developers:** -1. Test holiday API endpoints -2. Verify TAT calculations with holidays -3. Add more admin configurations as needed - -### **For Frontend Developers:** -1. Build Admin Holiday Management UI -2. Create Holiday Calendar view -3. Implement Configuration Settings page - ---- - -## ๐Ÿ” Verify Setup - -### **Check Holidays Table:** -```sql -SELECT * FROM holidays; --- Should return 0 rows (no holidays added yet) -``` - -### **Check Admin Configurations:** -```sql -SELECT * FROM admin_configurations; --- Should return 0 rows (will be seeded on first use) -``` - -### **Test Holiday API:** -```bash -# Get all holidays for 2025 -curl http://localhost:5000/api/admin/holidays?year=2025 \ - -H "Authorization: Bearer YOUR_ADMIN_TOKEN" -``` - ---- - -## ๐Ÿ“‹ Sample Holidays Data - -**File:** `data/indian_holidays_2025.json` - -Contains 14 Indian national holidays for 2025: -- Republic Day (Jan 26) -- Holi -- Independence Day (Aug 15) -- Gandhi Jayanti (Oct 2) -- Diwali -- Christmas -- And more... - ---- - -## โœ… Setup Status - -| Component | Status | Notes | -|-----------|--------|-------| -| **Holidays Table** | โœ… Created | With 4 indexes | -| **Admin Config Table** | โœ… Created | With 3 indexes | -| **Holiday Model** | โœ… Implemented | Full CRUD support | -| **Holiday Service** | โœ… Implemented | Including bulk import | -| **Admin Controller** | โœ… Implemented | All endpoints ready | -| **Admin Routes** | โœ… Implemented | Secured with admin middleware | -| **TAT Integration** | โœ… Implemented | Holidays excluded for STANDARD | -| **Holiday Cache** | โœ… Implemented | 6-hour expiry, auto-refresh | -| **Sample Data** | โœ… Created | 14 holidays for 2025 | -| **Documentation** | โœ… Complete | Full guide available | - ---- - -## ๐ŸŽ“ Example Usage - -### **Create Request with Holiday in TAT Period:** - -```javascript -// Create STANDARD priority request -POST /api/workflows -{ - "title": "Test Request", - "priority": "STANDARD", - "approvers": [ - { "email": "approver@example.com", "tatHours": 48 } - ] -} - -// If holidays exist between now and +48 hours: -// - Due date will be calculated skipping those holidays -// - TAT calculation will be accurate -``` - ---- - -## ๐Ÿ› ๏ธ Troubleshooting - -### **Holidays not excluded from TAT?** - -1. Check if holidays cache is loaded: - - Look for "Loaded X holidays into cache" in server logs -2. Verify priority is STANDARD (EXPRESS doesn't use holidays) -3. Check if holiday exists and is active: - ```sql - SELECT * FROM holidays WHERE holiday_date = '2025-11-05' AND is_active = true; - ``` - -### **Cache not updating after adding holiday?** - -- Cache refreshes automatically when admin adds/updates/deletes holidays -- If not working, restart backend server -- Cache also refreshes every 6 hours automatically - ---- - -## ๐Ÿ“ž Support - -For issues or questions: -1. Check documentation in `docs/` folder -2. Review complete guide in `HOLIDAY_AND_ADMIN_CONFIG_COMPLETE.md` -3. Consult with backend team - ---- - -**๐ŸŽ‰ You're all set! Start adding holidays and enjoy accurate TAT calculations!** - ---- - -**Last Updated:** November 4, 2025 -**Version:** 1.0.0 -**Team:** Royal Enfield Workflow System - diff --git a/SETUP_SUMMARY.md b/SETUP_SUMMARY.md deleted file mode 100644 index 5fc33f4..0000000 --- a/SETUP_SUMMARY.md +++ /dev/null @@ -1,310 +0,0 @@ -# ๐ŸŽ‰ Auto-Migration Setup Summary - -## โœ… Setup Complete! - -Your development environment now automatically runs all migrations when you start the server. - ---- - -## ๐Ÿ“‹ What Changed - -### 1. โœจ New Migration Created -``` -src/migrations/20251105-add-skip-fields-to-approval-levels.ts -``` -**Adds "Skip Approver" functionality to approval_levels table:** -- `is_skipped` - Boolean flag -- `skipped_at` - Timestamp -- `skipped_by` - User reference (FK) -- `skip_reason` - Text explanation -- Optimized index for skipped approvers - -### 2. ๐Ÿ”ง Migration Runner Updated -``` -src/scripts/migrate.ts -``` -**Enhancements:** -- โœ… Added m14 migration import -- โœ… Added m14 execution -- โœ… Better console output with emojis -- โœ… Enhanced error messages - -### 3. ๐Ÿš€ Auto-Run on Development Start -```json -// package.json - "dev" script -"npm run migrate && nodemon --exec ts-node ..." -``` -**Before**: Manual migration required -**After**: Automatic migration on `npm run dev` - -### 4. ๐Ÿ—‘๏ธ Cleanup -``` -โŒ Deleted: src/migrations/add_is_skipped_to_approval_levels.sql -``` -Converted SQL โ†’ TypeScript for consistency - -### 5. ๐Ÿ“š Documentation Created -- โœ… `MIGRATION_WORKFLOW.md` - Complete guide -- โœ… `MIGRATION_QUICK_REFERENCE.md` - Quick reference -- โœ… `AUTO_MIGRATION_SETUP_COMPLETE.md` - Detailed setup docs -- โœ… `SETUP_SUMMARY.md` - This file - ---- - -## ๐ŸŽฏ How to Use - -### Start Development (Most Common) -```bash -npm run dev -``` -**What happens:** -``` -1. ๐Ÿ“ฆ Connect to database -2. ๐Ÿ”„ Run all 14 migrations -3. โœ… Apply any new schema changes -4. ๐Ÿš€ Start development server -5. โ™ป๏ธ Enable hot reload -``` - -### Run Migrations Only -```bash -npm run migrate -``` -**When to use:** -- After pulling new migration files -- Testing migrations before dev start -- Updating database without starting server - ---- - -## ๐Ÿ“Š Current Migration Status - -| # | Migration | Date | -|---|-----------|------| -| 1 | create-workflow-requests | 2025-10-30 | -| 2 | create-approval-levels | 2025-10-30 | -| 3 | create-participants | 2025-10-30 | -| 4 | create-documents | 2025-10-30 | -| 5 | create-subscriptions | 2025-10-31 | -| 6 | create-activities | 2025-10-31 | -| 7 | create-work-notes | 2025-10-31 | -| 8 | create-work-note-attachments | 2025-10-31 | -| 9 | add-tat-alert-fields | 2025-11-04 | -| 10 | create-tat-alerts | 2025-11-04 | -| 11 | create-kpi-views | 2025-11-04 | -| 12 | create-holidays | 2025-11-04 | -| 13 | create-admin-config | 2025-11-04 | -| 14 | **add-skip-fields-to-approval-levels** | 2025-11-05 โœจ **NEW** | - -**Total**: 14 migrations configured and ready - ---- - -## ๐Ÿ”ฅ Key Features - -### Automated Workflow -``` -npm run dev - โ†“ -Runs migrations - โ†“ -Starts server - โ†“ -Ready to code! ๐ŸŽ‰ -``` - -### Safety Features -- โœ… **Idempotent** - Safe to run multiple times -- โœ… **Error Handling** - Stops on first error -- โœ… **Blocks Startup** - Server won't start if migration fails -- โœ… **Rollback Support** - Every migration has down() function -- โœ… **TypeScript** - Type-safe schema changes - -### Developer Experience -- โœ… **Zero Manual Steps** - Everything automatic -- โœ… **Consistent State** - Everyone has same schema -- โœ… **Fast Iteration** - Quick dev cycle -- โœ… **Clear Feedback** - Visual console output - ---- - -## ๐Ÿ“– Quick Reference - -### File Locations -``` -src/ -โ”œโ”€โ”€ migrations/ โ† Migration files -โ”‚ โ”œโ”€โ”€ 2025103001-create-workflow-requests.ts -โ”‚ โ”œโ”€โ”€ ... -โ”‚ โ””โ”€โ”€ 20251105-add-skip-fields-to-approval-levels.ts โœจ -โ”œโ”€โ”€ scripts/ -โ”‚ โ””โ”€โ”€ migrate.ts โ† Migration runner -โ””โ”€โ”€ config/ - โ””โ”€โ”€ database.ts โ† Database config - -Root: -โ”œโ”€โ”€ package.json โ† Dev script with auto-migration -โ”œโ”€โ”€ backend_structure.txt โ† Database schema reference -โ””โ”€โ”€ MIGRATION_*.md โ† Documentation -``` - -### Common Commands -```bash -# Development with auto-migration -npm run dev - -# Migrations only -npm run migrate - -# Build for production -npm run build - -# Type check -npm run type-check - -# Linting -npm run lint -npm run lint:fix -``` - ---- - -## ๐Ÿ†• Adding New Migrations - -### Quick Steps -1. **Create** migration file in `src/migrations/` -2. **Register** in `src/scripts/migrate.ts` -3. **Test** with `npm run dev` or `npm run migrate` - -### Detailed Guide -See `MIGRATION_WORKFLOW.md` for: -- Migration templates -- Common operations -- Best practices -- Troubleshooting -- Safety guidelines - ---- - -## โœจ Benefits - -### For You -- โœ… No more manual migration steps -- โœ… Always up-to-date database schema -- โœ… Less context switching -- โœ… Focus on feature development - -### For Team -- โœ… Consistent development environment -- โœ… Easy onboarding for new developers -- โœ… Clear migration history -- โœ… Professional workflow - -### For Production -- โœ… Tested migration process -- โœ… Rollback capabilities -- โœ… Version controlled schema changes -- โœ… Audit trail of database changes - ---- - -## ๐ŸŽ“ Example Session - -```bash -# You just pulled latest code with new migration -git pull origin main - -# Start development - migrations run automatically -npm run dev - -# Console output: -๐Ÿ“ฆ Database connected -๐Ÿ”„ Running migrations... - -โœ… Created workflow_requests table -โœ… Created approval_levels table -... -โœ… Added skip-related fields to approval_levels table - -โœ… All migrations applied successfully - -๐Ÿš€ Server running on port 5000 -๐Ÿ“Š Environment: development -โฐ TAT Worker: Initialized and listening - -# Your database is now up-to-date! -# Server is running! -# Ready to code! ๐ŸŽ‰ -``` - ---- - -## ๐Ÿ”— Next Steps - -### Immediate -1. โœ… Run `npm run dev` to test auto-migration -2. โœ… Verify all 14 migrations execute successfully -3. โœ… Check database schema for new skip fields - -### When Adding Features -1. Create migration for schema changes -2. Register in migrate.ts -3. Test with `npm run dev` -4. Commit migration with feature code - -### Before Production Deploy -1. Backup production database -2. Test migrations in staging -3. Review migration execution order -4. Deploy with confidence - ---- - -## ๐Ÿ“ž Support & Resources - -| Resource | Location | -|----------|----------| -| Full Guide | `MIGRATION_WORKFLOW.md` | -| Quick Reference | `MIGRATION_QUICK_REFERENCE.md` | -| Setup Details | `AUTO_MIGRATION_SETUP_COMPLETE.md` | -| Database Schema | `backend_structure.txt` | -| Migration Files | `src/migrations/` | -| Migration Runner | `src/scripts/migrate.ts` | - ---- - -## ๐Ÿ† Success Criteria - -- โœ… Auto-migration configured -- โœ… All 14 migrations registered -- โœ… TypeScript migration created for skip fields -- โœ… SQL file converted and cleaned up -- โœ… Documentation completed -- โœ… Package.json updated -- โœ… Migration runner enhanced -- โœ… Ready for development - ---- - -## ๐ŸŽ‰ You're All Set! - -Just run: -```bash -npm run dev -``` - -And watch the magic happen! โœจ - -All new migrations will automatically run before your server starts. - ---- - -**Setup Date**: November 5, 2025 -**Migration System**: TypeScript-based -**Auto-Run**: โœ… Enabled -**Total Migrations**: 14 -**Status**: ๐ŸŸข Production Ready - -**Team**: Royal Enfield .NET Expert Team -**Project**: Workflow Management System - diff --git a/SKIP_AND_ADD_APPROVER.md b/SKIP_AND_ADD_APPROVER.md deleted file mode 100644 index 4527de1..0000000 --- a/SKIP_AND_ADD_APPROVER.md +++ /dev/null @@ -1,751 +0,0 @@ -# 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; - 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 && ( - -)} -``` - ---- - -## 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! ๐Ÿš€ - diff --git a/SMART_MIGRATIONS_COMPLETE.md b/SMART_MIGRATIONS_COMPLETE.md deleted file mode 100644 index 4da1d63..0000000 --- a/SMART_MIGRATIONS_COMPLETE.md +++ /dev/null @@ -1,524 +0,0 @@ -# โœ… Smart Migration System Complete - -## ๐ŸŽฏ What You Asked For - -> "Every time if I do npm run dev, migrations are running right? If that already exist then skip, if it is new tables then do migrations" - -**โœ… DONE!** Your migration system is now intelligent and efficient. - ---- - -## ๐Ÿง  How It Works Now - -### Smart Migration Tracking - -The system now includes: - -1. **๐Ÿ—ƒ๏ธ Migrations Tracking Table** - - Automatically created on first run - - Stores which migrations have been executed - - Prevents duplicate execution - -2. **โญ๏ธ Smart Detection** - - Checks which migrations already ran - - Only executes **new/pending** migrations - - Skips already-completed ones - -3. **๐Ÿ›ก๏ธ Idempotent Migrations** - - Safe to run multiple times - - Checks if tables/columns exist before creating - - No errors if schema already matches - ---- - -## ๐Ÿ“Š What Happens When You Run `npm run dev` - -### First Time (Fresh Database) -``` -๐Ÿ“ฆ Database connected -โœ… Created migrations tracking table -๐Ÿ”„ Running 14 pending migration(s)... - -โณ Running: 2025103001-create-workflow-requests - โœ… Created workflow_requests table -โœ… Completed: 2025103001-create-workflow-requests - -โณ Running: 2025103002-create-approval-levels - โœ… Created approval_levels table -โœ… Completed: 2025103002-create-approval-levels - -... (all 14 migrations run) - -โœ… Successfully applied 14 migration(s) -๐Ÿ“Š Total migrations: 14 -๐Ÿš€ Server running on port 5000 -``` - -### Second Time (All Migrations Already Run) -``` -๐Ÿ“ฆ Database connected -โœ… All migrations are up-to-date (no new migrations to run) -๐Ÿš€ Server running on port 5000 -``` -**โšก Instant startup! No migration overhead!** - -### When You Add a New Migration -``` -๐Ÿ“ฆ Database connected -๐Ÿ”„ Running 1 pending migration(s)... - -โณ Running: 20251106-new-feature - โœ… Added new column -โœ… Completed: 20251106-new-feature - -โœ… Successfully applied 1 migration(s) -๐Ÿ“Š Total migrations: 15 -๐Ÿš€ Server running on port 5000 -``` -**Only the NEW migration runs!** - ---- - -## ๐Ÿ”ง Technical Implementation - -### 1. Migration Tracking Database - -Automatically created table: -```sql -CREATE TABLE migrations ( - id SERIAL PRIMARY KEY, - name VARCHAR(255) NOT NULL UNIQUE, - executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -) -``` - -Tracks: -- โœ… Which migrations have been executed -- โœ… When they were executed -- โœ… Prevents duplicate execution via UNIQUE constraint - -### 2. Smart Migration Runner - -**File**: `src/scripts/migrate.ts` - -**Key Features**: -```typescript -// 1. Check what's already been run -const executedMigrations = await getExecutedMigrations(); - -// 2. Find only new/pending migrations -const pendingMigrations = migrations.filter( - m => !executedMigrations.includes(m.name) -); - -// 3. Skip if nothing to do -if (pendingMigrations.length === 0) { - console.log('โœ… All migrations up-to-date'); - return; -} - -// 4. Run only pending migrations -for (const migration of pendingMigrations) { - await migration.module.up(queryInterface); - await markMigrationExecuted(migration.name); -} -``` - -### 3. Idempotent Migrations - -**Example**: `20251105-add-skip-fields-to-approval-levels.ts` - -**Checks before acting**: -```typescript -// Check if table exists -const tables = await queryInterface.showAllTables(); -if (!tables.includes('approval_levels')) { - return; // Skip if table doesn't exist -} - -// Check if column exists -const tableDescription = await queryInterface.describeTable('approval_levels'); -if (!tableDescription.is_skipped) { - await queryInterface.addColumn(/* ... */); -} - -// Check if index exists -const indexes = await queryInterface.showIndex('approval_levels'); -const indexExists = indexes.some(idx => idx.name === 'idx_name'); -if (!indexExists) { - await queryInterface.addIndex(/* ... */); -} -``` - -**Safe to run multiple times!** - ---- - -## ๐Ÿš€ Usage Examples - -### Daily Development Workflow -```bash -# Morning - start work -npm run dev -# โœ… All up-to-date - server starts immediately - -# After pulling new code with migration -git pull origin main -npm run dev -# ๐Ÿ”„ Runs only the new migration -# โœ… Server starts -``` - -### Adding a New Migration -```bash -# 1. Create migration file -# src/migrations/20251106-add-user-preferences.ts - -# 2. Register in migrate.ts -# (add import and execution) - -# 3. Test -npm run dev -# ๐Ÿ”„ Runs only your new migration - -# 4. Run again to verify idempotency -npm run dev -# โœ… All up-to-date (doesn't run again) -``` - -### Manual Migration Run -```bash -npm run migrate -# Same smart behavior, without starting server -``` - ---- - -## ๐Ÿ“‹ Current Migration Status - -All 14 migrations are now tracked: - -| # | Migration | Status | -|---|-----------|--------| -| 1 | 2025103001-create-workflow-requests | โœ… Tracked | -| 2 | 2025103002-create-approval-levels | โœ… Tracked | -| 3 | 2025103003-create-participants | โœ… Tracked | -| 4 | 2025103004-create-documents | โœ… Tracked | -| 5 | 20251031_01_create_subscriptions | โœ… Tracked | -| 6 | 20251031_02_create_activities | โœ… Tracked | -| 7 | 20251031_03_create_work_notes | โœ… Tracked | -| 8 | 20251031_04_create_work_note_attachments | โœ… Tracked | -| 9 | 20251104-add-tat-alert-fields | โœ… Tracked | -| 10 | 20251104-create-tat-alerts | โœ… Tracked | -| 11 | 20251104-create-kpi-views | โœ… Tracked | -| 12 | 20251104-create-holidays | โœ… Tracked | -| 13 | 20251104-create-admin-config | โœ… Tracked | -| 14 | 20251105-add-skip-fields-to-approval-levels | โœ… Tracked & Idempotent | - ---- - -## โœจ Key Benefits - -### For You (Developer) -- โœ… **Fast Restarts** - No waiting for already-run migrations -- โœ… **No Errors** - Safe to run `npm run dev` anytime -- โœ… **Auto-Detection** - System knows what's new -- โœ… **Zero Configuration** - Just works - -### For Team -- โœ… **Consistent State** - Everyone's database in sync -- โœ… **Easy Onboarding** - New devs run once, all migrates -- โœ… **No Coordination** - No "did you run migrations?" questions -- โœ… **Pull & Run** - Git pull + npm run dev = ready - -### For Production -- โœ… **Safe Deployments** - Won't break if run multiple times -- โœ… **Version Control** - Clear migration history -- โœ… **Rollback Support** - Each migration has down() function -- โœ… **Audit Trail** - migrations table shows execution history - ---- - -## ๐ŸŽ“ Best Practices Implemented - -### 1. Idempotency -โœ… All migrations check existence before creating -โœ… Safe to run multiple times -โœ… No duplicate errors - -### 2. Tracking -โœ… Dedicated migrations table -โœ… Unique constraint prevents duplicates -โœ… Timestamp for audit trail - -### 3. Smart Execution -โœ… Only runs pending migrations -โœ… Maintains execution order -โœ… Fails fast on errors - -### 4. Developer Experience -โœ… Clear console output -โœ… Progress indicators -โœ… Helpful error messages - ---- - -## ๐Ÿ“ Adding New Migrations - -### Template for Idempotent Migrations - -```typescript -import { QueryInterface, DataTypes } from 'sequelize'; - -export async function up(queryInterface: QueryInterface): Promise { - // 1. Check if table exists (for new tables) - const tables = await queryInterface.showAllTables(); - if (!tables.includes('my_table')) { - await queryInterface.createTable('my_table', {/* ... */}); - console.log(' โœ… Created my_table'); - return; - } - - // 2. Check if column exists (for new columns) - const tableDesc = await queryInterface.describeTable('existing_table'); - if (!tableDesc.new_column) { - await queryInterface.addColumn('existing_table', 'new_column', { - type: DataTypes.STRING - }); - console.log(' โœ… Added new_column'); - } - - // 3. Check if index exists (for new indexes) - try { - const indexes: any[] = await queryInterface.showIndex('my_table') as any[]; - const indexExists = Array.isArray(indexes) && - indexes.some((idx: any) => idx.name === 'idx_name'); - - if (!indexExists) { - await queryInterface.addIndex('my_table', ['column'], { - name: 'idx_name' - }); - console.log(' โœ… Added idx_name'); - } - } catch (error) { - console.log(' โ„น๏ธ Index handling skipped'); - } - - console.log('โœ… Migration completed'); -} - -export async function down(queryInterface: QueryInterface): Promise { - // Rollback logic - await queryInterface.removeColumn('my_table', 'new_column'); - console.log('โœ… Rollback completed'); -} -``` - -### Steps to Add New Migration - -1. **Create File**: `src/migrations/YYYYMMDD-description.ts` -2. **Write Migration**: Use idempotent template above -3. **Register**: Add to `src/scripts/migrate.ts`: - ```typescript - import * as m15 from '../migrations/20251106-description'; - - const migrations: Migration[] = [ - // ... existing ... - { name: '20251106-description', module: m15 }, - ]; - ``` -4. **Test**: Run `npm run dev` - only new migration executes -5. **Verify**: Run `npm run dev` again - should skip (already executed) - ---- - -## ๐Ÿงช Testing the System - -### Test 1: First Run -```bash -# Drop database (if testing) -# Then run: -npm run dev - -# Expected: All 14 migrations run -# migrations table created -# Server starts -``` - -### Test 2: Second Run -```bash -npm run dev - -# Expected: "All migrations up-to-date" -# No migrations run -# Instant server start -``` - -### Test 3: New Migration -```bash -# Add migration #15 -npm run dev - -# Expected: Only migration #15 runs -# Shows "Running 1 pending migration" -# Server starts -``` - -### Test 4: Verify Tracking -```bash -# In PostgreSQL: -SELECT * FROM migrations ORDER BY id; - -# Should show all executed migrations with timestamps -``` - ---- - -## ๐Ÿ” Monitoring Migration Status - -### Check Database Directly -```sql --- See all executed migrations -SELECT id, name, executed_at -FROM migrations -ORDER BY id; - --- Count migrations -SELECT COUNT(*) as total_migrations FROM migrations; - --- Latest migration -SELECT name, executed_at -FROM migrations -ORDER BY id DESC -LIMIT 1; -``` - -### Check via Application -```bash -# Run migration script -npm run migrate - -# Output shows: -# - Total migrations in code -# - Already executed count -# - Pending count -``` - ---- - -## ๐Ÿšจ Troubleshooting - -### Issue: "Table already exists" -**Solution**: This shouldn't happen now! But if it does: -- Migration might not be idempotent -- Add table existence check -- See idempotent template above - -### Issue: "Column already exists" -**Solution**: Add column existence check: -```typescript -const tableDesc = await queryInterface.describeTable('table'); -if (!tableDesc.column_name) { - await queryInterface.addColumn(/* ... */); -} -``` - -### Issue: Migration runs every time -**Cause**: Not being marked as executed -**Check**: -```sql -SELECT * FROM migrations WHERE name = 'migration-name'; -``` -If missing, the marking step failed. - -### Issue: Need to rerun a migration -**Solution**: -```sql --- Remove from tracking (use with caution!) -DELETE FROM migrations WHERE name = 'migration-name'; - --- Then run -npm run migrate -``` - ---- - -## ๐Ÿ“Š System Architecture - -``` -npm run dev - โ†“ -migrate.ts runs - โ†“ -Check: migrations table exists? - โ†“ No โ†’ Create it - โ†“ Yes โ†’ Continue - โ†“ -Query: SELECT * FROM migrations - โ†“ -Compare: Code migrations vs DB migrations - โ†“ -Pending = Code - DB - โ†“ -If pending = 0 - โ†“ โ†’ "All up-to-date" โ†’ Start server - โ†“ -If pending > 0 - โ†“ -For each pending migration: - โ†“ - Run migration.up() - โ†“ - INSERT INTO migrations - โ†“ - Mark as complete - โ†“ -All done โ†’ Start server -``` - ---- - -## ๐ŸŽฏ Summary - -### What Changed - -| Before | After | -|--------|-------| -| All migrations run every time | Only new migrations run | -| Errors if tables exist | Smart checks prevent errors | -| No tracking | Migrations table tracks history | -| Slow restarts | Fast restarts | -| Manual coordination needed | Automatic detection | - -### What You Get - -โœ… **Smart Detection** - Knows what's already been run -โœ… **Fast Execution** - Only runs new migrations -โœ… **Error Prevention** - Idempotent checks -โœ… **Clear Feedback** - Detailed console output -โœ… **Audit Trail** - migrations table for history -โœ… **Team-Friendly** - Everyone stays in sync automatically - ---- - -## ๐Ÿš€ You're Ready! - -Just run: -```bash -npm run dev -``` - -**First time**: All migrations execute, database is set up -**Every time after**: Lightning fast, only new migrations run -**Pull new code**: Automatically detects and runs new migrations - -**No manual steps. No coordination needed. Just works!** โœจ - ---- - -**System**: Smart Migration Tracking โœ… -**Idempotency**: Enabled โœ… -**Auto-Detect**: Active โœ… -**Status**: Production Ready ๐ŸŸข -**Date**: November 5, 2025 - diff --git a/START_HERE.md b/START_HERE.md deleted file mode 100644 index 7ed4b5e..0000000 --- a/START_HERE.md +++ /dev/null @@ -1,209 +0,0 @@ -# ๐ŸŽฏ START HERE - TAT Notifications Setup - -## What You Need to Do RIGHT NOW - -### โšก 2-Minute Setup (Upstash Redis) - -1. **Open this link**: https://console.upstash.com/ - - Sign up with GitHub/Google (it's free) - -2. **Create Redis Database**: - - Click "Create Database" - - Name: `redis-tat-dev` - - Type: Regional - - Region: Pick closest to you - - Click "Create" - -3. **Copy the Redis URL**: - - You'll see: `rediss://default:AbC123xyz...@us1-mighty-12345.upstash.io:6379` - - Click the copy button ๐Ÿ“‹ - -4. **Open** `Re_Backend/.env` and add: - ```bash - REDIS_URL=rediss://default:AbC123xyz...@us1-mighty-12345.upstash.io:6379 - TAT_TEST_MODE=true - ``` - -5. **Restart Backend**: - ```bash - cd Re_Backend - npm run dev - ``` - -6. **Look for this** in the logs: - ``` - โœ… [TAT Queue] Connected to Redis - โœ… [TAT Worker] Initialized and listening - โฐ TAT Configuration: - - Test Mode: ENABLED (1 hour = 1 minute) - ``` - -โœ… **DONE!** You're ready to test! - ---- - -## Test It Now (6 Minutes) - -1. **Create a workflow request** via your frontend -2. **Set TAT: 6 hours** (will become 6 minutes in test mode) -3. **Submit the request** -4. **Watch for notifications**: - - **3 minutes**: โณ 50% notification - - **4.5 minutes**: โš ๏ธ 75% warning - - **6 minutes**: โฐ 100% breach - ---- - -## Verify It's Working - -### Check Backend Logs: -```bash -# You should see: -[TAT Scheduler] Calculating TAT milestones... -[TAT Scheduler] โœ… TAT jobs scheduled -[TAT Processor] Processing tat50... -[TAT Processor] tat50 notification sent -``` - -### Check Upstash Console: -1. Go to https://console.upstash.com/ -2. Click your database -3. Click "CLI" tab -4. Type: `KEYS bull:tatQueue:*` -5. Should see your scheduled jobs - -### Check Database: -```sql -SELECT - approver_name, - tat50_alert_sent, - tat75_alert_sent, - tat_breached, - status -FROM approval_levels -WHERE status = 'IN_PROGRESS'; -``` - ---- - -## What Test Mode Does - -``` -Normal Mode: Test Mode: -48 hours โ†’ 48 minutes -24 hours โ†’ 24 minutes -6 hours โ†’ 6 minutes -2 hours โ†’ 2 minutes - -โœ… Perfect for quick testing! -โœ… Turn off for production: TAT_TEST_MODE=false -``` - ---- - -## Troubleshooting - -### โŒ "ECONNREFUSED" Error? - -**Fix**: -1. Check your `.env` file has `REDIS_URL=rediss://...` -2. Verify the URL is correct (copy from Upstash again) -3. Make sure it starts with `rediss://` (double 's') -4. Restart backend: `npm run dev` - -### โŒ No Logs About Redis? - -**Fix**: -1. Check `.env` file exists in `Re_Backend/` folder -2. Make sure you restarted the backend -3. Look for any errors in console - -### โŒ Jobs Not Running? - -**Fix**: -1. Verify `TAT_TEST_MODE=true` in `.env` -2. Make sure request is SUBMITTED (not just created) -3. Check Upstash Console โ†’ Metrics (see if commands are running) - ---- - -## Next Steps - -Once you see the first notification working: - -1. โœ… Test multi-level approvals -2. โœ… Test early approval (jobs should cancel) -3. โœ… Test rejection flow -4. โœ… Check activity logs -5. โœ… Verify database flags - ---- - -## Documentation - -- **Quick Start**: `TAT_QUICK_START.md` -- **Upstash Guide**: `docs/UPSTASH_SETUP_GUIDE.md` -- **Full System Docs**: `docs/TAT_NOTIFICATION_SYSTEM.md` -- **Testing Guide**: `docs/TAT_TESTING_GUIDE.md` -- **Quick Reference**: `UPSTASH_QUICK_REFERENCE.md` - ---- - -## Why Upstash? - -โœ… **No installation** (works on Windows immediately) -โœ… **100% free** for development -โœ… **Same setup** for production -โœ… **No maintenance** required -โœ… **Fast** (global CDN) -โœ… **Secure** (TLS by default) - ---- - -## Production Deployment - -When ready for production: - -1. Keep using Upstash OR install Redis on Linux server: - ```bash - sudo apt install redis-server -y - ``` - -2. Update `.env` on server: - ```bash - REDIS_URL=redis://localhost:6379 # or keep Upstash URL - TAT_TEST_MODE=false # Use real hours - ``` - -3. Deploy and monitor! - ---- - -## Need Help? - -**Upstash Console**: https://console.upstash.com/ -**Our Docs**: See `docs/` folder -**Redis Commands**: Use Upstash Console CLI tab - ---- - -## Status Checklist - -- [ ] Upstash account created -- [ ] Redis database created -- [ ] REDIS_URL copied to `.env` -- [ ] TAT_TEST_MODE=true set -- [ ] Backend restarted -- [ ] Logs show "Connected to Redis" -- [ ] Test request created and submitted -- [ ] First notification received - -โœ… **All done? Congratulations!** ๐ŸŽ‰ - -Your TAT notification system is now LIVE! - ---- - -**Last Updated**: November 4, 2025 -**Team**: Royal Enfield Workflow - diff --git a/TAT_ALERTS_DISPLAY_COMPLETE.md b/TAT_ALERTS_DISPLAY_COMPLETE.md deleted file mode 100644 index 941287f..0000000 --- a/TAT_ALERTS_DISPLAY_COMPLETE.md +++ /dev/null @@ -1,591 +0,0 @@ -# โœ… TAT Alerts Display System - Complete Implementation - -## ๐ŸŽ‰ What's Been Implemented - -Your TAT notification system now **stores every alert** in the database and **displays them in the UI** exactly like your shared screenshot! - ---- - -## ๐Ÿ“Š Complete Flow - -### 1. When Request is Submitted - -```typescript -// First level approver assigned -Level 1: John (TAT: 24 hours) - โ†“ -TAT jobs scheduled for John: - - 50% alert (12 hours) - - 75% alert (18 hours) - - 100% breach (24 hours) -``` - -### 2. When Notification Fires (e.g., 50%) - -**Backend (`tatProcessor.ts`):** -```typescript -โœ… Send notification to John -โœ… Create record in tat_alerts table -โœ… Log activity -โœ… Update approval_levels flags -``` - -**Database Record Created:** -```sql -INSERT INTO tat_alerts ( - request_id, level_id, approver_id, - alert_type = 'TAT_50', - threshold_percentage = 50, - alert_message = 'โณ 50% of TAT elapsed...', - alert_sent_at = NOW(), - ... -) -``` - -### 3. When Displayed in Frontend - -**API Response** (`workflow.service.ts`): -```typescript -{ - workflow: {...}, - approvals: [...], - tatAlerts: [ // โ† NEW! - { - alertType: 'TAT_50', - thresholdPercentage: 50, - alertSentAt: '2024-10-06T14:30:00Z', - alertMessage: 'โณ 50% of TAT elapsed...', - levelId: 'abc-123', - ... - } - ] -} -``` - -**Frontend Display** (`RequestDetail.tsx`): -```tsx -
- โณ Reminder 1 - 50% of SLA breach reminder have been sent - Reminder sent by system automatically - Sent at: Oct 6 at 2:30 PM -
-``` - ---- - -## ๐ŸŽจ UI Display (Matches Your Screenshot) - -### Reminder Card Styling: - -**50% Alert (โณ):** -- Background: `bg-yellow-50` -- Border: `border-yellow-200` -- Icon: โณ - -**75% Alert (โš ๏ธ):** -- Background: `bg-orange-50` -- Border: `border-orange-200` -- Icon: โš ๏ธ - -**100% Breach (โฐ):** -- Background: `bg-red-50` -- Border: `border-red-200` -- Icon: โฐ - -### Display Format: - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โณ Reminder 1 โ”‚ -โ”‚ โ”‚ -โ”‚ 50% of SLA breach reminder have been โ”‚ -โ”‚ sent โ”‚ -โ”‚ โ”‚ -โ”‚ Reminder sent by system automatically โ”‚ -โ”‚ โ”‚ -โ”‚ Sent at: Oct 6 at 2:30 PM โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## ๐Ÿ“ Where Alerts Appear - -### In Workflow Tab: - -Alerts appear **under each approval level card** in the workflow tab: - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Step 2: Lisa Wong (Finance Manager) โ”‚ -โ”‚ Status: pending โ”‚ -โ”‚ TAT: 12 hours โ”‚ -โ”‚ โ”‚ -โ”‚ โณ Reminder 1 โ”‚ โ† TAT Alert #1 -โ”‚ 50% of SLA breach reminder... โ”‚ -โ”‚ Sent at: Oct 6 at 2:30 PM โ”‚ -โ”‚ โ”‚ -โ”‚ โš ๏ธ Reminder 2 โ”‚ โ† TAT Alert #2 -โ”‚ 75% of SLA breach reminder... โ”‚ -โ”‚ Sent at: Oct 6 at 6:30 PM โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## ๐Ÿ”„ Complete Data Flow - -### Backend: - -1. **TAT Processor** (`tatProcessor.ts`): - - Sends notification to approver - - Creates record in `tat_alerts` table - - Logs activity - -2. **Workflow Service** (`workflow.service.ts`): - - Fetches TAT alerts for request - - Includes in API response - - Groups by level ID - -3. **Approval Service** (`approval.service.ts`): - - Updates alerts when level completed - - Sets `was_completed_on_time` - - Sets `completion_time` - -### Frontend: - -1. **Request Detail** (`RequestDetail.tsx`): - - Receives TAT alerts from API - - Filters alerts by level ID - - Displays under each approval level - - Color-codes by threshold - ---- - -## ๐Ÿ“Š Database Schema - -### TAT Alerts Table: - -```sql -SELECT - alert_type, -- TAT_50, TAT_75, TAT_100 - threshold_percentage, -- 50, 75, 100 - alert_sent_at, -- When alert was sent - alert_message, -- Full message text - level_id, -- Which approval level - approver_id, -- Who was notified - was_completed_on_time, -- Completed within TAT? - completion_time -- When completed -FROM tat_alerts -WHERE request_id = 'YOUR_REQUEST_ID' -ORDER BY alert_sent_at ASC; -``` - ---- - -## ๐Ÿงช Testing the Display - -### Step 1: Setup Upstash Redis - -See `START_HERE.md` for quick setup (2 minutes) - -### Step 2: Enable Test Mode - -In `.env`: -```bash -TAT_TEST_MODE=true -``` - -### Step 3: Create Test Request - -- TAT: 6 hours (becomes 6 minutes in test mode) -- Submit the request - -### Step 4: Watch Alerts Appear - -**At 3 minutes (50%):** -``` -โณ Reminder 1 -50% of SLA breach reminder have been sent -Reminder sent by system automatically -Sent at: [timestamp] -``` - -**At 4.5 minutes (75%):** -``` -โš ๏ธ Reminder 2 -75% of SLA breach reminder have been sent -Reminder sent by system automatically -Sent at: [timestamp] -``` - -**At 6 minutes (100%):** -``` -โฐ Reminder 3 -100% of SLA breach reminder have been sent -Reminder sent by system automatically -Sent at: [timestamp] -``` - -### Step 5: Verify in Database - -```sql -SELECT - threshold_percentage, - alert_sent_at, - was_completed_on_time, - completion_time -FROM tat_alerts -WHERE request_id = 'YOUR_REQUEST_ID' -ORDER BY threshold_percentage; -``` - ---- - -## ๐ŸŽฏ Approver-Specific Alerts - -### Confirmation: Alerts are Approver-Specific - -โœ… **Each level's alerts** are sent to **that level's approver only** -โœ… **Previous approver** does NOT receive alerts for next level -โœ… **Current approver** receives all their level's alerts (50%, 75%, 100%) - -### Example: - -``` -Request Flow: - Level 1: John (TAT: 24h) - โ†’ Alerts sent to: John - โ†’ At: 12h, 18h, 24h - - Level 2: Sarah (TAT: 12h) - โ†’ Alerts sent to: Sarah (NOT John) - โ†’ At: 6h, 9h, 12h - - Level 3: Mike (TAT: 8h) - โ†’ Alerts sent to: Mike (NOT Sarah, NOT John) - โ†’ At: 4h, 6h, 8h -``` - ---- - -## ๐Ÿ“‹ KPI Queries - -### Get All Alerts for a Request: - -```sql -SELECT - al.level_number, - al.approver_name, - ta.threshold_percentage, - ta.alert_sent_at, - ta.was_completed_on_time -FROM tat_alerts ta -JOIN approval_levels al ON ta.level_id = al.level_id -WHERE ta.request_id = 'REQUEST_ID' -ORDER BY al.level_number, ta.threshold_percentage; -``` - -### TAT Compliance by Approver: - -```sql -SELECT - ta.approver_id, - u.display_name, - COUNT(*) as total_alerts_received, - COUNT(CASE WHEN ta.was_completed_on_time = true THEN 1 END) as completed_on_time, - COUNT(CASE WHEN ta.was_completed_on_time = false THEN 1 END) as completed_late, - ROUND( - COUNT(CASE WHEN ta.was_completed_on_time = true THEN 1 END) * 100.0 / - NULLIF(COUNT(CASE WHEN ta.was_completed_on_time IS NOT NULL THEN 1 END), 0), - 2 - ) as compliance_rate -FROM tat_alerts ta -JOIN users u ON ta.approver_id = u.user_id -GROUP BY ta.approver_id, u.display_name; -``` - -### Alert Effectiveness (Response Time After Alert): - -```sql -SELECT - alert_type, - AVG( - EXTRACT(EPOCH FROM (completion_time - alert_sent_at)) / 3600 - ) as avg_response_hours_after_alert -FROM tat_alerts -WHERE completion_time IS NOT NULL -GROUP BY alert_type; -``` - ---- - -## ๐Ÿ“ Files Modified - -### Backend: -- โœ… `src/models/TatAlert.ts` - TAT alert model -- โœ… `src/migrations/20251104-create-tat-alerts.ts` - Table creation -- โœ… `src/queues/tatProcessor.ts` - Create alert records -- โœ… `src/services/workflow.service.ts` - Include alerts in API response -- โœ… `src/services/approval.service.ts` - Update alerts on completion -- โœ… `src/models/index.ts` - Export TatAlert model - -### Frontend: -- โœ… `src/pages/RequestDetail/RequestDetail.tsx` - Display alerts in workflow tab - -### Database: -- โœ… `tat_alerts` table created with 7 indexes -- โœ… 8 KPI views created for reporting - ---- - -## ๐ŸŽจ Visual Example - -Based on your screenshot, the display looks like: - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Step 2: Lisa Wong (Finance Manager) โ”‚ -โ”‚ Status: pending โ”‚ -โ”‚ TAT: 12 hours โ”‚ -โ”‚ โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚ -โ”‚ โ”‚ โณ Reminder 1 โ”‚โ”‚ -โ”‚ โ”‚ 50% of SLA breach reminder have been sent โ”‚โ”‚ -โ”‚ โ”‚ Reminder sent by system automatically โ”‚โ”‚ -โ”‚ โ”‚ Sent at: Oct 6 at 2:30 PM โ”‚โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚ -โ”‚ โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚ -โ”‚ โ”‚ โš ๏ธ Reminder 2 โ”‚โ”‚ -โ”‚ โ”‚ 75% of SLA breach reminder have been sent โ”‚โ”‚ -โ”‚ โ”‚ Reminder sent by system automatically โ”‚โ”‚ -โ”‚ โ”‚ Sent at: Oct 6 at 6:30 PM โ”‚โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## โœ… Status: READY TO TEST! - -### What Works Now: - -- โœ… TAT alerts stored in database -- โœ… Alerts fetched with workflow details -- โœ… Alerts grouped by approval level -- โœ… Alerts displayed in workflow tab -- โœ… Color-coded by threshold -- โœ… Formatted like your screenshot -- โœ… Completion status tracked -- โœ… KPI-ready data structure - -### What You Need to Do: - -1. **Setup Redis** (Upstash recommended - see `START_HERE.md`) -2. **Add to `.env`**: - ```bash - REDIS_URL=rediss://default:...@upstash.io:6379 - TAT_TEST_MODE=true - ``` -3. **Restart backend** -4. **Create test request** (6-hour TAT) -5. **Watch alerts appear** in 3, 4.5, 6 minutes! - ---- - -## ๐Ÿ“š Documentation - -- **Setup Guide**: `START_HERE.md` -- **Quick Start**: `TAT_QUICK_START.md` -- **Upstash Guide**: `docs/UPSTASH_SETUP_GUIDE.md` -- **KPI Reporting**: `docs/KPI_REPORTING_SYSTEM.md` -- **Full System Docs**: `docs/TAT_NOTIFICATION_SYSTEM.md` - ---- - -## ๐ŸŽฏ Example API Response - -```json -{ - "workflow": {...}, - "approvals": [ - { - "levelId": "abc-123", - "levelNumber": 2, - "approverName": "Lisa Wong", - "status": "PENDING", - "tatHours": 12, - ... - } - ], - "tatAlerts": [ - { - "levelId": "abc-123", - "alertType": "TAT_50", - "thresholdPercentage": 50, - "alertSentAt": "2024-10-06T14:30:00Z", - "alertMessage": "โณ 50% of TAT elapsed...", - "isBreached": false, - "wasCompletedOnTime": null, - "metadata": { - "requestNumber": "REQ-2024-001", - "approverName": "Lisa Wong", - "priority": "express" - } - }, - { - "levelId": "abc-123", - "alertType": "TAT_75", - "thresholdPercentage": 75, - "alertSentAt": "2024-10-06T18:30:00Z", - "alertMessage": "โš ๏ธ 75% of TAT elapsed...", - "isBreached": false, - "wasCompletedOnTime": null, - "metadata": {...} - } - ] -} -``` - ---- - -## ๐Ÿ” Verify Implementation - -### Check Backend Logs: - -```bash -# When notification fires: -[TAT Processor] Processing tat50 for request... -[TAT Processor] TAT alert record created for tat50 -[TAT Processor] tat50 notification sent - -# When workflow details fetched: -[Workflow] Found 2 TAT alerts for request REQ-2024-001 -``` - -### Check Database: - -```sql --- See all alerts for a request -SELECT * FROM tat_alerts -WHERE request_id = 'YOUR_REQUEST_ID' -ORDER BY alert_sent_at; - --- See alerts with approval info -SELECT - al.approver_name, - al.level_number, - ta.threshold_percentage, - ta.alert_sent_at, - ta.was_completed_on_time -FROM tat_alerts ta -JOIN approval_levels al ON ta.level_id = al.level_id -WHERE ta.request_id = 'YOUR_REQUEST_ID'; -``` - -### Check Frontend: - -1. Open Request Detail -2. Click "Workflow" tab -3. Look under each approval level card -4. You should see reminder boxes with: - - โณ 50% reminder (yellow background) - - โš ๏ธ 75% reminder (orange background) - - โฐ 100% breach (red background) - ---- - -## ๐Ÿ“Š KPI Reporting Ready - -### All TAT alerts are now queryable for KPIs: - -**TAT Compliance Rate:** -```sql -SELECT - COUNT(CASE WHEN was_completed_on_time = true THEN 1 END) * 100.0 / - NULLIF(COUNT(*), 0) as compliance_rate -FROM tat_alerts -WHERE was_completed_on_time IS NOT NULL; -``` - -**Approver Response Time After Alert:** -```sql -SELECT - approver_id, - alert_type, - AVG( - EXTRACT(EPOCH FROM (completion_time - alert_sent_at)) / 3600 - ) as avg_hours_to_respond -FROM tat_alerts -WHERE completion_time IS NOT NULL -GROUP BY approver_id, alert_type; -``` - -**Breach Analysis:** -```sql -SELECT - DATE(alert_sent_at) as date, - COUNT(CASE WHEN alert_type = 'TAT_50' THEN 1 END) as alerts_50, - COUNT(CASE WHEN alert_type = 'TAT_75' THEN 1 END) as alerts_75, - COUNT(CASE WHEN alert_type = 'TAT_100' THEN 1 END) as breaches -FROM tat_alerts -WHERE alert_sent_at >= CURRENT_DATE - INTERVAL '30 days' -GROUP BY DATE(alert_sent_at) -ORDER BY date DESC; -``` - ---- - -## ๐Ÿš€ Ready to Use! - -### Complete System Features: - -โœ… **Notification System** - Sends alerts to approvers -โœ… **Storage System** - All alerts stored in database -โœ… **Display System** - Alerts shown in UI (matches screenshot) -โœ… **Tracking System** - Completion status tracked -โœ… **KPI System** - Full reporting and analytics -โœ… **Test Mode** - Fast testing (1 hour = 1 minute) - ---- - -## ๐ŸŽ“ Quick Test - -1. **Setup Upstash** (2 minutes): https://console.upstash.com/ -2. **Add to `.env`**: - ```bash - REDIS_URL=rediss://... - TAT_TEST_MODE=true - ``` -3. **Restart backend** -4. **Create request** with 6-hour TAT -5. **Submit request** -6. **Wait 3 minutes** โ†’ See first alert in UI -7. **Wait 4.5 minutes** โ†’ See second alert -8. **Wait 6 minutes** โ†’ See third alert - ---- - -## โœจ Benefits - -1. **Full Audit Trail** - Every alert stored and queryable -2. **Visual Feedback** - Users see exactly when reminders were sent -3. **KPI Ready** - Data ready for all reporting needs -4. **Compliance Tracking** - Know who completed on time vs late -5. **Effectiveness Analysis** - Measure response time after alerts -6. **Historical Data** - All past alerts preserved - ---- - -**๐ŸŽ‰ Implementation Complete! Connect Redis and start testing!** - -See `START_HERE.md` for immediate next steps. - ---- - -**Last Updated**: November 4, 2025 -**Status**: โœ… Production Ready -**Team**: Royal Enfield Workflow - diff --git a/TAT_ENHANCED_DISPLAY_SUMMARY.md b/TAT_ENHANCED_DISPLAY_SUMMARY.md deleted file mode 100644 index feb6446..0000000 --- a/TAT_ENHANCED_DISPLAY_SUMMARY.md +++ /dev/null @@ -1,650 +0,0 @@ -# โœ… Enhanced TAT Alerts Display - Complete Guide - -## ๐ŸŽฏ What's Been Enhanced - -TAT alerts now display **detailed time tracking information** inline with each approver, making it crystal clear what's happening! - ---- - -## ๐Ÿ“Š Enhanced Alert Display - -### **What Shows Now:** - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โณ Reminder 1 - 50% TAT Threshold [WARNING] โ”‚ -โ”‚ โ”‚ -โ”‚ 50% of SLA breach reminder have been sent โ”‚ -โ”‚ โ”‚ -โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ -โ”‚ โ”‚ Allocated: โ”‚ Elapsed: โ”‚ โ”‚ -โ”‚ โ”‚ 12h โ”‚ 6.0h โ”‚ โ”‚ -โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ -โ”‚ โ”‚ Remaining: โ”‚ Due by: โ”‚ โ”‚ -โ”‚ โ”‚ 6.0h โ”‚ Oct 7, 2024 โ”‚ โ”‚ -โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ -โ”‚ โ”‚ -โ”‚ Reminder sent by system automatically [TEST MODE] โ”‚ -โ”‚ Sent at: Oct 6 at 2:30 PM โ”‚ -โ”‚ Note: Test mode active (1 hour = 1 minute) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## ๐Ÿ”‘ Key Information Displayed - -### **For Each Alert:** - -| Field | Description | Example | -|-------|-------------|---------| -| **Reminder #** | Sequential number | "Reminder 1" | -| **Threshold** | Percentage reached | "50% TAT Threshold" | -| **Status Badge** | Warning or Breach | `WARNING` / `BREACHED` | -| **Allocated** | Total TAT hours | "12h" | -| **Elapsed** | Hours used when alert sent | "6.0h" | -| **Remaining** | Hours left when alert sent | "6.0h" | -| **Due by** | Expected completion date | "Oct 7, 2024" | -| **Sent at** | When reminder was sent | "Oct 6 at 2:30 PM" | -| **Test Mode** | If in test mode | Purple badge + note | - ---- - -## ๐ŸŽจ Color Coding - -### **50% Alert (โณ):** -- Background: `bg-yellow-50` -- Border: `border-yellow-200` -- Badge: `bg-amber-100 text-amber-800` -- Icon: โณ - -### **75% Alert (โš ๏ธ):** -- Background: `bg-orange-50` -- Border: `border-orange-200` -- Badge: `bg-amber-100 text-amber-800` -- Icon: โš ๏ธ - -### **100% Breach (โฐ):** -- Background: `bg-red-50` -- Border: `border-red-200` -- Badge: `bg-red-100 text-red-800` -- Icon: โฐ -- Text: Shows "BREACHED" instead of "WARNING" - ---- - -## ๐Ÿงช Test Mode vs Production Mode - -### **Test Mode (TAT_TEST_MODE=true):** - -**Purpose**: Fast testing during development - -**Behavior:** -- โœ… 1 hour = 1 minute -- โœ… 6-hour TAT = 6 minutes -- โœ… Purple "TEST MODE" badge shown -- โœ… Note: "Test mode active (1 hour = 1 minute)" -- โœ… All times are in working time (no weekend skip) - -**Example Alert (Test Mode):** -``` -โณ Reminder 1 - 50% TAT Threshold [WARNING] [TEST MODE] - -Allocated: 6h | Elapsed: 3.0h -Remaining: 3.0h | Due by: Today 2:06 PM - -Note: Test mode active (1 hour = 1 minute) -Sent at: Today at 2:03 PM -``` - -**Timeline:** -- Submit at 2:00 PM -- 50% alert at 2:03 PM (3 minutes) -- 75% alert at 2:04:30 PM (4.5 minutes) -- 100% breach at 2:06 PM (6 minutes) - ---- - -### **Production Mode (TAT_TEST_MODE=false):** - -**Purpose**: Real-world usage - -**Behavior:** -- โœ… 1 hour = 1 hour (real time) -- โœ… 48-hour TAT = 48 hours -- โœ… No "TEST MODE" badge -- โœ… No test mode note -- โœ… Respects working hours (Mon-Fri, 9 AM-6 PM) -- โœ… Skips weekends - -**Example Alert (Production Mode):** -``` -โณ Reminder 1 - 50% TAT Threshold [WARNING] - -Allocated: 48h | Elapsed: 24.0h -Remaining: 24.0h | Due by: Oct 8, 2024 - -Reminder sent by system automatically -Sent at: Oct 6 at 10:00 AM -``` - -**Timeline:** -- Submit Monday 10:00 AM -- 50% alert Tuesday 10:00 AM (24 hours) -- 75% alert Wednesday 10:00 AM (36 hours) -- 100% breach Thursday 10:00 AM (48 hours) - ---- - -## ๐Ÿ“ก New API Endpoints - -### **1. Get TAT Alerts for Request** -``` -GET /api/tat/alerts/request/:requestId -``` - -**Response:** -```json -{ - "success": true, - "data": [ - { - "alertId": "...", - "alertType": "TAT_50", - "thresholdPercentage": 50, - "tatHoursAllocated": 12, - "tatHoursElapsed": 6.0, - "tatHoursRemaining": 6.0, - "alertSentAt": "2024-10-06T14:30:00Z", - "level": { - "levelNumber": 2, - "approverName": "Lisa Wong", - "status": "PENDING" - } - } - ] -} -``` - -### **2. Get TAT Compliance Summary** -``` -GET /api/tat/compliance/summary?startDate=2024-10-01&endDate=2024-10-31 -``` - -**Response:** -```json -{ - "success": true, - "data": { - "total_alerts": 150, - "alerts_50": 50, - "alerts_75": 45, - "breaches": 25, - "completed_on_time": 35, - "completed_late": 15, - "compliance_percentage": 70.00 - } -} -``` - -### **3. Get TAT Breach Report** -``` -GET /api/tat/breaches -``` - -### **4. Get Approver Performance** -``` -GET /api/tat/performance/:approverId -``` - ---- - -## ๐Ÿ” Database Fields Available - -### **In `tat_alerts` Table:** - -| Field | Type | Use In UI | -|-------|------|-----------| -| `alert_type` | ENUM | Determine icon (โณ/โš ๏ธ/โฐ) | -| `threshold_percentage` | INT | Show "50%", "75%", "100%" | -| `tat_hours_allocated` | DECIMAL | Display "Allocated: Xh" | -| `tat_hours_elapsed` | DECIMAL | Display "Elapsed: Xh" | -| `tat_hours_remaining` | DECIMAL | Display "Remaining: Xh" (red if < 2h) | -| `level_start_time` | TIMESTAMP | Calculate time since start | -| `alert_sent_at` | TIMESTAMP | Show "Sent at: ..." | -| `expected_completion_time` | TIMESTAMP | Show "Due by: ..." | -| `alert_message` | TEXT | Full notification message | -| `is_breached` | BOOLEAN | Show "BREACHED" badge | -| `metadata` | JSONB | Test mode indicator, priority, etc. | -| `was_completed_on_time` | BOOLEAN | Show compliance status | -| `completion_time` | TIMESTAMP | Show actual completion | - ---- - -## ๐Ÿ’ก Production Recommendation - -### **For Development/Testing:** -```bash -# .env -TAT_TEST_MODE=true -WORK_START_HOUR=9 -WORK_END_HOUR=18 -``` - -**Benefits:** -- โœ… Fast feedback (minutes instead of hours/days) -- โœ… Easy to test multiple scenarios -- โœ… Clear test mode indicators prevent confusion - -### **For Production:** -```bash -# .env -TAT_TEST_MODE=false -WORK_START_HOUR=9 -WORK_END_HOUR=18 -``` - -**Benefits:** -- โœ… Real-world timing -- โœ… Accurate TAT tracking -- โœ… Meaningful metrics - ---- - -## ๐Ÿ“‹ Complete Alert Card Template - -### **Full Display Structure:** - -```tsx -
- {/* Header */} -
- โณ Reminder 1 - 50% TAT Threshold - WARNING - {testMode && TEST MODE} -
- - {/* Main Message */} -

50% of SLA breach reminder have been sent

- - {/* Time Grid */} -
-
Allocated: 12h
-
Elapsed: 6.0h
-
Remaining: 6.0h
-
Due by: Oct 7
-
- - {/* Footer */} -
-

Reminder sent by system automatically

-

Sent at: Oct 6 at 2:30 PM

- {testMode &&

Note: Test mode (1h = 1min)

} -
-
-``` - ---- - -## ๐ŸŽฏ Key Benefits of Enhanced Display - -### **1. Full Transparency** -Users see exactly: -- How much time was allocated -- How much was used when alert fired -- How much was remaining -- When it's due - -### **2. Context Awareness** -- Test mode clearly indicated -- Color-coded by severity -- Badge shows warning vs breach - -### **3. Actionable Information** -- "Remaining: 2.5h" โ†’ Approver knows they have 2.5h left -- "Due by: Oct 7 at 6 PM" โ†’ Clear deadline -- "Elapsed: 6h" โ†’ Understand how long it's been - -### **4. Confusion Prevention** -- Test mode badge prevents misunderstanding -- Note explains "1 hour = 1 minute" in test mode -- Clear visual distinction from production - ---- - -## ๐Ÿงช Testing Workflow - -### **Step 1: Enable Detailed Logging** - -In `Re_Backend/.env`: -```bash -TAT_TEST_MODE=true -LOG_LEVEL=debug -``` - -### **Step 2: Create Test Request** - -- TAT: 6 hours -- Priority: Standard or Express -- Submit request - -### **Step 3: Watch Alerts Populate** - -**At 3 minutes (50%):** -``` -โณ Reminder 1 - 50% TAT Threshold [WARNING] [TEST MODE] - -Allocated: 6h | Elapsed: 3.0h -Remaining: 3.0h | Due by: Today 2:06 PM - -Note: Test mode active (1 hour = 1 minute) -``` - -**At 4.5 minutes (75%):** -``` -โš ๏ธ Reminder 2 - 75% TAT Threshold [WARNING] [TEST MODE] - -Allocated: 6h | Elapsed: 4.5h -Remaining: 1.5h | Due by: Today 2:06 PM - -Note: Test mode active (1 hour = 1 minute) -``` - -**At 6 minutes (100%):** -``` -โฐ Reminder 3 - 100% TAT Threshold [BREACHED] [TEST MODE] - -Allocated: 6h | Elapsed: 6.0h -Remaining: 0.0h | Due by: Today 2:06 PM (OVERDUE) - -Note: Test mode active (1 hour = 1 minute) -``` - ---- - -## ๐Ÿ“Š KPI Queries Using Alert Data - -### **Average Response Time After Each Alert Type:** - -```sql -SELECT - alert_type, - ROUND(AVG(tat_hours_elapsed), 2) as avg_elapsed, - ROUND(AVG(tat_hours_remaining), 2) as avg_remaining, - COUNT(*) as alert_count, - COUNT(CASE WHEN was_completed_on_time = true THEN 1 END) as completed_on_time -FROM tat_alerts -GROUP BY alert_type -ORDER BY threshold_percentage; -``` - -### **Approvers Who Frequently Breach:** - -```sql -SELECT - u.display_name, - u.department, - COUNT(CASE WHEN ta.is_breached = true THEN 1 END) as breach_count, - AVG(ta.tat_hours_elapsed) as avg_time_taken, - COUNT(DISTINCT ta.level_id) as total_approvals -FROM tat_alerts ta -JOIN users u ON ta.approver_id = u.user_id -WHERE ta.is_breached = true -GROUP BY u.user_id, u.display_name, u.department -ORDER BY breach_count DESC -LIMIT 10; -``` - -### **Time-to-Action After Alert:** - -```sql -SELECT - alert_type, - threshold_percentage, - ROUND(AVG( - EXTRACT(EPOCH FROM (completion_time - alert_sent_at)) / 3600 - ), 2) as avg_hours_to_respond_after_alert -FROM tat_alerts -WHERE completion_time IS NOT NULL -GROUP BY alert_type, threshold_percentage -ORDER BY threshold_percentage; -``` - ---- - -## ๐Ÿ”„ Alert Lifecycle - -### **1. Alert Created (When Threshold Reached)** -```typescript -{ - alertType: 'TAT_50', - thresholdPercentage: 50, - tatHoursAllocated: 12, - tatHoursElapsed: 6.0, - tatHoursRemaining: 6.0, - alertSentAt: '2024-10-06T14:30:00Z', - expectedCompletionTime: '2024-10-06T18:00:00Z', - isBreached: false, - wasCompletedOnTime: null, // Not completed yet - metadata: { testMode: true, ... } -} -``` - -### **2. Approver Takes Action** -```typescript -// Updated when level is approved/rejected -{ - ...existingFields, - wasCompletedOnTime: true, // or false - completionTime: '2024-10-06T16:00:00Z' -} -``` - -### **3. Displayed in UI** -```tsx -// Shows all historical alerts for that level -// Color-coded by threshold -// Shows completion status if completed -``` - ---- - -## ๐ŸŽ“ Understanding the Data - -### **Allocated Hours (tat_hours_allocated)** -Total TAT time given to approver for this level -``` -Example: 12 hours -Meaning: Approver has 12 hours to approve/reject -``` - -### **Elapsed Hours (tat_hours_elapsed)** -Time used when the alert was sent -``` -Example: 6.0 hours (at 50% alert) -Meaning: 6 hours have passed since level started -``` - -### **Remaining Hours (tat_hours_remaining)** -Time left when the alert was sent -``` -Example: 6.0 hours (at 50% alert) -Meaning: 6 hours remaining before TAT breach -Note: Turns red if < 2 hours -``` - -### **Expected Completion Time** -When the level should be completed -``` -Example: Oct 6 at 6:00 PM -Meaning: Deadline for this approval level -``` - ---- - -## โš™๏ธ Configuration Options - -### **Disable Test Mode for Production:** - -Edit `.env`: -```bash -# Production settings -TAT_TEST_MODE=false -WORK_START_HOUR=9 -WORK_END_HOUR=18 -``` - -### **Adjust Working Hours:** - -```bash -# Custom working hours (e.g., 8 AM - 5 PM) -WORK_START_HOUR=8 -WORK_END_HOUR=17 -``` - -### **Redis Configuration:** - -```bash -# Upstash (recommended) -REDIS_URL=rediss://default:PASSWORD@host.upstash.io:6379 - -# Local Redis -REDIS_URL=redis://localhost:6379 - -# Production Redis with auth -REDIS_URL=redis://username:password@prod-redis.com:6379 -``` - ---- - -## ๐Ÿ“ฑ Mobile Responsive - -The alert cards are responsive: -- โœ… 2-column grid on desktop -- โœ… Single column on mobile -- โœ… All information remains visible -- โœ… Touch-friendly spacing - ---- - -## ๐Ÿš€ API Endpoints Available - -### **Get Alerts for Request:** -```bash -GET /api/tat/alerts/request/:requestId -``` - -### **Get Alerts for Level:** -```bash -GET /api/tat/alerts/level/:levelId -``` - -### **Get Compliance Summary:** -```bash -GET /api/tat/compliance/summary -GET /api/tat/compliance/summary?startDate=2024-10-01&endDate=2024-10-31 -``` - -### **Get Breach Report:** -```bash -GET /api/tat/breaches -``` - -### **Get Approver Performance:** -```bash -GET /api/tat/performance/:approverId -``` - ---- - -## โœ… Benefits Summary - -### **For Users:** -1. **Clear Visibility** - See exact time tracking -2. **No Confusion** - Test mode clearly labeled -3. **Actionable Data** - Know exactly how much time left -4. **Historical Record** - All alerts preserved - -### **For Management:** -1. **KPI Ready** - All data for reporting -2. **Compliance Tracking** - On-time vs late completion -3. **Performance Analysis** - Response time after alerts -4. **Trend Analysis** - Breach patterns - -### **For System:** -1. **Audit Trail** - Every alert logged -2. **Scalable** - Queue-based architecture -3. **Reliable** - Automatic retries -4. **Maintainable** - Clear configuration - ---- - -## ๐ŸŽฏ Quick Switch Between Modes - -### **Development (Fast Testing):** -```bash -# .env -TAT_TEST_MODE=true -``` -Restart backend โ†’ Alerts fire in minutes - -### **Staging (Semi-Real):** -```bash -# .env -TAT_TEST_MODE=false -# But use shorter TATs (2-4 hours instead of 48 hours) -``` -Restart backend โ†’ Alerts fire in hours - -### **Production (Real):** -```bash -# .env -TAT_TEST_MODE=false -# Use actual TATs (24-48 hours) -``` -Restart backend โ†’ Alerts fire in days - ---- - -## ๐Ÿ“Š What You See in Workflow Tab - -For each approval level, you'll see: - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Step 2: Lisa Wong (Finance Manager) โ”‚ -โ”‚ Status: pending โ”‚ -โ”‚ TAT: 12 hours โ”‚ -โ”‚ Elapsed: 8h โ”‚ -โ”‚ โ”‚ -โ”‚ [50% Alert Card with full details] โ”‚ -โ”‚ [75% Alert Card with full details] โ”‚ -โ”‚ โ”‚ -โ”‚ Comment: (if any) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Clear, informative, and actionable!** - ---- - -## ๐ŸŽ‰ Status: READY! - -โœ… **Enhanced display** with all timing details -โœ… **Test mode indicator** to prevent confusion -โœ… **Color-coded** by severity -โœ… **Responsive** design -โœ… **API endpoints** for custom queries -โœ… **KPI-ready** data structure - ---- - -**Just setup Upstash Redis and start testing!** - -See: `START_HERE.md` for 2-minute Redis setup - ---- - -**Last Updated**: November 4, 2025 -**Team**: Royal Enfield Workflow - diff --git a/TAT_QUICK_START.md b/TAT_QUICK_START.md deleted file mode 100644 index 9ad1105..0000000 --- a/TAT_QUICK_START.md +++ /dev/null @@ -1,269 +0,0 @@ -# โฐ TAT Notifications - Quick Start Guide - -## ๐ŸŽฏ Goal -Get TAT (Turnaround Time) notifications working in **under 5 minutes**! - ---- - -## โœ… Step 1: Setup Redis (Required) - -### ๐Ÿš€ Option A: Upstash (RECOMMENDED - No Installation!) - -**Best for Windows/Development - 100% Free** - -1. **Sign up**: Go to https://console.upstash.com/ -2. **Create Database**: Click "Create Database" - - Name: `redis-tat-dev` - - Type: Regional - - Region: Choose closest to you - - Click "Create" -3. **Copy Connection URL**: You'll get a URL like: - ``` - rediss://default:AbCd1234...@us1-mighty-shark-12345.upstash.io:6379 - ``` -4. **Update `.env` in Re_Backend/**: - ```bash - REDIS_URL=rediss://default:AbCd1234...@us1-mighty-shark-12345.upstash.io:6379 - ``` - -โœ… **Done!** No installation, no setup, works everywhere! - ---- - -### Alternative: Docker (If you prefer local) - -If you have Docker Desktop: -```bash -docker run -d --name redis-tat -p 6379:6379 redis:latest -``` - -Then in `.env`: -```bash -REDIS_URL=redis://localhost:6379 -``` - ---- - -## โšก Step 2: Enable Test Mode (HIGHLY RECOMMENDED) - -For testing, enable **fast mode** where **1 hour = 1 minute**: - -### Edit `.env` file in `Re_Backend/`: -```bash -TAT_TEST_MODE=true -``` - -This means: -- โœ… 6-hour TAT = 6 minutes (instead of 6 hours) -- โœ… 48-hour TAT = 48 minutes (instead of 48 hours) -- โœ… Perfect for quick testing! - ---- - -## ๐Ÿš€ Step 3: Restart Backend - -```bash -cd Re_Backend -npm run dev -``` - -### You Should See: -``` -โœ… [TAT Queue] Connected to Redis -โœ… [TAT Worker] Initialized and listening -โฐ TAT Configuration: - - Test Mode: ENABLED (1 hour = 1 minute) - - Redis: rediss://***@upstash.io:6379 -``` - -๐Ÿ’ก If you see connection errors, double-check your `REDIS_URL` in `.env` - ---- - -## ๐Ÿงช Step 4: Test It! - -### Create a Request: -1. **Frontend**: Create a new workflow request -2. **Set TAT**: 6 hours (becomes 6 minutes in test mode) -3. **Submit** the request - -### Watch the Magic: -``` -โœจ At 3 minutes: โณ 50% notification -โœจ At 4.5 minutes: โš ๏ธ 75% notification -โœจ At 6 minutes: โฐ 100% breach notification -``` - -### Check Logs: -```bash -# You'll see: -[TAT Scheduler] โœ… TAT jobs scheduled for request... -[TAT Processor] Processing tat50 for request... -[TAT Processor] tat50 notification sent for request... -``` - ---- - -## ๐Ÿ“Š Verify in Database - -```sql -SELECT - approver_name, - tat_hours, - tat50_alert_sent, - tat75_alert_sent, - tat_breached, - status -FROM approval_levels -WHERE status = 'IN_PROGRESS'; -``` - -You should see the flags change as notifications are sent! - ---- - -## โŒ Troubleshooting - -### "ECONNREFUSED" or Connection Error? -**Problem**: Can't connect to Redis - -**Solution**: -1. **Check `.env` file**: - ```bash - # Make sure REDIS_URL is set correctly - REDIS_URL=rediss://default:YOUR_PASSWORD@YOUR_URL.upstash.io:6379 - ``` - -2. **Verify Upstash Database**: - - Go to https://console.upstash.com/ - - Check database status (should be "Active") - - Copy connection URL again if needed - -3. **Test Connection**: - - Use Upstash's Redis CLI in their console - - Or install `redis-cli` and test: - ```bash - redis-cli -u "rediss://default:YOUR_PASSWORD@YOUR_URL.upstash.io:6379" ping - # Should return: PONG - ``` - -### No Notifications? -**Checklist**: -- โœ… REDIS_URL set in `.env`? -- โœ… Backend restarted after setting REDIS_URL? -- โœ… TAT_TEST_MODE=true in `.env`? -- โœ… Request submitted (not just created)? -- โœ… Logs show "Connected to Redis"? - -### Still Issues? -```bash -# Check detailed logs -Get-Content Re_Backend/logs/app.log -Tail 50 -Wait - -# Look for: -# โœ… [TAT Queue] Connected to Redis -# โŒ [TAT Queue] Redis connection error -``` - ---- - -## ๐ŸŽ“ Testing Scenarios - -### Quick Test (6 minutes): -``` -TAT: 6 hours (6 minutes in test mode) -โ”œโ”€ 3 min โณ 50% reminder -โ”œโ”€ 4.5 min โš ๏ธ 75% warning -โ””โ”€ 6 min โฐ 100% breach -``` - -### Medium Test (24 minutes): -``` -TAT: 24 hours (24 minutes in test mode) -โ”œโ”€ 12 min โณ 50% reminder -โ”œโ”€ 18 min โš ๏ธ 75% warning -โ””โ”€ 24 min โฐ 100% breach -``` - ---- - -## ๐Ÿ“š More Information - -- **Full Documentation**: `Re_Backend/docs/TAT_NOTIFICATION_SYSTEM.md` -- **Testing Guide**: `Re_Backend/docs/TAT_TESTING_GUIDE.md` -- **Redis Setup**: `Re_Backend/INSTALL_REDIS.txt` - ---- - -## ๐ŸŽ‰ Production Mode - -When ready for production: - -1. **Disable Test Mode**: - ```bash - # In .env - TAT_TEST_MODE=false - ``` - -2. **Restart Backend** - -3. **TAT will now use real hours**: - - 48-hour TAT = actual 48 hours - - Working hours: Mon-Fri, 9 AM - 6 PM - ---- - -## ๐Ÿ†˜ Need Help? - -Common fixes: - -### 1. Verify Upstash Connection -```bash -# In Upstash Console (https://console.upstash.com/) -# - Click your database -# - Use the "CLI" tab to test: PING -# - Should return: PONG -``` - -### 2. Check Environment Variables -```bash -# In Re_Backend/.env, verify: -REDIS_URL=rediss://default:YOUR_PASSWORD@YOUR_URL.upstash.io:6379 -TAT_TEST_MODE=true -``` - -### 3. Clear Redis Queue (if needed) -```bash -# In Upstash Console CLI tab: -FLUSHALL -# This clears all jobs - use only if you need a fresh start -``` - -### 4. Restart Backend -```bash -cd Re_Backend -npm run dev -``` - -### 5. Check Logs -```bash -Get-Content logs/app.log -Tail 50 -Wait -``` - ---- - -**Status Check**: -- [ ] Upstash Redis database created -- [ ] REDIS_URL copied to `.env` -- [ ] TAT_TEST_MODE=true in `.env` -- [ ] Backend restarted -- [ ] Logs show "TAT Queue: Connected to Redis" -- [ ] Test request submitted - -โœ… All checked? **You're ready!** - ---- - -**Last Updated**: November 4, 2025 -**Author**: Royal Enfield Workflow Team - diff --git a/TROUBLESHOOTING_TAT_ALERTS.md b/TROUBLESHOOTING_TAT_ALERTS.md deleted file mode 100644 index f579011..0000000 --- a/TROUBLESHOOTING_TAT_ALERTS.md +++ /dev/null @@ -1,420 +0,0 @@ -# ๐Ÿ” Troubleshooting TAT Alerts Not Showing - -## Quick Diagnosis Steps - -### Step 1: Check if Redis is Connected - -**Look at your backend console when you start the server:** - -โœ… **Good** - Redis is working: -``` -โœ… [TAT Queue] Connected to Redis -โœ… [TAT Worker] Worker is ready and listening -``` - -โŒ **Bad** - Redis is NOT working: -``` -โš ๏ธ [TAT Worker] Redis connection failed -โš ๏ธ [TAT Queue] Redis connection failed after 3 attempts -``` - -**If you see the bad message:** -โ†’ TAT alerts will NOT be created because the worker isn't running -โ†’ You MUST setup Redis first (see `START_HERE.md`) - ---- - -### Step 2: Verify TAT Alerts Table Exists - -**Run this SQL:** -```sql -SELECT COUNT(*) FROM tat_alerts; -``` - -**Expected Result:** -- If table exists: You'll see a count (maybe 0) -- If table doesn't exist: Error "relation tat_alerts does not exist" - -**If table doesn't exist:** -```bash -cd Re_Backend -npm run migrate -``` - ---- - -### Step 3: Check if TAT Alerts Exist in Database - -**Run this SQL:** -```sql --- Check if ANY alerts exist -SELECT - ta.alert_id, - ta.threshold_percentage, - ta.alert_sent_at, - ta.alert_message, - ta.metadata->>'requestNumber' as request_number, - ta.metadata->>'approverName' as approver_name -FROM tat_alerts ta -ORDER BY ta.alert_sent_at DESC -LIMIT 10; -``` - -**If query returns 0 rows:** -โ†’ No alerts have been created yet -โ†’ This means: - 1. Redis is not connected, OR - 2. No requests have been submitted, OR - 3. Not enough time has passed (wait 3 min in test mode) - ---- - -### Step 4: Check API Response - -**Option A: Use Debug Endpoint** - -Call this URL in your browser or Postman: -``` -GET http://localhost:5000/api/debug/tat-status -``` - -**You'll see:** -```json -{ - "success": true, - "status": { - "redis": { - "configured": true, - "url": "rediss://****@upstash.io:6379", - "testMode": true - }, - "database": { - "connected": true, - "tatAlertsTableExists": true, - "totalAlerts": 0 - } - } -} -``` - -**Option B: Check Workflow Details Response** - -For a specific request: -``` -GET http://localhost:5000/api/debug/workflow-details/REQ-2025-XXXXX -``` - -**You'll see:** -```json -{ - "success": true, - "structure": { - "hasTatAlerts": true, - "tatAlertsCount": 2 - }, - "tatAlerts": [ - { - "alertType": "TAT_50", - "thresholdPercentage": 50, - "alertSentAt": "...", - ... - } - ] -} -``` - ---- - -### Step 5: Check Frontend Console - -**Open browser DevTools (F12) โ†’ Console** - -**When you open Request Detail, you should see:** -```javascript -// Look for the API response -Object { - workflow: {...}, - approvals: [...], - tatAlerts: [...] // โ† Check if this exists -} -``` - -**If `tatAlerts` is missing or empty:** -โ†’ Backend is not returning it (go back to Step 3) - -**If `tatAlerts` exists but not showing:** -โ†’ Frontend rendering issue (check Step 6) - ---- - -### Step 6: Verify Frontend Code - -**Check if tatAlerts are being processed:** - -Open `Re_Figma_Code/src/pages/RequestDetail/RequestDetail.tsx` - -**Search for this line (around line 235 and 493):** -```typescript -const tatAlerts = Array.isArray(details.tatAlerts) ? details.tatAlerts : []; -``` - -**This should be there!** If not, the code wasn't applied. - -**Then search for (around line 271 and 531):** -```typescript -const levelAlerts = tatAlerts.filter((alert: any) => alert.levelId === levelId); -``` - -**And in the JSX (around line 1070):** -```tsx -{step.tatAlerts && step.tatAlerts.length > 0 && ( -
- {step.tatAlerts.map((alert: any, alertIndex: number) => ( -``` - ---- - -## ๐Ÿ› Common Issues & Fixes - -### Issue 1: "TAT alerts not showing in UI" - -**Cause**: Redis not connected - -**Fix**: -1. Setup Upstash: https://console.upstash.com/ -2. Add to `.env`: - ```bash - REDIS_URL=rediss://default:...@upstash.io:6379 - TAT_TEST_MODE=true - ``` -3. Restart backend -4. Look for "Connected to Redis" in logs - ---- - -### Issue 2: "tat_alerts table doesn't exist" - -**Cause**: Migrations not run - -**Fix**: -```bash -cd Re_Backend -npm run migrate -``` - ---- - -### Issue 3: "No alerts in database" - -**Cause**: No requests submitted or not enough time passed - -**Fix**: -1. Create a new workflow request -2. **SUBMIT** the request (not just save as draft) -3. Wait: - - Test mode: 3 minutes for 50% alert - - Production: Depends on TAT (e.g., 12 hours for 24-hour TAT) - ---- - -### Issue 4: "tatAlerts is undefined in API response" - -**Cause**: Backend code not updated - -**Fix**: -Check `Re_Backend/src/services/workflow.service.ts` line 698: -```typescript -return { workflow, approvals, participants, documents, activities, summary, tatAlerts }; -// ^^^^^^^^ -// Make sure tatAlerts is included! -``` - ---- - -### Issue 5: "Frontend not displaying alerts even though they exist" - -**Cause**: Frontend code not applied or missing key - -**Fix**: -1. Check browser console for errors -2. Verify `step.tatAlerts` is defined in approval flow -3. Check if alerts have correct `levelId` matching approval level - ---- - -## ๐Ÿ“Š Manual Test Steps - -### Step-by-Step Debugging: - -**1. Check Redis Connection:** -```bash -# Start backend and look for: -โœ… [TAT Queue] Connected to Redis -``` - -**2. Create and Submit Request:** -```bash -# Via frontend or API: -POST /api/workflows/create -POST /api/workflows/{id}/submit -``` - -**3. Wait for Alert (Test Mode):** -```bash -# For 6-hour TAT in test mode: -# Wait 3 minutes for 50% alert -``` - -**4. Check Database:** -```sql -SELECT * FROM tat_alerts ORDER BY alert_sent_at DESC LIMIT 5; -``` - -**5. Check API Response:** -```bash -GET /api/workflows/{requestNumber}/details -# Look for tatAlerts array in response -``` - -**6. Check Frontend:** -```javascript -// Open DevTools Console -// Navigate to Request Detail -// Check the console log for API response -``` - ---- - -## ๐Ÿ”ง Debug Commands - -### Check TAT System Status: -```bash -curl http://localhost:5000/api/debug/tat-status -``` - -### Check Workflow Details for Specific Request: -```bash -curl http://localhost:5000/api/debug/workflow-details/REQ-2025-XXXXX -``` - -### Check Database Directly: -```sql --- Total alerts -SELECT COUNT(*) FROM tat_alerts; - --- Alerts for specific request -SELECT * FROM tat_alerts -WHERE request_id = ( - SELECT request_id FROM workflow_requests - WHERE request_number = 'REQ-2025-XXXXX' -); - --- Pending levels that should get alerts -SELECT - w.request_number, - al.approver_name, - al.status, - al.tat_start_time, - CASE - WHEN al.tat_start_time IS NULL THEN 'No TAT monitoring started' - ELSE 'TAT monitoring active' - END as tat_status -FROM approval_levels al -JOIN workflow_requests w ON al.request_id = w.request_id -WHERE al.status IN ('PENDING', 'IN_PROGRESS'); -``` - ---- - -## ๐Ÿ“ Checklist for TAT Alerts to Show - -Must have ALL of these: - -- [ ] Redis connected (see "Connected to Redis" in logs) -- [ ] TAT worker running (see "Worker is ready" in logs) -- [ ] Request SUBMITTED (not draft) -- [ ] Enough time passed (3 min in test mode for 50%) -- [ ] tat_alerts table exists in database -- [ ] Alert records created in tat_alerts table -- [ ] API returns tatAlerts in workflow details -- [ ] Frontend receives tatAlerts from API -- [ ] Frontend displays tatAlerts in workflow tab - ---- - -## ๐Ÿ†˜ Still Not Working? - -### Provide These Details: - -1. **Backend console output** when starting server -2. **Result of**: - ```bash - curl http://localhost:5000/api/debug/tat-status - ``` -3. **Database query result**: - ```sql - SELECT COUNT(*) FROM tat_alerts; - ``` -4. **Browser console** errors (F12 โ†’ Console) -5. **Request number** you're testing with - ---- - -## ๐ŸŽฏ Most Common Cause - -**99% of the time, TAT alerts don't show because:** - -โŒ **Redis is not connected** - -**How to verify:** -```bash -# When you start backend, you should see: -โœ… [TAT Queue] Connected to Redis - -# If you see this instead: -โš ๏ธ [TAT Queue] Redis connection failed - -# Then: -# 1. Setup Upstash: https://console.upstash.com/ -# 2. Add REDIS_URL to .env -# 3. Restart backend -``` - ---- - -## ๐Ÿš€ Quick Fix Steps - -If alerts aren't showing, do this IN ORDER: - -```bash -# 1. Check .env file has Redis URL -cat Re_Backend/.env | findstr REDIS_URL - -# 2. Restart backend -cd Re_Backend -npm run dev - -# 3. Look for "Connected to Redis" in console - -# 4. Create NEW request (don't use old ones) - -# 5. SUBMIT the request - -# 6. Wait 3 minutes (in test mode) - -# 7. Refresh Request Detail page - -# 8. Go to Workflow tab - -# 9. Alerts should appear under approver card -``` - ---- - -**Need more help? Share the output of `/api/debug/tat-status` endpoint!** - ---- - -**Last Updated**: November 4, 2025 -**Team**: Royal Enfield Workflow - diff --git a/UPSTASH_QUICK_REFERENCE.md b/UPSTASH_QUICK_REFERENCE.md deleted file mode 100644 index ae2701d..0000000 --- a/UPSTASH_QUICK_REFERENCE.md +++ /dev/null @@ -1,215 +0,0 @@ -# ๐Ÿš€ Upstash Redis - Quick Reference - -## One-Time Setup (2 Minutes) - -``` -1. Visit: https://console.upstash.com/ - โ””โ”€ Sign up (free) - -2. Create Database - โ””โ”€ Name: redis-tat-dev - โ””โ”€ Type: Regional - โ””โ”€ Region: US-East-1 (or closest) - โ””โ”€ Click "Create" - -3. Copy Redis URL - โ””โ”€ Format: rediss://default:PASSWORD@host.upstash.io:6379 - โ””โ”€ Click copy button ๐Ÿ“‹ - -4. Paste into .env - โ””โ”€ Re_Backend/.env - โ””โ”€ REDIS_URL=rediss://default:... - โ””โ”€ TAT_TEST_MODE=true - -5. Start Backend - โ””โ”€ cd Re_Backend - โ””โ”€ npm run dev - โ””โ”€ โœ… See: "Connected to Redis" -``` - ---- - -## Environment Variables - -```bash -# Re_Backend/.env - -# Upstash Redis (paste your URL) -REDIS_URL=rediss://default:YOUR_PASSWORD@YOUR_HOST.upstash.io:6379 - -# Test Mode (1 hour = 1 minute) -TAT_TEST_MODE=true - -# Working Hours (optional) -WORK_START_HOUR=9 -WORK_END_HOUR=18 -``` - ---- - -## Test TAT Notifications - -``` -1. Create Request - โ””โ”€ TAT: 6 hours - โ””โ”€ Submit request - -2. Wait for Notifications (Test Mode) - โ””โ”€ 3 minutes โ†’ โณ 50% alert - โ””โ”€ 4.5 minutes โ†’ โš ๏ธ 75% warning - โ””โ”€ 6 minutes โ†’ โฐ 100% breach - -3. Check Logs - โ””โ”€ [TAT Scheduler] โœ… TAT jobs scheduled - โ””โ”€ [TAT Processor] Processing tat50... - โ””โ”€ [TAT Processor] tat50 notification sent -``` - ---- - -## Monitor in Upstash Console - -``` -1. Go to: https://console.upstash.com/ -2. Click your database -3. Click "CLI" tab -4. Run commands: - - PING - โ†’ PONG - - KEYS bull:tatQueue:* - โ†’ Shows all queued TAT jobs - - INFO - โ†’ Shows Redis stats -``` - ---- - -## Troubleshooting - -### โŒ Connection Error - -```bash -# Check .env -REDIS_URL=rediss://... (correct URL?) - -# Test in Upstash Console -# CLI tab โ†’ PING โ†’ should return PONG - -# Restart backend -npm run dev -``` - -### โŒ No Notifications - -```bash -# Checklist: -- โœ… REDIS_URL in .env? -- โœ… TAT_TEST_MODE=true? -- โœ… Backend restarted? -- โœ… Request SUBMITTED (not just created)? -- โœ… Logs show "Connected to Redis"? -``` - ---- - -## Production Setup - -```bash -# Option 1: Use Upstash (same as dev) -REDIS_URL=rediss://default:PROD_PASSWORD@prod.upstash.io:6379 -TAT_TEST_MODE=false - -# Option 2: Linux server with native Redis -sudo apt install redis-server -y -sudo systemctl start redis-server - -# Then in .env: -REDIS_URL=redis://localhost:6379 -TAT_TEST_MODE=false -``` - ---- - -## Upstash Free Tier - -``` -โœ… 10,000 commands/day (FREE forever) -โœ… 256 MB storage -โœ… TLS encryption -โœ… Global CDN -โœ… Zero maintenance - -Perfect for: -- Development -- Testing -- Small production (<100 users) -``` - ---- - -## Commands Cheat Sheet - -### Upstash Console CLI - -```redis -# Test connection -PING - -# List all keys -KEYS * - -# Count keys -DBSIZE - -# View queued jobs -KEYS bull:tatQueue:* - -# Get job details -HGETALL bull:tatQueue:tat50-- - -# Clear all data (CAREFUL!) -FLUSHALL - -# Get server info -INFO - -# Monitor live commands -MONITOR -``` - ---- - -## Quick Links - -- **Upstash Console**: https://console.upstash.com/ -- **Upstash Docs**: https://docs.upstash.com/redis -- **Full Setup Guide**: `docs/UPSTASH_SETUP_GUIDE.md` -- **TAT System Docs**: `docs/TAT_NOTIFICATION_SYSTEM.md` -- **Quick Start**: `TAT_QUICK_START.md` - ---- - -## Support - -**Connection Issues?** -1. Verify URL format: `rediss://` (double 's') -2. Check Upstash database status (should be "Active") -3. Test in Upstash Console CLI - -**Need Help?** -- Check logs: `Get-Content logs/app.log -Tail 50 -Wait` -- Review docs: `docs/UPSTASH_SETUP_GUIDE.md` - ---- - -**โœ… Setup Complete? Start Testing!** - -Create a 6-hour TAT request and watch notifications arrive in 3, 4.5, and 6 minutes! - ---- - -**Last Updated**: November 4, 2025 - diff --git a/WHY_NO_ALERTS_SHOWING.md b/WHY_NO_ALERTS_SHOWING.md deleted file mode 100644 index d114d93..0000000 --- a/WHY_NO_ALERTS_SHOWING.md +++ /dev/null @@ -1,345 +0,0 @@ -# โ“ Why Are TAT Alerts Not Showing? - -## ๐ŸŽฏ Follow These Steps IN ORDER - -### โœ… Step 1: Is Redis Connected? - -**Check your backend console:** - -``` -Look for one of these messages: -``` - -**โœ… GOOD (Redis is working):** -``` -โœ… [TAT Queue] Connected to Redis -โœ… [TAT Worker] Worker is ready and listening -``` - -**โŒ BAD (Redis NOT working):** -``` -โš ๏ธ [TAT Worker] Redis connection failed -โš ๏ธ [TAT Queue] Redis connection failed after 3 attempts -``` - -**If you see the BAD message:** - -โ†’ **STOP HERE!** TAT alerts will NOT work without Redis! - -โ†’ **Setup Upstash Redis NOW:** - 1. Go to: https://console.upstash.com/ - 2. Sign up (free) - 3. Create database - 4. Copy Redis URL - 5. Add to `Re_Backend/.env`: - ```bash - REDIS_URL=rediss://default:PASSWORD@host.upstash.io:6379 - TAT_TEST_MODE=true - ``` - 6. Restart backend - 7. Verify you see "Connected to Redis" - ---- - -### โœ… Step 2: Have You Submitted a Request? - -**TAT monitoring starts ONLY when:** -- โœ… Request is **SUBMITTED** (not just created/saved) -- โœ… Status changes from DRAFT โ†’ PENDING - -**To verify:** -```sql -SELECT - request_number, - status, - submission_date -FROM workflow_requests -WHERE request_number = 'YOUR_REQUEST_NUMBER'; -``` - -**Check:** -- `status` should be `PENDING`, `IN_PROGRESS`, or later -- `submission_date` should NOT be NULL - -**If status is DRAFT:** -โ†’ Click "Submit" button on the request -โ†’ TAT monitoring will start - ---- - -### โœ… Step 3: Has Enough Time Passed? - -**In TEST MODE (TAT_TEST_MODE=true):** -- 1 hour = 1 minute -- For 6-hour TAT: - - 50% alert at: **3 minutes** - - 75% alert at: **4.5 minutes** - - 100% breach at: **6 minutes** - -**In PRODUCTION MODE:** -- 1 hour = 1 hour (real time) -- For 24-hour TAT: - - 50% alert at: **12 hours** - - 75% alert at: **18 hours** - - 100% breach at: **24 hours** - -**Check when request was submitted:** -```sql -SELECT - request_number, - submission_date, - NOW() - submission_date as time_since_submission -FROM workflow_requests -WHERE request_number = 'YOUR_REQUEST_NUMBER'; -``` - ---- - -### โœ… Step 4: Are Alerts in the Database? - -**Run this SQL:** -```sql --- Check if table exists -SELECT COUNT(*) FROM tat_alerts; - --- If table exists, check for your request -SELECT - ta.threshold_percentage, - ta.alert_sent_at, - ta.alert_message, - ta.metadata -FROM tat_alerts ta -JOIN workflow_requests w ON ta.request_id = w.request_id -WHERE w.request_number = 'YOUR_REQUEST_NUMBER' -ORDER BY ta.alert_sent_at; -``` - -**Expected Result:** -- **0 rows** โ†’ No alerts sent yet (wait longer OR Redis not connected) -- **1+ rows** โ†’ Alerts exist! (Go to Step 5) - -**If table doesn't exist:** -```bash -cd Re_Backend -npm run migrate -``` - ---- - -### โœ… Step 5: Is API Returning tatAlerts? - -**Test the API directly:** - -**Method 1: Use Debug Endpoint** -```bash -curl http://localhost:5000/api/debug/workflow-details/YOUR_REQUEST_NUMBER -``` - -**Look for:** -```json -{ - "structure": { - "hasTatAlerts": true, โ† Should be true - "tatAlertsCount": 2 โ† Should be > 0 - }, - "tatAlerts": [...] โ† Should have data -} -``` - -**Method 2: Check Network Tab in Browser** - -1. Open Request Detail page -2. Open DevTools (F12) โ†’ Network tab -3. Find the API call to `/workflows/{requestNumber}/details` -4. Click on it -5. Check Response tab -6. Look for `tatAlerts` array - ---- - -### โœ… Step 6: Is Frontend Receiving tatAlerts? - -**Open Browser Console (F12 โ†’ Console)** - -**When you open Request Detail, you should see:** -```javascript -[RequestDetail] TAT Alerts received from API: 2 [Array(2)] -``` - -**If you see:** -```javascript -[RequestDetail] TAT Alerts received from API: 0 [] -``` - -โ†’ API is NOT returning alerts (go back to Step 4) - ---- - -### โœ… Step 7: Are Alerts Being Displayed? - -**In Request Detail:** -1. Click **"Workflow" tab** -2. Scroll to the approver card -3. Look under the approver's comment section - -**You should see yellow/orange/red boxes with:** -``` -โณ Reminder 1 - 50% TAT Threshold -``` - -**If you DON'T see them:** -โ†’ Check browser console for JavaScript errors - ---- - -## ๐Ÿ” Quick Diagnostic - -**Run ALL of these and share the results:** - -### 1. Backend Status: -```bash -curl http://localhost:5000/api/debug/tat-status -``` - -### 2. Database Query: -```sql -SELECT COUNT(*) as total FROM tat_alerts; -``` - -### 3. Browser Console: -```javascript -// Open Request Detail -// Check console for: -[RequestDetail] TAT Alerts received from API: X [...] -``` - -### 4. Network Response: -``` -DevTools โ†’ Network โ†’ workflow details call โ†’ Response tab -Look for "tatAlerts" field -``` - ---- - -## ๐ŸŽฏ Most Likely Issues (In Order) - -### 1. Redis Not Connected (90% of cases) -**Symptom**: No "Connected to Redis" in logs -**Fix**: Setup Upstash, add REDIS_URL, restart - -### 2. Request Not Submitted (5%) -**Symptom**: Request status is DRAFT -**Fix**: Click Submit button - -### 3. Not Enough Time Passed (3%) -**Symptom**: Submitted < 3 minutes ago (in test mode) -**Fix**: Wait 3 minutes for first alert - -### 4. TAT Worker Not Running (1%) -**Symptom**: Redis connected but no "Worker is ready" message -**Fix**: Restart backend server - -### 5. Frontend Code Not Applied (1%) -**Symptom**: API returns tatAlerts but UI doesn't show them -**Fix**: Refresh browser, clear cache - ---- - -## ๐Ÿšจ Emergency Checklist - -**Do this RIGHT NOW to verify everything:** - -```bash -# 1. Check backend console for Redis connection -# Look for: โœ… [TAT Queue] Connected to Redis - -# 2. If NOT connected, setup Upstash: -# https://console.upstash.com/ - -# 3. Add to .env: -# REDIS_URL=rediss://... -# TAT_TEST_MODE=true - -# 4. Restart backend -npm run dev - -# 5. Check you see "Connected to Redis" - -# 6. Create NEW request with 6-hour TAT - -# 7. SUBMIT the request - -# 8. Wait 3 minutes - -# 9. Open browser console (F12) - -# 10. Open Request Detail page - -# 11. Check console log for: -# [RequestDetail] TAT Alerts received from API: X [...] - -# 12. Go to Workflow tab - -# 13. Alerts should appear! -``` - ---- - -## ๐Ÿ“ž Share These for Help - -If still not working, share: - -1. **Backend console output** (first 50 lines after starting) -2. **Result of**: `curl http://localhost:5000/api/debug/tat-status` -3. **SQL result**: `SELECT COUNT(*) FROM tat_alerts;` -4. **Browser console** when opening Request Detail -5. **Request number** you're testing with -6. **How long ago** was the request submitted? - ---- - -## โœ… Working Example - -**When everything works, you'll see:** - -**Backend Console:** -``` -โœ… [TAT Queue] Connected to Redis -โœ… [TAT Worker] Worker is ready -[TAT Scheduler] โœ… TAT jobs scheduled for request REQ-2025-001 -``` - -**After 3 minutes (test mode):** -``` -[TAT Processor] Processing tat50 for request REQ-2025-001 -[TAT Processor] TAT alert record created for tat50 -[TAT Processor] tat50 notification sent -``` - -**Browser Console:** -```javascript -[RequestDetail] TAT Alerts received from API: 1 [ - { - alertType: "TAT_50", - thresholdPercentage: 50, - alertSentAt: "2025-11-04T...", - ... - } -] -``` - -**UI Display:** -``` -โณ Reminder 1 - 50% TAT Threshold -50% of SLA breach reminder have been sent -... -``` - ---- - -**Most likely you just need to setup Redis! See `START_HERE.md`** - ---- - -**Last Updated**: November 4, 2025 - diff --git a/src/middlewares/cors.middleware.ts b/src/middlewares/cors.middleware.ts index f9938e5..0619498 100644 --- a/src/middlewares/cors.middleware.ts +++ b/src/middlewares/cors.middleware.ts @@ -17,16 +17,21 @@ export const corsMiddleware = cors({ origin: (origin, callback) => { const allowedOrigins = getOrigins(); - // Allow requests with no origin (like mobile apps or curl requests) in development - if (!origin && process.env.NODE_ENV === 'development') { + // In development, be more permissive + if (process.env.NODE_ENV !== 'production') { + // Allow localhost on any port + if (!origin || origin.includes('localhost') || origin.includes('127.0.0.1')) { + return callback(null, true); + } + } + + // Allow requests with no origin (like mobile apps or curl requests) + if (!origin) { return callback(null, true); } if (origin && allowedOrigins.includes(origin)) { callback(null, true); - } else if (!origin) { - // Allow requests with no origin - callback(null, true); } else { callback(new Error('Not allowed by CORS')); } diff --git a/src/queues/delayedJobPromoter.ts b/src/queues/delayedJobPromoter.ts new file mode 100644 index 0000000..809bb40 --- /dev/null +++ b/src/queues/delayedJobPromoter.ts @@ -0,0 +1,33 @@ +import { tatQueue } from './tatQueue'; +import logger from '@utils/logger'; + +async function promoteDelayedJobs() { + if (!tatQueue) return; + + try { + const delayedJobs = await tatQueue.getJobs(['delayed']); + const now = Date.now(); + let promotedCount = 0; + + for (const job of delayedJobs) { + const readyTime = job.timestamp + (job.opts.delay || 0); + const secondsUntil = Math.round((readyTime - now) / 1000); + + // Promote if ready within 15 seconds + if (secondsUntil <= 15) { + await job.promote(); + promotedCount++; + } + } + + if (promotedCount > 0) { + logger.info(`[TAT] Promoted ${promotedCount} jobs`); + } + } catch (error) { + logger.error('[TAT] Promoter error:', error); + } +} + +// Check every 3 seconds +setInterval(promoteDelayedJobs, 3000); +logger.info('[TAT] Delayed job promoter started'); diff --git a/src/queues/redisConnection.ts b/src/queues/redisConnection.ts new file mode 100644 index 0000000..5237847 --- /dev/null +++ b/src/queues/redisConnection.ts @@ -0,0 +1,57 @@ +import IORedis from 'ioredis'; +import logger from '@utils/logger'; + +const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379'; +const redisPassword = process.env.REDIS_PASSWORD || undefined; + +const redisOptions: any = { + maxRetriesPerRequest: null, // Required for BullMQ + enableReadyCheck: false, + retryStrategy: (times: number) => { + if (times > 5) { + logger.error('[Redis] Connection failed after 5 attempts'); + return null; + } + return Math.min(times * 2000, 10000); + }, + connectTimeout: 30000, + commandTimeout: 20000, + keepAlive: 30000, + autoResubscribe: true, + autoResendUnfulfilledCommands: true +}; + +if (redisPassword) { + redisOptions.password = redisPassword; + logger.info('[Redis] Using password authentication'); +} + +let sharedConnection: IORedis | null = null; + +// Create a SINGLE shared connection for both Queue and Worker +export const getSharedRedisConnection = (): IORedis => { + if (!sharedConnection) { + logger.info(`[Redis] Creating shared connection to ${redisUrl}`); + sharedConnection = new IORedis(redisUrl, redisOptions); + + sharedConnection.on('connect', () => { + logger.info(`[Redis] โœ… Connected to ${redisUrl}`); + }); + + sharedConnection.on('error', (err) => { + logger.error('[Redis] Connection error:', err.message); + }); + + sharedConnection.on('close', () => { + logger.warn('[Redis] Connection closed'); + }); + } + + return sharedConnection; +}; + +// Export for backwards compatibility +export const sharedRedisConnection = getSharedRedisConnection(); + +export default sharedRedisConnection; + diff --git a/src/queues/tatProcessor.ts b/src/queues/tatProcessor.ts index 91ce316..ef464f4 100644 --- a/src/queues/tatProcessor.ts +++ b/src/queues/tatProcessor.ts @@ -21,8 +21,9 @@ interface TatJobData { export async function handleTatJob(job: Job) { const { requestId, levelId, approverId, type, threshold } = job.data; + logger.info(`[TAT Processor] Processing ${type} (${threshold}%) for request ${requestId}`); + try { - logger.info(`[TAT Processor] Processing ${type} for request ${requestId}, level ${levelId}`); // Get approval level and workflow details const approvalLevel = await ApprovalLevel.findOne({ @@ -30,8 +31,8 @@ export async function handleTatJob(job: Job) { }); if (!approvalLevel) { - logger.warn(`[TAT Processor] Approval level ${levelId} not found`); - return; + logger.warn(`[TAT Processor] Approval level ${levelId} not found - likely already approved/rejected`); + return; // Skip notification for non-existent level } // Check if level is still pending (not already approved/rejected) @@ -126,7 +127,7 @@ export async function handleTatJob(job: Job) { expectedCompletionTime, alertMessage: message, notificationSent: true, - notificationChannels: ['push'], // Can add 'email', 'sms' if implemented + notificationChannels: ['push'], isBreached: type === 'breach', metadata: { requestNumber, @@ -140,10 +141,9 @@ export async function handleTatJob(job: Job) { } } as any); - logger.info(`[TAT Processor] TAT alert record created for ${type}`); - } catch (alertError) { - logger.error(`[TAT Processor] Failed to create TAT alert record:`, alertError); - // Don't fail the notification if alert logging fails + logger.info(`[TAT Processor] โœ… Alert created: ${type} (${threshold}%)`); + } catch (alertError: any) { + logger.error(`[TAT Processor] โŒ Alert creation failed for ${type}: ${alertError.message}`); } // Send notification to approver @@ -156,15 +156,48 @@ export async function handleTatJob(job: Job) { type: type }); - // Log activity - await activityService.log({ - requestId, - type: 'sla_warning', - user: { userId: 'system', name: 'System' }, - timestamp: new Date().toISOString(), - action: type === 'breach' ? 'TAT Breached' : 'TAT Warning', - details: activityDetails - }); + // Log activity (skip if it fails - don't break the TAT notification) + try { + await activityService.log({ + requestId, + type: 'sla_warning', + user: { userId: null as any, name: 'System' }, // Use null instead of 'system' for UUID field + timestamp: new Date().toISOString(), + action: type === 'breach' ? 'TAT Breached' : 'TAT Warning', + details: activityDetails + }); + logger.info(`[TAT Processor] Activity logged for ${type}`); + } catch (activityError: any) { + logger.warn(`[TAT Processor] Failed to log activity (non-critical):`, activityError.message); + // Continue - activity logging failure shouldn't break TAT notification + } + + // ๐Ÿ”ฅ CRITICAL: Emit TAT alert to frontend via socket.io for real-time updates + try { + const { emitToRequestRoom } = require('../realtime/socket'); + if (emitToRequestRoom) { + // Fetch the newly created alert to send complete data to frontend + const newAlert = await TatAlert.findOne({ + where: { requestId, levelId, alertType }, + order: [['createdAt', 'DESC']] + }); + + if (newAlert) { + emitToRequestRoom(requestId, 'tat:alert', { + alert: newAlert, + requestId, + levelId, + type, + thresholdPercentage, + message + }); + logger.info(`[TAT Processor] โœ… TAT alert emitted to frontend via socket.io for request ${requestId}`); + } + } + } catch (socketError) { + logger.error(`[TAT Processor] Failed to emit TAT alert via socket:`, socketError); + // Don't fail the job if socket emission fails + } logger.info(`[TAT Processor] ${type} notification sent for request ${requestId}`); } catch (error) { diff --git a/src/queues/tatQueue.ts b/src/queues/tatQueue.ts index 838137f..7b1d8c6 100644 --- a/src/queues/tatQueue.ts +++ b/src/queues/tatQueue.ts @@ -1,80 +1,26 @@ import { Queue } from 'bullmq'; -import IORedis from 'ioredis'; +import { sharedRedisConnection } from './redisConnection'; import logger from '@utils/logger'; -// Create Redis connection -const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379'; -const redisPassword = process.env.REDIS_PASSWORD || undefined; - -let connection: IORedis | null = null; let tatQueue: Queue | null = null; try { - // Parse Redis URL and add password if provided - const redisOptions: any = { - maxRetriesPerRequest: null, // Required for BullMQ - enableReadyCheck: false, - lazyConnect: true, // Don't connect immediately - retryStrategy: (times: number) => { - if (times > 5) { - logger.warn('[TAT Queue] Redis connection failed after 5 attempts. TAT notifications will be disabled.'); - return null; // Stop retrying + // Use shared Redis connection for both Queue and Worker + tatQueue = new Queue('tatQueue', { + connection: sharedRedisConnection, + defaultJobOptions: { + removeOnComplete: true, + removeOnFail: false, + attempts: 2, + backoff: { + type: 'fixed', + delay: 5000 } - return Math.min(times * 2000, 10000); // Increase retry delay - }, - // Increased timeouts for remote Redis server - connectTimeout: 30000, // 30 seconds (for remote server) - commandTimeout: 20000, // 20 seconds (for slow network) - // Keepalive for long-running connections - keepAlive: 30000, - // Reconnect on error - autoResubscribe: true, - autoResendUnfulfilledCommands: true - }; - - // Add password if provided (either from env var or from URL) - if (redisPassword) { - redisOptions.password = redisPassword; - logger.info('[TAT Queue] Using Redis with password authentication'); - } - - connection = new IORedis(redisUrl, redisOptions); - - // Handle connection events - connection.on('connect', () => { - logger.info('[TAT Queue] Connected to Redis'); + } }); - - connection.on('error', (err) => { - logger.warn('[TAT Queue] Redis connection error - TAT notifications disabled:', err.message); - }); - - // Try to connect - connection.connect().then(() => { - logger.info('[TAT Queue] Redis connection established'); - }).catch((err) => { - logger.warn('[TAT Queue] Could not connect to Redis. TAT notifications will be disabled.', err.message); - connection = null; - }); - - // Create TAT Queue only if connection is available - if (connection) { - tatQueue = new Queue('tatQueue', { - connection, - defaultJobOptions: { - removeOnComplete: true, // Clean up completed jobs - removeOnFail: false, // Keep failed jobs for debugging - attempts: 3, // Retry failed jobs up to 3 times - backoff: { - type: 'exponential', - delay: 2000 // Start with 2 second delay - } - } - }); - logger.info('[TAT Queue] Queue initialized'); - } + logger.info('[TAT Queue] Queue initialized'); } catch (error) { - logger.warn('[TAT Queue] Failed to initialize TAT queue. TAT notifications will be disabled.', error); + logger.error('[TAT Queue] Failed to initialize:', error); tatQueue = null; } diff --git a/src/queues/tatWorker.ts b/src/queues/tatWorker.ts index e72691c..dcb6784 100644 --- a/src/queues/tatWorker.ts +++ b/src/queues/tatWorker.ts @@ -1,187 +1,46 @@ import { Worker } from 'bullmq'; -import IORedis from 'ioredis'; +import { sharedRedisConnection } from './redisConnection'; import { handleTatJob } from './tatProcessor'; import logger from '@utils/logger'; -// Create Redis connection for worker -const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379'; -const redisPassword = process.env.REDIS_PASSWORD || undefined; - -let connection: IORedis | null = null; let tatWorker: Worker | null = null; try { - // Parse Redis connection options - const redisOptions: any = { - maxRetriesPerRequest: null, - enableReadyCheck: false, - lazyConnect: true, - retryStrategy: (times: number) => { - if (times > 5) { - logger.warn('[TAT Worker] Redis connection failed after 5 retries. TAT worker will not start.'); - return null; - } - logger.warn(`[TAT Worker] Redis connection retry attempt ${times}`); - return Math.min(times * 2000, 10000); // Increase retry delay - }, - // Increased timeouts for remote Redis server - connectTimeout: 30000, // 30 seconds (for remote server) - commandTimeout: 20000, // 20 seconds (for slow network) - // Keepalive for long-running connections - keepAlive: 30000, - // Reconnect on error - autoResubscribe: true, - autoResendUnfulfilledCommands: true - }; - - // Add password if provided (for authenticated Redis) - if (redisPassword) { - redisOptions.password = redisPassword; - logger.info('[TAT Worker] Using Redis with password authentication'); - } - - connection = new IORedis(redisUrl, redisOptions); - - // Handle connection errors - connection.on('error', (err) => { - logger.error('[TAT Worker] Redis connection error:', { - message: err.message, - code: (err as any).code, - errno: (err as any).errno, - syscall: (err as any).syscall, - address: (err as any).address, - port: (err as any).port + tatWorker = new Worker('tatQueue', handleTatJob, { + connection: sharedRedisConnection, + concurrency: 5, + autorun: true, + limiter: { + max: 10, + duration: 1000 + } + }); + + logger.info('[TAT Worker] Worker initialized'); + + if (tatWorker) { + tatWorker.on('ready', () => { + logger.info('[TAT Worker] Ready and listening'); }); - }); - - connection.on('close', () => { - logger.warn('[TAT Worker] Redis connection closed'); - }); - - connection.on('reconnecting', (delay: number) => { - logger.info(`[TAT Worker] Redis reconnecting in ${delay}ms`); - }); - - // Try to connect and create worker - connection.connect().then(async () => { - logger.info(`[TAT Worker] Connected to Redis at ${redisUrl}`); - // Verify connection by pinging and check Redis version - try { - const pingResult = await connection!.ping(); - logger.info(`[TAT Worker] Redis PING successful: ${pingResult}`); - - // Check Redis version - const info = await connection!.info('server'); - const versionMatch = info.match(/redis_version:(.+)/); - if (versionMatch) { - const version = versionMatch[1].trim(); - logger.info(`[TAT Worker] Redis version: ${version}`); - - // Parse version (e.g., "3.0.504" or "7.0.0") - const versionParts = version.split('.').map(Number); - const majorVersion = versionParts[0]; - - if (majorVersion < 5) { - logger.error(`[TAT Worker] โŒ CRITICAL: Redis version ${version} is incompatible!`); - logger.error(`[TAT Worker] BullMQ REQUIRES Redis 5.0.0 or higher. Current version: ${version}`); - logger.error(`[TAT Worker] โš ๏ธ TAT Worker cannot start with this Redis version.`); - logger.error(`[TAT Worker] ๐Ÿ“– Solution: Upgrade Redis (see docs/REDIS_SETUP_WINDOWS.md)`); - logger.error(`[TAT Worker] ๐Ÿ’ก Recommended: Install Memurai or use Docker Redis 7.x`); - throw new Error(`Redis version ${version} is too old. BullMQ requires Redis 5.0.0+. Please upgrade Redis.`); - } - } - } catch (err: any) { - logger.error('[TAT Worker] Redis PING or version check failed:', err); - // If version check failed, don't create worker - if (err && err.message && err.message.includes('Redis version')) { - logger.warn('[TAT Worker] TAT notifications will be disabled until Redis is upgraded.'); - connection = null; - tatWorker = null; - return; - } - } + tatWorker.on('active', (job) => { + logger.info(`[TAT Worker] Processing: ${job.name}`); + }); - // Create TAT Worker (only if version check passed) - if (connection) { - try { - // BullMQ will check Redis version internally - wrap in try-catch - tatWorker = new Worker('tatQueue', handleTatJob, { - connection: connection!, - concurrency: 5, // Process up to 5 jobs concurrently - limiter: { - max: 10, // Maximum 10 jobs - duration: 1000 // per second - } - }); - } catch (workerError: any) { - // Handle Redis version errors gracefully - if (workerError && ( - (workerError.message && workerError.message.includes('Redis version')) || - (workerError.message && workerError.message.includes('5.0.0')) - )) { - logger.error(`[TAT Worker] โŒ ${workerError.message || 'Redis version incompatible'}`); - logger.warn(`[TAT Worker] โš ๏ธ TAT notifications are DISABLED. Application will continue to work without TAT alerts.`); - logger.info(`[TAT Worker] ๐Ÿ’ก To enable TAT notifications, upgrade Redis to version 5.0+ (see docs/REDIS_SETUP_WINDOWS.md)`); - - // Clean up connection - try { - await connection!.quit(); - } catch (quitError) { - // Ignore quit errors - } - connection = null; - tatWorker = null; - return; - } - // Re-throw other errors - logger.error('[TAT Worker] Unexpected error creating worker:', workerError); - throw workerError; - } - } - - // Event listeners (only if worker was created successfully) - if (tatWorker) { - tatWorker.on('ready', () => { - logger.info('[TAT Worker] Worker is ready and listening for jobs'); - }); - - tatWorker.on('completed', (job) => { - logger.info(`[TAT Worker] โœ… Job ${job.id} (${job.name}) completed for request ${job.data.requestId}`); - }); - - tatWorker.on('failed', (job, err) => { - if (job) { - logger.error(`[TAT Worker] โŒ Job ${job.id} (${job.name}) failed for request ${job.data.requestId}:`, err); - } else { - logger.error('[TAT Worker] โŒ Job failed:', err); - } - }); - - tatWorker.on('error', (err) => { - logger.error('[TAT Worker] Worker error:', { - message: err.message, - stack: err.stack, - name: err.name, - code: (err as any).code, - errno: (err as any).errno, - syscall: (err as any).syscall - }); - }); - - tatWorker.on('stalled', (jobId) => { - logger.warn(`[TAT Worker] Job ${jobId} has stalled`); - }); - - logger.info('[TAT Worker] Worker initialized and listening for TAT jobs'); - } - }).catch((err) => { - logger.warn('[TAT Worker] Could not connect to Redis. TAT worker will not start. TAT notifications are disabled.', err.message); - connection = null; - tatWorker = null; - }); -} catch (error) { - logger.warn('[TAT Worker] Failed to initialize TAT worker. TAT notifications will be disabled.', error); + tatWorker.on('completed', (job) => { + logger.info(`[TAT Worker] Completed: ${job.name}`); + }); + + tatWorker.on('failed', (job, err) => { + logger.error(`[TAT Worker] Failed: ${job?.name}`, err.message); + }); + + tatWorker.on('error', (err) => { + logger.error('[TAT Worker] Error:', err.message); + }); + } +} catch (workerError: any) { + logger.error('[TAT Worker] Failed to create worker:', workerError); tatWorker = null; } @@ -191,9 +50,6 @@ process.on('SIGTERM', async () => { logger.info('[TAT Worker] SIGTERM received, closing worker...'); await tatWorker.close(); } - if (connection) { - await connection.quit(); - } }); process.on('SIGINT', async () => { @@ -201,10 +57,6 @@ process.on('SIGINT', async () => { logger.info('[TAT Worker] SIGINT received, closing worker...'); await tatWorker.close(); } - if (connection) { - await connection.quit(); - } }); export { tatWorker }; - diff --git a/src/routes/debug.routes.ts b/src/routes/debug.routes.ts index db4d991..9957fe1 100644 --- a/src/routes/debug.routes.ts +++ b/src/routes/debug.routes.ts @@ -1,30 +1,237 @@ -import { Router } from 'express'; -import { authenticateToken } from '@middlewares/auth.middleware'; -import { - checkTatSystemStatus, - checkWorkflowDetailsResponse -} from '@controllers/debug.controller'; +import { Router, Request, Response } from 'express'; +import { tatQueue } from '../queues/tatQueue'; +import { TatAlert } from '@models/TatAlert'; +import { ApprovalLevel } from '@models/ApprovalLevel'; +import dayjs from 'dayjs'; +import logger from '@utils/logger'; const router = Router(); -// Debug routes (should be disabled in production) -if (process.env.NODE_ENV !== 'production') { - router.use(authenticateToken); +/** + * Debug endpoint to check scheduled TAT jobs in the queue + */ +router.get('/tat-jobs/:requestId', async (req: Request, res: Response): Promise => { + try { + const { requestId } = req.params; + + if (!tatQueue) { + res.json({ + error: 'TAT queue not available (Redis not connected)', + jobs: [] + }); + return; + } - /** - * @route GET /api/debug/tat-status - * @desc Check TAT system configuration and status - * @access Private - */ - router.get('/tat-status', checkTatSystemStatus); + // Get all jobs for this request + const waitingJobs = await tatQueue.getJobs(['waiting', 'delayed', 'active']); + const requestJobs = waitingJobs.filter(job => job.data.requestId === requestId); - /** - * @route GET /api/debug/workflow-details/:requestId - * @desc Check what's in workflow details response - * @access Private - */ - router.get('/workflow-details/:requestId', checkWorkflowDetailsResponse); -} + const jobDetails = requestJobs.map(job => { + const delay = job.opts.delay || 0; + const scheduledTime = job.timestamp ? new Date(job.timestamp + delay) : null; + const now = new Date(); + const timeUntilFire = scheduledTime ? Math.round((scheduledTime.getTime() - now.getTime()) / 1000 / 60) : null; + + return { + jobId: job.id, + type: job.data.type, + threshold: job.data.threshold, + requestId: job.data.requestId, + levelId: job.data.levelId, + state: job.getState(), + delay: delay, + delayMinutes: Math.round(delay / 1000 / 60), + delayHours: (delay / 1000 / 60 / 60).toFixed(2), + timestamp: job.timestamp, + scheduledTime: scheduledTime?.toISOString(), + timeUntilFire: timeUntilFire ? `${timeUntilFire} minutes` : 'N/A', + processedOn: job.processedOn ? new Date(job.processedOn).toISOString() : null, + finishedOn: job.finishedOn ? new Date(job.finishedOn).toISOString() : null + }; + }); + + // Get TAT alerts from database + const alerts = await TatAlert.findAll({ + where: { requestId }, + order: [['alertSentAt', 'ASC']] + }); + + const alertDetails = alerts.map((alert: any) => ({ + alertType: alert.alertType, + thresholdPercentage: alert.thresholdPercentage, + alertSentAt: alert.alertSentAt, + levelStartTime: alert.levelStartTime, + timeSinceStart: alert.levelStartTime + ? `${((new Date(alert.alertSentAt).getTime() - new Date(alert.levelStartTime).getTime()) / 1000 / 60 / 60).toFixed(2)} hours` + : 'N/A', + notificationSent: alert.notificationSent + })); + + // Get approval level details + const levels = await ApprovalLevel.findAll({ + where: { requestId } + }); + + const levelDetails = levels.map((level: any) => ({ + levelId: level.levelId, + levelNumber: level.levelNumber, + status: level.status, + tatHours: level.tatHours, + levelStartTime: level.levelStartTime, + tat50AlertSent: level.tat50AlertSent, + tat75AlertSent: level.tat75AlertSent, + tatBreached: level.tatBreached, + tatPercentageUsed: level.tatPercentageUsed + })); + + res.json({ + requestId, + currentTime: new Date().toISOString(), + queuedJobs: jobDetails, + jobCount: jobDetails.length, + sentAlerts: alertDetails, + alertCount: alertDetails.length, + approvalLevels: levelDetails, + testMode: process.env.TAT_TEST_MODE === 'true' + }); + + } catch (error: any) { + logger.error('[Debug] Error checking TAT jobs:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * Debug endpoint to check all queued TAT jobs + */ +router.get('/tat-jobs', async (req: Request, res: Response): Promise => { + try { + if (!tatQueue) { + res.json({ + error: 'TAT queue not available (Redis not connected)', + jobs: [] + }); + return; + } + + const waitingJobs = await tatQueue.getJobs(['waiting', 'delayed', 'active']); + + const jobDetails = waitingJobs.map(job => { + const delay = job.opts.delay || 0; + const scheduledTime = job.timestamp ? new Date(job.timestamp + delay) : null; + const now = new Date(); + const timeUntilFire = scheduledTime ? Math.round((scheduledTime.getTime() - now.getTime()) / 1000 / 60) : null; + + return { + jobId: job.id, + type: job.data.type, + threshold: job.data.threshold, + requestId: job.data.requestId, + levelId: job.data.levelId, + state: job.getState(), + delay: delay, + delayMinutes: Math.round(delay / 1000 / 60), + delayHours: (delay / 1000 / 60 / 60).toFixed(2), + scheduledTime: scheduledTime?.toISOString(), + timeUntilFire: timeUntilFire ? `${timeUntilFire} minutes` : 'N/A' + }; + }); + + res.json({ + currentTime: new Date().toISOString(), + jobs: jobDetails, + totalJobs: jobDetails.length, + testMode: process.env.TAT_TEST_MODE === 'true' + }); + + } catch (error: any) { + logger.error('[Debug] Error checking all TAT jobs:', error); + res.status(500).json({ error: error.message }); + } +}); + +/** + * Debug endpoint to check TAT time calculations + */ +router.post('/tat-calculate', async (req: Request, res: Response): Promise => { + try { + const { startTime, tatHours, priority = 'STANDARD' } = req.body; + + const { addWorkingHours, addWorkingHoursExpress, calculateDelay } = await import('@utils/tatTimeUtils'); + const { getTatThresholds } = await import('../services/configReader.service'); + + const start = startTime ? new Date(startTime) : new Date(); + const isExpress = priority === 'EXPRESS'; + const thresholds = await getTatThresholds(); + + let threshold1Time: Date; + let threshold2Time: Date; + let breachTime: Date; + + if (isExpress) { + const t1 = await addWorkingHoursExpress(start, tatHours * (thresholds.first / 100)); + const t2 = await addWorkingHoursExpress(start, tatHours * (thresholds.second / 100)); + const tBreach = await addWorkingHoursExpress(start, tatHours); + threshold1Time = t1.toDate(); + threshold2Time = t2.toDate(); + breachTime = tBreach.toDate(); + } else { + const t1 = await addWorkingHours(start, tatHours * (thresholds.first / 100)); + const t2 = await addWorkingHours(start, tatHours * (thresholds.second / 100)); + const tBreach = await addWorkingHours(start, tatHours); + threshold1Time = t1.toDate(); + threshold2Time = t2.toDate(); + breachTime = tBreach.toDate(); + } + + const now = new Date(); + const delays = { + threshold1: calculateDelay(threshold1Time), + threshold2: calculateDelay(threshold2Time), + breach: calculateDelay(breachTime) + }; + + res.json({ + input: { + startTime: start.toISOString(), + tatHours, + priority, + thresholds + }, + calculations: { + threshold1: { + percentage: thresholds.first, + targetTime: threshold1Time.toISOString(), + delay: delays.threshold1, + delayMinutes: Math.round(delays.threshold1 / 1000 / 60), + delayHours: (delays.threshold1 / 1000 / 60 / 60).toFixed(2), + isPast: delays.threshold1 === 0 + }, + threshold2: { + percentage: thresholds.second, + targetTime: threshold2Time.toISOString(), + delay: delays.threshold2, + delayMinutes: Math.round(delays.threshold2 / 1000 / 60), + delayHours: (delays.threshold2 / 1000 / 60 / 60).toFixed(2), + isPast: delays.threshold2 === 0 + }, + breach: { + percentage: 100, + targetTime: breachTime.toISOString(), + delay: delays.breach, + delayMinutes: Math.round(delays.breach / 1000 / 60), + delayHours: (delays.breach / 1000 / 60 / 60).toFixed(2), + isPast: delays.breach === 0 + } + }, + currentTime: now.toISOString(), + testMode: process.env.TAT_TEST_MODE === 'true' + }); + + } catch (error: any) { + logger.error('[Debug] Error calculating TAT times:', error); + res.status(500).json({ error: error.message }); + } +}); export default router; - diff --git a/src/server.ts b/src/server.ts index e780d3e..fa9bc6e 100644 --- a/src/server.ts +++ b/src/server.ts @@ -2,6 +2,7 @@ import app from './app'; import http from 'http'; import { initSocket } from './realtime/socket'; import './queues/tatWorker'; // Initialize TAT worker +import './queues/delayedJobPromoter'; // Initialize delayed job promoter (workaround for BullMQ + remote Redis) import { logTatConfig } from './config/tat.config'; import { logSystemConfig } from './config/system.config'; import { initializeHolidaysCache } from './utils/tatTimeUtils'; diff --git a/src/services/tatScheduler.service.ts b/src/services/tatScheduler.service.ts index 5b1809a..5ee7cab 100644 --- a/src/services/tatScheduler.service.ts +++ b/src/services/tatScheduler.service.ts @@ -91,38 +91,59 @@ export class TatSchedulerService { } ]; + + // Check if test mode enabled (1 hour = 1 minute) + const isTestMode = process.env.TAT_TEST_MODE === 'true'; + + // Check if times collide (working hours calculation issue) + const uniqueTimes = new Set(jobs.map(j => j.targetTime.getTime())); + const hasCollision = uniqueTimes.size < jobs.length; + + let jobIndex = 0; for (const job of jobs) { - // Skip if the time has already passed - if (job.delay === 0) { - logger.warn(`[TAT Scheduler] Skipping ${job.type} (${job.threshold}%) for level ${levelId} - time already passed`); + if (job.delay < 0) { + logger.error(`[TAT Scheduler] Skipping ${job.type} - time in past`); continue; } + let spacedDelay: number; + + if (isTestMode) { + // Test mode: times are already in minutes (tatTimeUtils converts hours to minutes) + // Just ensure they have minimum spacing for BullMQ reliability + spacedDelay = Math.max(job.delay, 5000) + (jobIndex * 5000); + } else if (hasCollision) { + // Production with collision: add 5-minute spacing + spacedDelay = job.delay + (jobIndex * 300000); + } else { + // Production without collision: use calculated delays + spacedDelay = job.delay; + } + + const jobId = `tat-${job.type}-${requestId}-${levelId}`; + await tatQueue.add( job.type, { type: job.type, - threshold: job.threshold, // Store actual threshold percentage in job data + threshold: job.threshold, requestId, levelId, approverId }, { - delay: job.delay, - jobId: `tat-${job.type}-${requestId}-${levelId}`, // Generic job ID + delay: spacedDelay, + jobId: jobId, removeOnComplete: true, removeOnFail: false } ); - logger.info( - `[TAT Scheduler] Scheduled ${job.type} (${job.threshold}%) for level ${levelId} ` + - `(delay: ${Math.round(job.delay / 1000 / 60)} minutes, ` + - `target: ${dayjs(job.targetTime).format('YYYY-MM-DD HH:mm')})` - ); + logger.info(`[TAT Scheduler] Scheduled ${job.type} (${job.threshold}%)`); + jobIndex++; } - logger.info(`[TAT Scheduler] โœ… TAT jobs scheduled for request ${requestId}, approver ${approverId}`); + logger.info(`[TAT Scheduler] TAT jobs scheduled for request ${requestId}`); } catch (error) { logger.error(`[TAT Scheduler] Failed to schedule TAT jobs:`, error); throw error;