Website : rimsha.abasa.com
backdoor
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
var
/
www
/
mudeerapi.abasa.com
/
nodetest
/
Filename :
REDIS_CACHING_STRATEGY.md
back
Copy
# Redis Caching Strategy for Mudeer Backend ## Overview This document outlines a comprehensive Redis caching strategy for all APIs, organized by priority based on query frequency, data size, and staleness tolerance. --- ## 🔴 **Priority 1: CRITICAL (High Impact)** ### 1. **Attendance Records - `GET /:user_id/attendance`** - **Current Status**: ✅ Already Implemented - **Cache Key**: `attendance:{user_id}:{sorted_query_params}` - Example: `attendance:507f1f77bcf86cd799439011:date=2024-01|month=2024-01` - **TTL**: `3600s` (1 hour) - **Why Cache**: Complex date-based queries with multiple filtering options (date, month, year, week, date range) - **Invalidate On**: - `POST /attendance` (markAttendance) - `PUT /attendance` (updateAttendance) - `POST /attendance/batch` (massUpdateHoliday) - `POST /attendance/checkout` (attendanceCheckout) - Pattern: `attendance:{user_id}:*` ### 2. **User List - `GET /users`** - **Cache Key**: `users:list:{role}:{department}:{query_params}` - Example: `users:list:admin:all:role=employee` - **TTL**: `300s` (5 minutes) - **Why Cache**: Heavy aggregation pipeline (joins with departments, attendance, userStatus) - **Invalidate On**: - `POST /signup` - `PUT /:id/updateUser` - `POST /attendance` (affects today's attendance status) - `POST /attendance/checkout` - `PUT /fcm-token` - Pattern: `users:list:*` ### 3. **Employee Details - `GET /Employee/:id`** - **Cache Key**: `user:detail:{user_id}` - **TTL**: `300s` (5 minutes) - **Why Cache**: Complex aggregation with multiple lookups (department, attendance, status, eventActivity) - **Invalidate On**: - `PUT /:id/updateUser` - `POST /attendance` (if user_id matches) - `POST /attendance/checkout` (if user_id matches) - `DELETE /user/:id` - Pattern: `user:detail:{user_id}` --- ## 🟠 **Priority 2: HIGH (Medium-High Impact)** ### 4. **Department List - `GET /department/all`** - **Cache Key**: `departments:list:{role}:{department_id}` - Example: `departments:list:admin:all` or `departments:list:department_head:507f1f77bcf86cd799439011` - **TTL**: `600s` (10 minutes) - **Why Cache**: Populated with head and employees (2 joins), relatively static data - **Invalidate On**: - `POST /department/create` - `PUT /department/update` - `DELETE /department/delete/:id` - `PUT /department/add/employee/:id` - `DELETE /department/remove/employee/:id` - `PUT /department/add/head/:id` - `DELETE /department/remove/head/:id` - Pattern: `departments:list:*` ### 5. **Single Department - `GET /department/get/employee/:id`** - **Cache Key**: `department:detail:{department_id}` - **TTL**: `600s` (10 minutes) - **Why Cache**: Populated with full employee and head details - **Invalidate On**: (Same as #4) - Pattern: `department:detail:{department_id}` ### 6. **Event Activity - `GET /:user_id/eventactivity`** - **Cache Key**: `eventactivity:{user_id}:{sorted_query_params}` - Example: `eventactivity:507f1f77bcf86cd799439011:date=2024-01-15|shiftStatus=morning` - **TTL**: `1800s` (30 minutes) - **Why Cache**: Complex grouping logic by date/week/month/year with calculations - **Invalidate On**: - `POST /eventactivity` - Pattern: `eventactivity:{user_id}:*` ### 7. **Active Window - `GET /:user_id/activewindow`** - **Cache Key**: `activewindow:{user_id}:{sorted_query_params}` - Example: `activewindow:507f1f77bcf86cd799439011:month=2024-01|shiftStatus=morning` - **TTL**: `1800s` (30 minutes) - **Why Cache**: Similar complex grouping as event activity - **Invalidate On**: - `POST /activewindow` - Pattern: `activewindow:{user_id}:*` --- ## 🟡 **Priority 3: MEDIUM (Moderate Impact)** ### 8. **Leave Information - `GET /:user_id/leave-info`** - **Cache Key**: `leave:info:{user_id}` - **TTL**: `600s` (10 minutes) - **Why Cache**: Relatively static, changes only when leave is taken/updated - **Invalidate On**: - `POST /attendance` (if status is Paid Leave, Occasional off, Unpaid Leave) - `PUT /attendance` (if changing to/from leave statuses) - `POST /attendance/batch` (if mass setting Occasional off) - Pattern: `leave:info:{user_id}` ### 9. **User Notifications - `GET /notifications`** - **Cache Key**: `notifications:user:{user_id}:page={page}:limit={limit}:isRead={isRead}:type={type}` - **TTL**: `120s` (2 minutes) - **Why Cache**: High read frequency, pagination can be expensive - **Invalidate On**: - `POST /notifications/send` - `POST /notifications/send-multiple` - `POST /notifications/send-department` - `PATCH /notifications/:id/read` - `PATCH /notifications/read-multiple` - `PATCH /notifications/read-all` - `DELETE /notifications/:id` - Pattern: `notifications:user:{user_id}:*` ### 10. **Unread Notification Count - `GET /notifications/unread-count`** - **Cache Key**: `notifications:unread:{user_id}` - **TTL**: `60s` (1 minute) - **Why Cache**: Frequently polled, simple count query - **Invalidate On**: (Same as #9) - Pattern: `notifications:unread:{user_id}` ### 11. **Notification Stats - `GET /notifications/stats`** - **Cache Key**: `notifications:stats:global` - **TTL**: `300s` (5 minutes) - **Why Cache**: Admin dashboard aggregation, doesn't need real-time accuracy - **Invalidate On**: - Any notification creation/deletion - Pattern: `notifications:stats:*` --- ## 🟢 **Priority 4: LOW (Nice to Have)** ### 12. **Password Reset Token** (Session Cache) - **Cache Key**: `password_reset:{email}:{token}` - **TTL**: `600s` (10 minutes - matches JWT expiry) - **Why Cache**: Store token validation state, prevent replay attacks - **Usage**: In `POST /password/reset` - check if token already used - **Invalidate On**: Token used successfully ### 13. **FCM Tokens** (Lookup Cache) - **Cache Key**: `fcm:token:{user_id}` - **TTL**: `86400s` (24 hours) - **Why Cache**: Frequently accessed for push notifications - **Invalidate On**: - `PUT /fcm-token` - Pattern: `fcm:token:{user_id}` --- ## 📊 Cache Key Patterns Summary | Pattern | Purpose | Invalidation Scope | |---------|---------|-------------------| | `attendance:{user_id}:*` | All attendance data for a user | User-specific attendance changes | | `users:list:*` | All user list queries | Any user or attendance update | | `user:detail:{user_id}` | Single user details | Specific user updates | | `departments:list:*` | All department lists | Any department structure change | | `department:detail:{dept_id}` | Single department | Specific department changes | | `eventactivity:{user_id}:*` | User event activity | New events for user | | `activewindow:{user_id}:*` | User active windows | New windows for user | | `leave:info:{user_id}` | User leave balance | Leave status changes | | `notifications:user:{user_id}:*` | User notifications | Notification changes for user | | `notifications:unread:{user_id}` | Unread count | Notification reads/deletes | | `fcm:token:{user_id}` | FCM push token | Token updates | --- ## 🛠️ Implementation Guidelines ### Cache Helper Utility (`src/utils/cacheHelper.js`) ```javascript import { redisClient } from '../db/redis.js'; export const cacheHelper = { // Build consistent cache keys buildKey: (prefix, id, params = {}) => { const sortedParams = Object.keys(params) .sort() .map(k => `${k}=${params[k]}`) .join('|'); return sortedParams ? `${prefix}:${id}:${sortedParams}` : `${prefix}:${id}`; }, // Get from cache get: async (key) => { try { const cached = await redisClient.get(key); return cached ? JSON.parse(cached) : null; } catch (err) { console.warn('Cache read error:', err); return null; } }, // Set to cache set: async (key, data, ttl = 3600) => { try { await redisClient.setEx(key, ttl, JSON.stringify(data)); return true; } catch (err) { console.warn('Cache write error:', err); return false; } }, // Delete by pattern deletePattern: async (pattern) => { try { const keys = await redisClient.keys(pattern); if (keys.length > 0) { await redisClient.del(keys); } return keys.length; } catch (err) { console.warn('Cache delete error:', err); return 0; } }, // Delete specific key delete: async (key) => { try { await redisClient.del(key); return true; } catch (err) { console.warn('Cache delete error:', err); return false; } } }; ``` ### Invalidation Helper (`src/utils/invalidationHelper.js`) ```javascript import { cacheHelper } from './cacheHelper.js'; export const invalidateCache = { // After attendance changes attendance: async (userId) => { await cacheHelper.deletePattern(`attendance:${userId}:*`); await cacheHelper.deletePattern(`users:list:*`); // Affects user list await cacheHelper.delete(`user:detail:${userId}`); await cacheHelper.delete(`leave:info:${userId}`); }, // After user updates user: async (userId) => { await cacheHelper.delete(`user:detail:${userId}`); await cacheHelper.deletePattern(`users:list:*`); }, // After department changes department: async (departmentId = null) => { await cacheHelper.deletePattern(`departments:list:*`); if (departmentId) { await cacheHelper.delete(`department:detail:${departmentId}`); } await cacheHelper.deletePattern(`users:list:*`); // Users have dept info }, // After notification changes notification: async (userId) => { await cacheHelper.deletePattern(`notifications:user:${userId}:*`); await cacheHelper.delete(`notifications:unread:${userId}`); }, // After leave changes leave: async (userId) => { await cacheHelper.delete(`leave:info:${userId}`); } }; ``` --- ## 📈 Expected Performance Gains | API Endpoint | Current Avg Response | With Cache | Improvement | |--------------|---------------------|------------|-------------| | `GET /users` (aggregation) | 800-1200ms | 5-10ms | **~99%** | | `GET /Employee/:id` | 400-600ms | 3-8ms | **~98%** | | `GET /:user_id/attendance` | 300-500ms | 2-5ms | **~99%** | | `GET /department/all` | 200-400ms | 2-5ms | **~98%** | | `GET /:user_id/eventactivity` | 500-800ms | 3-7ms | **~99%** | | `GET /notifications` | 150-250ms | 2-4ms | **~98%** | --- ## ⚠️ Important Considerations 1. **Authorization First**: Always validate user permissions BEFORE checking cache 2. **Graceful Degradation**: App should work even if Redis is down 3. **Cache Versioning**: Add version prefix (`v1:`) to all keys for easy invalidation on schema changes 4. **Monitoring**: Track cache hit rates, TTL effectiveness, and memory usage 5. **Stale Data Risk**: Balance TTL duration with data freshness requirements 6. **Invalidation Complexity**: Cascading invalidations (e.g., user update affects multiple caches) need careful handling --- ## 🎯 Quick Win Recommendations **Implement in this order for maximum ROI:** 1. ✅ Attendance API (already done) 2. 🔥 User List API (`GET /users`) - Highest query frequency + heavy aggregation 3. 🔥 Employee Detail API (`GET /Employee/:id`) 4. 🔥 Department List (`GET /department/all`) 5. Event Activity & Active Window (both similar patterns) 6. Notifications (high frequency but simpler queries) 7. Leave info (lower frequency) **Estimated total implementation time**: 2-3 days for Priority 1-2 endpoints