Files
mek-tech-showcase/server/lib/sources/fraud.js
T

117 lines
5.2 KiB
JavaScript

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 };