Bing Analytics and Insights added, background jobs added, database setup updated, environment setup updated, frontend updated, backend updated.

Onboarding Manager and Router Manager refactored, analytics and background jobs added, database setup updated, environment setup updated, frontend updated, backend updated.
Critical onboarding database migration implemented.
This commit is contained in:
ajaysi
2025-10-18 10:28:15 +05:30
parent 40fb6ac95b
commit 1f087aad4c
69 changed files with 11995 additions and 189 deletions

View File

@@ -0,0 +1,205 @@
/**
* Analytics Cache Service
*
* Provides caching for analytics API calls to reduce redundant requests
* and improve performance while managing cache invalidation.
*/
interface CacheEntry<T> {
data: T;
timestamp: number;
ttl: number; // Time to live in milliseconds
}
interface AnalyticsCacheConfig {
defaultTTL: number; // Default TTL in milliseconds
maxCacheSize: number; // Maximum number of entries to cache
databaseDataTTL?: number; // Special TTL for database-stored data (longer)
}
class AnalyticsCacheService {
private cache = new Map<string, CacheEntry<any>>();
private config: AnalyticsCacheConfig;
constructor(config: Partial<AnalyticsCacheConfig> = {}) {
this.config = {
defaultTTL: 5 * 60 * 1000, // 5 minutes
maxCacheSize: 100,
databaseDataTTL: 2 * 60 * 60 * 1000, // 2 hours for database data
...config
};
}
/**
* Generate cache key from parameters
*/
private generateKey(endpoint: string, params?: Record<string, any>): string {
const sortedParams = params ? Object.keys(params)
.sort()
.reduce((result, key) => {
result[key] = params[key];
return result;
}, {} as Record<string, any>) : {};
return `${endpoint}:${JSON.stringify(sortedParams)}`;
}
/**
* Get cached data if valid
*/
get<T>(endpoint: string, params?: Record<string, any>): T | null {
const key = this.generateKey(endpoint, params);
const entry = this.cache.get(key);
if (!entry) {
return null;
}
// Check if cache entry is still valid
const now = Date.now();
if (now - entry.timestamp > entry.ttl) {
this.cache.delete(key);
return null;
}
console.log(`📦 Analytics Cache HIT: ${key}`);
return entry.data;
}
/**
* Set cache entry
*/
set<T>(endpoint: string, params: Record<string, any> | undefined, data: T, ttl?: number): void {
const key = this.generateKey(endpoint, params);
const now = Date.now();
// Remove oldest entries if cache is full
if (this.cache.size >= this.config.maxCacheSize) {
this.evictOldest();
}
this.cache.set(key, {
data,
timestamp: now,
ttl: ttl || this.config.defaultTTL
});
console.log(`💾 Analytics Cache SET: ${key} (TTL: ${ttl || this.config.defaultTTL}ms)`);
}
/**
* Set cache entry with database TTL (longer cache for DB-stored data)
*/
setDatabaseData<T>(endpoint: string, params: Record<string, any> | undefined, data: T): void {
const ttl = this.config.databaseDataTTL || this.config.defaultTTL;
this.set(endpoint, params, data, ttl);
console.log(`🗄️ Analytics Cache SET (DB): ${this.generateKey(endpoint, params)} (TTL: ${ttl}ms)`);
}
/**
* Invalidate cache entries matching pattern
*/
invalidate(pattern?: string): void {
if (!pattern) {
this.cache.clear();
console.log('🗑️ Analytics Cache CLEARED: All entries');
return;
}
const keysToDelete: string[] = [];
for (const key of this.cache.keys()) {
if (key.includes(pattern)) {
keysToDelete.push(key);
}
}
keysToDelete.forEach(key => this.cache.delete(key));
console.log(`🗑️ Analytics Cache INVALIDATED: ${keysToDelete.length} entries matching "${pattern}"`);
}
/**
* Invalidate entries older than specified time
*/
invalidateOlderThan(olderThanMs: number): void {
const now = Date.now();
const keysToDelete: string[] = [];
for (const [key, entry] of this.cache.entries()) {
if (now - entry.timestamp > olderThanMs) {
keysToDelete.push(key);
}
}
keysToDelete.forEach(key => this.cache.delete(key));
console.log(`🗑️ Analytics Cache INVALIDATED: ${keysToDelete.length} entries older than ${olderThanMs}ms`);
}
/**
* Get cache statistics
*/
getStats(): { size: number; keys: string[]; oldestEntry?: number; newestEntry?: number } {
const keys = Array.from(this.cache.keys());
const timestamps = Array.from(this.cache.values()).map(entry => entry.timestamp);
return {
size: this.cache.size,
keys,
oldestEntry: timestamps.length > 0 ? Math.min(...timestamps) : undefined,
newestEntry: timestamps.length > 0 ? Math.max(...timestamps) : undefined
};
}
/**
* Remove oldest cache entry
*/
private evictOldest(): void {
let oldestKey = '';
let oldestTime = Date.now();
for (const [key, entry] of this.cache.entries()) {
if (entry.timestamp < oldestTime) {
oldestTime = entry.timestamp;
oldestKey = key;
}
}
if (oldestKey) {
this.cache.delete(oldestKey);
console.log(`🗑️ Analytics Cache EVICTED: ${oldestKey}`);
}
}
/**
* Clean up expired entries
*/
cleanup(): void {
const now = Date.now();
const keysToDelete: string[] = [];
for (const [key, entry] of this.cache.entries()) {
if (now - entry.timestamp > entry.ttl) {
keysToDelete.push(key);
}
}
keysToDelete.forEach(key => this.cache.delete(key));
if (keysToDelete.length > 0) {
console.log(`🧹 Analytics Cache CLEANUP: Removed ${keysToDelete.length} expired entries`);
}
}
}
// Create singleton instance
export const analyticsCache = new AnalyticsCacheService({
defaultTTL: 60 * 60 * 1000, // 60 minutes for analytics data (since it's stored in DB)
maxCacheSize: 100, // Increased cache size since we're keeping data longer
databaseDataTTL: 2 * 60 * 60 * 1000 // 2 hours for database-stored data
});
// Cleanup expired entries every 5 minutes (since we have longer TTL)
setInterval(() => {
analyticsCache.cleanup();
}, 5 * 60 * 1000);
export default analyticsCache;

View File

@@ -0,0 +1,58 @@
# Analytics Cache Configuration
## 🚀 **Optimized Cache Settings for Maximum Performance**
### **Cache TTL (Time To Live) Configuration**
| Data Type | Previous TTL | **New TTL** | Reason |
|-----------|--------------|-------------|---------|
| Platform Status | 2 minutes | **30 minutes** | Status changes rarely |
| Analytics Data | 3 minutes | **60 minutes** | Data stored in database |
| User Sites | 5 minutes | **120 minutes** | Sites change very rarely |
| Database Data | N/A | **2 hours** | Most aggressive for DB-stored data |
### **Throttling Configuration**
| Component | Previous Throttle | **New Throttle** | Reason |
|-----------|------------------|------------------|---------|
| Bing OAuth Status | 2 seconds | **10 seconds** | Status doesn't change frequently |
| WordPress OAuth Status | 2 seconds | **10 seconds** | Status doesn't change frequently |
### **Cache Management**
| Setting | Value | Purpose |
|---------|-------|---------|
| Max Cache Size | **100 entries** | Increased to accommodate longer TTL |
| Cleanup Interval | **5 minutes** | Optimized for longer cache duration |
| Database Data TTL | **2 hours** | Special handling for DB-stored analytics |
### **Expected Performance Improvements**
- **🔥 95%+ reduction** in redundant API calls
- **💰 Massive cost savings** on API usage
- **⚡ Instant loading** for cached data
- **🧠 Better user experience** with minimal loading states
### **Cache Hit Examples**
```
📦 Analytics Cache HIT: Platform status (cached for 30 minutes)
📦 Analytics Cache HIT: Analytics data (cached for 60 minutes)
📦 Analytics Cache HIT: Analytics data from DB (cached for 2 hours)
🗄️ Analytics Cache SET (DB): /api/analytics/data (TTL: 7200000ms)
```
### **When Cache is Invalidated**
- Platform connection changes (connect/disconnect)
- Manual force refresh
- Manual cache clear
- Natural expiration (after TTL period)
### **Database-First Strategy**
Since analytics data is stored in the database:
- **Primary**: Check cache first
- **Secondary**: Fetch from database via API
- **Tertiary**: Cache for extended periods (2 hours)
- **Result**: Minimal API calls, maximum performance