# Redis/Valkey Caching & Search Implementation ## Overview This implementation adds Redis/Valkey caching and search functionality to the Job-List application, following the same patterns used in Job-Info-Prod. ## Features Implemented ### 1. Redis/Valkey Connection Module (`redis.ts`) **Connection Management:** - Automatic connection to Redis/Valkey using `REDIS_URL` environment variable - Defaults to `redis://localhost:6379` if not configured - Connection pooling and automatic reconnection on failures - Error handling and logging **Cache Operations:** - `getCached(key)` - Retrieve cached data by key - `setCached(key, data, options)` - Store data with TTL (default 5 minutes) - `deleteCached(keyOrPattern)` - Delete cache by key or pattern (supports wildcards) - `invalidateSearchCache()` - Clear all search results cache **Search Operations:** - `cacheSearchResults(query, results, options)` - Cache search results - `getCachedSearchResults(query)` - Retrieve cached search results ### 2. API Endpoints (`server.ts`) #### GET `/api/jobs` **Purpose:** Fetch all job records with Redis caching **Headers:** - `X-PocketBase-Token` - User authentication token (required) **Response:** ```json { "success": true, "data": [...], "cached": true/false } ``` **Caching:** - Cache key: `jobs:all:Job_Info_TestEnv` - TTL: 5 minutes (300 seconds) - Automatically fetches from PocketBase if cache miss #### GET `/api/jobs/search?q=` **Purpose:** Search jobs across multiple fields with caching **Headers:** - `X-PocketBase-Token` - User authentication token (required) **Query Parameters:** - `q` - Search query (required) **Searchable Fields:** - Job_Number - Job_Full_Name - Job_Name - Company_Client - Contact_Person - Estimator - Job_Status - Project_Manager - Notes **Response:** ```json { "success": true, "data": [...], "query": "search term", "cached": true/false } ``` **Caching:** - Cache key: `search:` - TTL: 3 minutes (180 seconds) - Case-insensitive query matching #### POST `/api/cache/clear` **Purpose:** Manually clear all caches (admin/debugging) **Headers:** - `X-PocketBase-Token` - User authentication token (required) **Response:** ```json { "success": true, "message": "Cache cleared successfully" } ``` ### 3. Cache Invalidation **Automatic Cache Clearing:** - When data is submitted via `/api/submit`, all job caches are automatically cleared - Ensures cache consistency with PocketBase data - Clears both job data cache and search result caches **Manual Cache Clearing:** - Use `/api/cache/clear` endpoint for manual cache invalidation ## Configuration ### Environment Variables Add to your `.env` file (or secrets location): ```bash # Redis/Valkey Configuration REDIS_URL=redis://localhost:6379 # For production, connect to the same instance as Job-Info-Prod # REDIS_URL=redis://redis-server:6379 # With authentication: REDIS_URL=redis://:password@redis-server:6379 ``` ### Dependencies Added ```json { "dependencies": { "ioredis": "^5.8.2" }, "devDependencies": { "@types/ioredis": "^5.0.0" } } ``` ## Architecture ``` ┌──────────────┐ │ Frontend │ │ (HTML/JS) │ └──────┬───────┘ │ │ HTTP Requests │ X-PocketBase-Token header │ ┌──────▼────────────────────────────────┐ │ Server (server.ts) │ │ ┌────────────────────────────────┐ │ │ │ 1. Check Redis Cache │ │ │ │ ↓ (if miss) │ │ │ │ 2. Fetch from PocketBase │ │ │ │ ↓ │ │ │ │ 3. Store in Redis Cache │ │ │ │ ↓ │ │ │ │ 4. Return to client │ │ │ └────────────────────────────────┘ │ └───────────┬───────────────────────────┘ │ ├─────────────┬──────────────┐ │ │ │ ┌───────▼──────┐ ┌──▼──────────┐ │ │ Redis/ │ │ PocketBase │ │ │ Valkey │ │ Database │ │ │ (Cache) │ │ (Source) │ │ └──────────────┘ └─────────────┘ │ │ Same Redis instance as Job-Info-Prod ``` ## Cache Strategy ### Read Path 1. Client requests data via `/api/jobs` or `/api/jobs/search` 2. Server checks Redis cache first 3. On cache hit: Return cached data immediately 4. On cache miss: Fetch from PocketBase, cache it, then return ### Write Path 1. Client submits update via `/api/submit` 2. Server updates PocketBase directly 3. Server invalidates all related caches 4. Next read will fetch fresh data from PocketBase and cache it ### Benefits - **Reduced Load:** Minimizes PocketBase queries - **Faster Response:** Cached responses are ~10-100x faster - **Scalability:** Multiple instances can share the same cache - **Consistency:** Cache invalidation ensures data freshness ## Future Migration to Job-Info-Prod The current implementation: - ✅ Uses Redis/Valkey for caching and search - ✅ Keeps PocketBase as source of truth for writes - ✅ Can connect to the same Redis instance as Job-Info-Prod Future migration path: 1. Connect to the same Redis instance used by Job-Info-Prod 2. Implement Redis PubSub or webhooks for real-time cache invalidation 3. Gradually transition writes to Job-Info-Prod backend 4. Eventually use Job-Info-Prod as primary data source ## Testing ### Test Cache Functionality 1. **Test cached reads:** ```bash # First request (cache miss) curl -H "X-PocketBase-Token: YOUR_TOKEN" http://localhost:3025/api/jobs # Second request within 5 minutes (cache hit) curl -H "X-PocketBase-Token: YOUR_TOKEN" http://localhost:3025/api/jobs ``` 2. **Test search:** ```bash # Search for jobs curl -H "X-PocketBase-Token: YOUR_TOKEN" "http://localhost:3025/api/jobs/search?q=Estimating" ``` 3. **Test cache invalidation:** ```bash # Clear cache curl -X POST -H "X-PocketBase-Token: YOUR_TOKEN" http://localhost:3025/api/cache/clear ``` ### Verify Redis Connection ```bash # Check if Redis is running redis-cli ping # Should return: PONG # Monitor Redis operations redis-cli monitor # Then make API requests to see cache operations ``` ## Monitoring Redis operations are logged to console: - "Jobs fetched from cache" - Data served from cache - "Jobs fetched from PocketBase and cached" - Cache miss, data fetched and cached - "Search results fetched from cache" - Search results from cache - "Cache cleared successfully" - Manual cache clear ## Troubleshooting ### Redis Connection Issues If Redis connection fails: 1. Check `REDIS_URL` environment variable 2. Verify Redis/Valkey is running: `redis-cli ping` 3. Check network connectivity to Redis server 4. Review server logs for connection errors ### Cache Not Working If cache doesn't seem to work: 1. Verify Redis is accessible 2. Check server logs for cache errors 3. Try manually clearing cache: `POST /api/cache/clear` 4. Verify TTL values are appropriate for your use case ### Stale Data If seeing stale data: 1. Cache invalidation should happen automatically on updates 2. Manually clear cache if needed 3. Consider reducing TTL values for more frequent updates 4. Check if updates are going through `/api/submit` endpoint