Re_Backend/docs/HOLIDAY_CALENDAR_SYSTEM.md

9.9 KiB

📅 Holiday Calendar System - Complete Guide

Overview

The Holiday Calendar System allows administrators to manage organizational holidays that are excluded from TAT (Turnaround Time) calculations for STANDARD priority requests.

Key Features:

  • Admin can add/edit/delete holidays
  • Supports different holiday types (National, Regional, Organizational, Optional)
  • Recurring holidays (e.g., Independence Day every year)
  • Department/location-specific holidays
  • Bulk import from CSV/JSON
  • Automatic integration with TAT calculations
  • Year-based calendar view

🎯 How It Works

For STANDARD Priority:

Working Days = Monday-Friday (excluding weekends AND holidays)
TAT Calculation = Skips Saturdays, Sundays, AND holidays

For EXPRESS Priority:

Calendar Days = All days (including weekends and holidays)
TAT Calculation = Continuous (no skipping)

📊 Database Schema

Holidays Table:

CREATE TABLE holidays (
  holiday_id UUID PRIMARY KEY,
  holiday_date DATE NOT NULL UNIQUE,
  holiday_name VARCHAR(200) NOT NULL,
  description TEXT,
  is_recurring BOOLEAN DEFAULT false,
  recurrence_rule VARCHAR(100),  -- For annual recurring
  holiday_type ENUM('NATIONAL', 'REGIONAL', 'ORGANIZATIONAL', 'OPTIONAL'),
  is_active BOOLEAN DEFAULT true,
  applies_to_departments TEXT[],  -- NULL = all departments
  applies_to_locations TEXT[],    -- NULL = all locations
  created_by UUID REFERENCES users(user_id),
  updated_by UUID REFERENCES users(user_id),
  created_at TIMESTAMP,
  updated_at TIMESTAMP
);

🔌 API Endpoints

1. Get All Holidays

GET /api/admin/holidays?year=2025

Response:

{
  "success": true,
  "data": [
    {
      "holidayId": "...",
      "holidayDate": "2025-01-26",
      "holidayName": "Republic Day",
      "description": "Indian Republic Day",
      "holidayType": "NATIONAL",
      "isRecurring": true,
      "isActive": true
    }
  ],
  "count": 15
}

2. Get Holiday Calendar for Year

GET /api/admin/holidays/calendar/2025

Response:

{
  "success": true,
  "year": 2025,
  "holidays": [
    {
      "date": "2025-01-26",
      "name": "Republic Day",
      "description": "...",
      "type": "NATIONAL",
      "isRecurring": true
    }
  ]
}

3. Create Holiday

POST /api/admin/holidays
Content-Type: application/json

{
  "holidayDate": "2025-10-02",
  "holidayName": "Gandhi Jayanti",
  "description": "Mahatma Gandhi's Birthday",
  "holidayType": "NATIONAL",
  "isRecurring": true,
  "recurrenceRule": "FREQ=YEARLY;BYMONTH=10;BYMONTHDAY=2"
}

4. Update Holiday

PUT /api/admin/holidays/:holidayId
Content-Type: application/json

{
  "holidayName": "Updated Name",
  "description": "Updated description"
}

5. Delete Holiday

DELETE /api/admin/holidays/:holidayId

6. Bulk Import Holidays

POST /api/admin/holidays/bulk-import
Content-Type: application/json

{
  "holidays": [
    {
      "holidayDate": "2025-01-26",
      "holidayName": "Republic Day",
      "holidayType": "NATIONAL"
    },
    {
      "holidayDate": "2025-08-15",
      "holidayName": "Independence Day",
      "holidayType": "NATIONAL"
    }
  ]
}

🎨 Frontend Implementation (Future)

Holiday Management Page:

// Admin Dashboard → Settings → Holiday Calendar

<HolidayCalendar>
  <YearSelector currentYear={2025} />
  
  <CalendarView>
    {/* Visual calendar showing all holidays */}
    <Day date="2025-01-26" isHoliday>
      Republic Day
    </Day>
  </CalendarView>
  
  <HolidayList>
    {/* List view with add/edit/delete */}
    <HolidayCard>
      📅 Jan 26, 2025 - Republic Day
      <Actions>
        <EditButton />
        <DeleteButton />
      </Actions>
    </HolidayCard>
  </HolidayList>
  
  <AddHolidayButton onClick={openModal} />
  <BulkImportButton onClick={openImportDialog} />
</HolidayCalendar>

📝 Sample Holidays Data

Indian National Holidays 2025:

[
  { "date": "2025-01-26", "name": "Republic Day", "type": "NATIONAL" },
  { "date": "2025-03-14", "name": "Holi", "type": "NATIONAL" },
  { "date": "2025-03-30", "name": "Ram Navami", "type": "NATIONAL" },
  { "date": "2025-04-10", "name": "Mahavir Jayanti", "type": "NATIONAL" },
  { "date": "2025-04-14", "name": "Ambedkar Jayanti", "type": "NATIONAL" },
  { "date": "2025-04-18", "name": "Good Friday", "type": "NATIONAL" },
  { "date": "2025-05-01", "name": "May Day", "type": "NATIONAL" },
  { "date": "2025-08-15", "name": "Independence Day", "type": "NATIONAL" },
  { "date": "2025-08-27", "name": "Janmashtami", "type": "NATIONAL" },
  { "date": "2025-10-02", "name": "Gandhi Jayanti", "type": "NATIONAL" },
  { "date": "2025-10-22", "name": "Dussehra", "type": "NATIONAL" },
  { "date": "2025-11-01", "name": "Diwali", "type": "NATIONAL" },
  { "date": "2025-11-05", "name": "Guru Nanak Jayanti", "type": "NATIONAL" },
  { "date": "2025-12-25", "name": "Christmas", "type": "NATIONAL" }
]

🔄 TAT Calculation Integration

How Holidays Affect TAT:

Example: 48-hour TAT for STANDARD priority

Without Holidays:

Submit: Monday 10:00 AM
Due: Wednesday 10:00 AM (48 working hours, skipping weekend)

With Holiday (Tuesday is holiday):

Submit: Monday 10:00 AM
Holiday: Tuesday (skipped)
Due: Thursday 10:00 AM (48 working hours, skipping Tuesday AND weekend)

TAT Calculation Logic:

// For STANDARD priority:
1. Start from submission time
2. Add hours one by one
3. Skip if:
   - Weekend (Saturday/Sunday)
   - Outside working hours (before 9 AM or after 6 PM)
   - Holiday (from holidays table)
4. Continue until all hours are added

🏗️ Architecture

Holiday Cache System:

Server Startup
  ↓
Load holidays from database
  ↓
Cache in memory (Set of dates)
  ↓
Cache expires after 6 hours
  ↓
Reload automatically

Benefits:

  • Fast lookups (no DB query for each hour)
  • Automatic refresh
  • Minimal memory footprint

TAT Calculation Flow:

calculateTatMilestones()
  ↓
addWorkingHours()
  ↓
loadHolidaysCache() (if expired)
  ↓
For each hour:
  isWorkingTime()
    ├─ Check weekend? → Skip
    ├─ Check working hours? → Skip if outside
    └─ Check holiday? → Skip if holiday
  ↓
Return calculated date

📋 Admin Configuration

Admin Can Configure:

Config Area Options Default
TAT Settings Default TAT hours (Express/Standard) 24h/48h
Reminder thresholds 50%, 75%
Working hours 9 AM - 6 PM
Holidays Add/edit/delete holidays None
Bulk import holidays -
Recurring holidays -
Document Policy Max file size 10 MB
Allowed file types pdf,doc,...
Retention period 365 days
AI Configuration Enable/disable AI remarks Enabled
Max characters 500
Notifications Channels (email/push) All
Frequency Immediate

🧪 Testing Holiday Integration

Test Scenario 1: Add Holiday

# 1. Add a holiday for tomorrow
POST /api/admin/holidays
{
  "holidayDate": "2025-11-05",
  "holidayName": "Test Holiday",
  "holidayType": "ORGANIZATIONAL"
}

# 2. Create request with 24-hour STANDARD TAT
# Expected: Due date should skip the holiday

# 3. Verify TAT calculation excludes the holiday

Test Scenario 2: Recurring Holiday

# 1. Add Independence Day (recurring)
POST /api/admin/holidays
{
  "holidayDate": "2025-08-15",
  "holidayName": "Independence Day",
  "isRecurring": true,
  "recurrenceRule": "FREQ=YEARLY;BYMONTH=8;BYMONTHDAY=15"
}

# 2. Test requests spanning this date

📊 Holiday Statistics API

Get Holiday Count by Type:

SELECT 
  holiday_type,
  COUNT(*) as count
FROM holidays
WHERE is_active = true
  AND EXTRACT(YEAR FROM holiday_date) = 2025
GROUP BY holiday_type;

Get Upcoming Holidays:

SELECT 
  holiday_name,
  holiday_date,
  holiday_type
FROM holidays
WHERE holiday_date >= CURRENT_DATE
  AND holiday_date <= CURRENT_DATE + INTERVAL '90 days'
  AND is_active = true
ORDER BY holiday_date;

🔒 Security

Admin Only Access:

All holiday and configuration management endpoints require:

  1. Valid JWT token (authenticateToken)
  2. Admin role (requireAdmin)

Middleware Chain:

router.use(authenticateToken);  // Must be logged in
router.use(requireAdmin);        // Must be admin

🎓 Best Practices

1. Holiday Naming:

  • Use clear, descriptive names
  • Include year if not recurring
  • Example: "Diwali 2025" or "Independence Day" (recurring)

2. Types:

  • NATIONAL: Applies to entire country
  • REGIONAL: Specific to state/region
  • ORGANIZATIONAL: Company-specific
  • OPTIONAL: Optional holidays (float)

3. Department/Location Specific:

{
  "holidayName": "Regional Holiday",
  "appliesToDepartments": ["Sales", "Marketing"],
  "appliesToLocations": ["Mumbai", "Delhi"]
}

4. Recurring Holidays:

{
  "isRecurring": true,
  "recurrenceRule": "FREQ=YEARLY;BYMONTH=8;BYMONTHDAY=15"
}

🚀 Deployment

Initial Setup:

  1. Run Migrations:

    npm run migrate
    
  2. Import Indian Holidays:

    curl -X POST http://localhost:5000/api/admin/holidays/bulk-import \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
    -d @sample_holidays_2025.json
    
  3. Verify:

    curl http://localhost:5000/api/admin/holidays?year=2025
    

  • Admin Configuration: See admin configuration tables
  • TAT Calculation: See TAT_NOTIFICATION_SYSTEM.md
  • API Reference: See API documentation

Last Updated: November 4, 2025
Version: 1.0.0
Team: Royal Enfield Workflow