Files
tilbudgivern/_archive/DASHBOARD_SYNC_IMPLEMENTATION.md

5.3 KiB

Dashboard Metrics Auto-Sync Implementation

Overview

Dashboard metrics (Nøgletal) er nu konfigureret til at opdateres automatisk hver time gennem det eksisterende sync job.

Architecture

1. Hourly Sync Job (OrdrestyringSyncService)

  • Kører hver time automatisk
  • Synkroniserer: Cases, Users, Hours, Materials, Debtors, Dashboard Metrics
  • Lokalisering: /backend/src/services/ordrestyringSyncService.js

2. Dashboard Metrics Cache

  • Database Table: ordrestyring_local.dashboard_cache
  • Cache Key: noegletal_dashboard_metrics
  • TTL (Time-to-Live): 1 time (selvfølgende med sync interval)
  • Data Size: ~417 bytes
CREATE TABLE dashboard_cache (
  id INT AUTO_INCREMENT PRIMARY KEY,
  cache_key VARCHAR(255) UNIQUE NOT NULL,
  cache_data LONGTEXT NOT NULL,
  expires_at DATETIME NOT NULL,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_cache_key (cache_key),
  INDEX idx_expires_at (expires_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

3. API Endpoint Optimization

  • Route: GET /api/dashboard/noegletal
  • Lokalisering: /backend/unified-server.js (lines 1366-1442)
  • Logik:
    1. Check cache først (hvis valid - return immediately)
    2. Hvis cache invalid/expired → fetch fresh data fra API
    3. Return formatted response

Data Flow

Every Hour:
Ordrestyring GraphQL API 
    ↓
ordrestyringService.calculateDashboardMetrics()
    ↓
ordrestyringSyncService.syncDashboardMetrics()
    ↓
dashboard_cache table (1-hour TTL)

On Frontend Request:
GET /api/dashboard/noegletal
    ↓
Check dashboard_cache first ⚡ (instant)
    ↓
If expired → fetch from API (1.7 sec) 
    ↓
Return to dashboard

Current Metrics Cached

{
  "pendingOffers": 21,
  "currentMonthOffers": 11,
  "currentMonthValue": 785841400,
  "yearToDateOffers": 200,
  "yearToDateValue": 4140316489,
  "statusDistribution": {
    "Nyt tilbud": 1,
    "Sendt": 20,
    "Konverteret": 59,
    "Aflyst": 115,
    "Åben": 3,
    "Opfølgning udført": 2
  },
  "conversionMetrics": {
    "pending": 26,
    "converted": 59,
    "rejected": 115
  },
  "conversionPercentages": {
    "pending": 13,
    "converted": 30,
    "rejected": 57
  },
  "totalOffers": 200
}

Performance Impact

Scenario Response Time Source
Cache Hit ~10-50ms Database cache lookup
Cache Miss ~1700ms Fresh GraphQL query
Hourly Sync ~1600ms Scheduled background job

Implementation Details

Added to ordrestyringSyncService.js

// Lines 139-141: Added to performSync()
this.syncDashboardMetrics() // Cache dashboard metrics hourly

// Lines 583-617: New method
async syncDashboardMetrics() {
  // Queries GraphQL API for metrics
  // Caches result in database_cache table
  // 1-hour expiration
}

Updated /api/dashboard/noegletal endpoint

// Lines 1366-1442
- Try to get cached metrics first
- If cache valid (< 1 hour)  return immediately
- If expired  fetch fresh from GraphQL API
- Always return latest available data

Manual Testing

Trigger sync manually:

node -e "
const OrdrestyringSyncService = require('./backend/src/services/ordrestyringSyncService');
const service = new OrdrestyringSyncService();
service.syncDashboardMetrics().then(result => {
  console.log('Sync result:', result);
  process.exit(0);
});
"

Verify cache:

mysql -h 127.0.0.1 -u tilbudgivern_service -p"${DB_PASSWORD}" ordrestyring_local \
  -e "SELECT cache_key, updated_at, LENGTH(cache_data) as size FROM dashboard_cache;"

Test endpoint:

curl http://localhost:4031/api/dashboard/noegletal | jq '.data'

Monitoring

  • Sync Job Logs: Check PM2 logs for syncDashboardMetrics entries
  • Cache Status: Query dashboard_cache table for expires_at status
  • Performance: Check response times in browser DevTools

Future Enhancements

  1. Adaptive Caching: Adjust TTL based on data change frequency
  2. Metrics Versioning: Track historical metrics trends
  3. Dashboard Notifications: Alert on significant changes (e.g., >10 new offers)
  4. Cache Warming: Pre-warm cache 5 minutes before expiry
  5. Multi-Tenant Support: Cache per-client if needed

Troubleshooting

Dashboard shows old data?

  • Check cache expiry: SELECT expires_at FROM dashboard_cache WHERE cache_key = 'noegletal_dashboard_metrics'
  • If expired, sync job will refresh on next hour
  • Manual sync: Use command above

Cache not updating?

  • Verify sync service is running: pm2 list | grep tilbudgivern
  • Check logs: pm2 logs tilbudgivern-unified --lines 50
  • Verify database connection: mysql ordrestyring_local -e "SHOW TABLES LIKE 'dashboard_cache';"

Slow responses even with cache?

  • Check database load: SHOW PROCESSLIST;
  • Verify GraphQL API status: Test endpoint directly
  • Check network latency to API server
  • Backend Service: /backend/src/services/ordrestyringSyncService.js
  • API Endpoint: /backend/unified-server.js (lines 1366-1442)
  • Frontend Component: /frontend/src/components/NoeglatalDashboard.js
  • Database: ordrestyring_local.dashboard_cache table

Deployment Status

DEPLOYED - November 16, 2025, 20:09 UTC

  • Sync service: Running (every hour)
  • Cache table: Created and functional
  • API endpoint: Updated with cache logic
  • PM2 restart: #73