9.9 KiB
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:
- ✅ Valid JWT token (
authenticateToken) - ✅ 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:
-
Run Migrations:
npm run migrate -
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 -
Verify:
curl http://localhost:5000/api/admin/holidays?year=2025
📚 Related Documentation
- 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