const cache = require('../cache'); const SANCTIONS_NAMES = [ 'IVANOV PETR', 'KIM JONG UN', 'RODRIGUEZ CARLOS', 'AL-RASHID OMAR', 'PETROV SERGEI', 'WANG WEI', 'MULLER HANS', 'SILVA ANA', 'NAKAMURA YUKI', 'PETROVA ANNA' ]; let txCounter = 0; const hitsTimeline = []; const riskBuckets = { low: 0, medium: 0, high: 0, critical: 0 }; async function loadSanctions() { const cached = cache.get('sanctions-list', 24 * 60 * 60 * 1000); if (cached) return cached; const list = SANCTIONS_NAMES.map((name, i) => ({ id: i + 1, name, list: 'EU Consolidated', country: ['RU', 'KP', 'VE', 'SY', 'RU', 'CN', 'DE', 'BR', 'JP', 'RU'][i] })); cache.set('sanctions-list', list); return list; } function generateTx(sanctions) { txCounter++; const hit = Math.random() < 0.09; const name = hit ? sanctions[Math.floor(Math.random() * sanctions.length)].name : `CUSTOMER ${Math.floor(Math.random() * 9000 + 1000)}`; const amount = +(Math.random() * 50000 + 100).toFixed(2); const risk = hit ? Math.round(85 + Math.random() * 15) : Math.round(Math.random() * 55); if (risk < 25) riskBuckets.low++; else if (risk < 50) riskBuckets.medium++; else if (risk < 75) riskBuckets.high++; else riskBuckets.critical++; const tx = { id: `TX-${Date.now()}-${txCounter}`, name, amount, currency: ['EUR', 'USD', 'GBP'][Math.floor(Math.random() * 3)], country: ['NL', 'DE', 'BE', 'FR', 'UK', 'US', 'RU', 'CN'][Math.floor(Math.random() * 8)], risk, hit, type: ['SEPA', 'SWIFT', 'CARD', 'CRYPTO'][Math.floor(Math.random() * 4)], ts: new Date().toISOString() }; return tx; } async function getFraudSnapshot() { const sanctions = await loadSanctions(); const recent = Array.from({ length: 25 }, () => generateTx(sanctions)); const hits = recent.filter(t => t.hit).length; hitsTimeline.push({ t: new Date().toISOString().slice(11, 19), hits, screened: recent.length }); if (hitsTimeline.length > 30) hitsTimeline.shift(); const countryRisk = ['NL', 'DE', 'BE', 'FR', 'UK', 'US', 'RU', 'CN'].map(c => ({ country: c, txs: Math.round(50 + Math.random() * 200), hits: c === 'RU' || c === 'CN' ? Math.round(3 + Math.random() * 8) : Math.round(Math.random() * 2) })); const riskDistribution = [ { name: 'Laag', value: riskBuckets.low || 120, fill: '#22c55e' }, { name: 'Medium', value: riskBuckets.medium || 80, fill: '#f59e0b' }, { name: 'Hoog', value: riskBuckets.high || 40, fill: '#f97316' }, { name: 'Kritiek', value: riskBuckets.critical || 15, fill: '#ef4444' } ]; const typeBreakdown = [ { type: 'SEPA', blocked: Math.round(Math.random() * 5), cleared: 420 }, { type: 'SWIFT', blocked: Math.round(Math.random() * 8), cleared: 180 }, { type: 'CARD', blocked: Math.round(Math.random() * 12), cleared: 890 }, { type: 'CRYPTO', blocked: Math.round(Math.random() * 15), cleared: 65 } ]; const insights = [ { type: 'warn', label: 'Compliance', text: `${sanctions.length} entiteiten op EU-lijst — elke tx gescored in <20ms.` }, { type: 'info', label: 'ML', text: 'Velocity + geo-mismatch rules vangen 94% demo-anomalies — uitbreidbaar met eigen modellen.' }, { type: 'ok', label: 'Audit', text: 'Volledige audit trail exporteerbaar voor DNB/AFM toezicht.' }, { type: 'warn', label: 'Hits', text: `${hits} hits in huidige batch — RU/CN geo-risico geconcentreerd.` }, { type: 'info', label: 'Throughput', text: `${1240 + Math.floor(Math.random() * 50)} tx/min — SSE stream elke 1,5s.` }, { type: 'ok', label: 'Actie', text: 'False-positive review queue koppelbaar — zelfde Global Ops UI als treasury & retail.' } ]; const contextBlocks = [ { title: 'Waarom Fraud Command Center?', body: 'Financiële instellingen moeten sancties, PEP en anomalies combineren — realtime, auditable, zonder vendor lock-in.' }, { title: 'Wat u hier ziet', body: 'Live tx stream, sanctions hits, risk verdeling, geo-risico en type breakdown — refresh elke 1,5 seconden.' }, { title: 'Technische aanpak Mek-Tech', body: 'EU Consolidated List + rule engine + SSE. ML models plug-in ready. Geen opslag van demo-tx.' }, { title: 'ROI voor uw organisatie', body: 'Snellere compliance response, lagere false-positive kosten, audit-ready logging.' }, { title: 'Productie-architectuur', body: 'Payment gateway → screening service → Kafka audit log → dit dashboard + case management.' }, { title: 'Volgende stap', body: 'Pilot met echte sanctions feed + 3 custom rules — productie POC binnen 3 weken.' } ]; return { ts: new Date().toISOString(), refreshMs: 1500, sanctionsCount: sanctions.length, recent, hitsLastMinute: hits, hitsTimeline: [...hitsTimeline], countryRisk, riskDistribution, typeBreakdown, avgLatencyMs: Math.round(12 + Math.random() * 8), screeningRate: 1240 + Math.floor(Math.random() * 50), blockRate: +(hits / recent.length * 100).toFixed(2), insights, contextBlocks, criticalCount: recent.filter(t => t.risk > 85).length, context: { pitch: 'Global Fraud & Compliance Operations — sanctions screening live.', deployment: 'EU Consolidated List · OpenSanctions · ECB Payment Stats' } }; } module.exports = { getFraudSnapshot, generateTx, loadSanctions };