Files

70 lines
4.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const cache = require('../cache');
async function getRetailData() {
const regions = [
{ region: 'Noord-Holland', index: 108.2, yoy: 2.1, stores: 8420, onlineShare: 34, footfall: 112 },
{ region: 'Zuid-Holland', index: 105.6, yoy: 1.4, stores: 7100, onlineShare: 31, footfall: 105 },
{ region: 'Noord-Brabant', index: 103.1, yoy: 0.8, stores: 5200, onlineShare: 28, footfall: 98 },
{ region: 'Gelderland', index: 101.4, yoy: 0.3, stores: 3800, onlineShare: 26, footfall: 94 },
{ region: 'Utrecht', index: 106.8, yoy: 1.9, stores: 2900, onlineShare: 36, footfall: 108 },
{ region: 'Limburg', index: 99.2, yoy: -0.4, stores: 2100, onlineShare: 24, footfall: 88 },
{ region: 'Overijssel', index: 100.5, yoy: 0.5, stores: 2400, onlineShare: 25, footfall: 91 },
{ region: 'Groningen', index: 98.7, yoy: -0.2, stores: 1200, onlineShare: 22, footfall: 85 }
];
const history = ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'].map((month, i) => ({
month, index: +(100 + Math.sin(i / 2) * 3 + i * 0.15).toFixed(1),
online: +(28 + i * 0.8 + Math.sin(i) * 2).toFixed(1),
footfall: +(95 + Math.cos(i / 2) * 8).toFixed(1)
}));
const categories = [
{ name: 'Supermarkt', share: 32, growth: 1.2 },
{ name: 'Mode', share: 18, growth: -0.8 },
{ name: 'Elektronica', share: 14, growth: 2.4 },
{ name: 'Bouwmarkt', share: 12, growth: 0.5 },
{ name: 'E-commerce', share: 24, growth: 8.2 }
];
const scatter = regions.map(r => ({
region: r.region, stores: r.stores, index: r.index, yoy: r.yoy
}));
const sorted = regions.sort((a, b) => b.index - a.index);
const insights = [
{ type: 'ok', label: 'Groei', text: 'Noord-Holland leidt met index 108 — combineer CBS-data met footfall sensoren voor locatiekeuze.' },
{ type: 'warn', label: 'Druk', text: 'Limburg negatief YoY — gerichte promoties en regionale voorraadoptimalisatie.' },
{ type: 'info', label: 'Omnichannel', text: 'Online share stijgt ~0.8%/maand — dashboard koppelt winkel + web in één view.' },
{ type: 'info', label: 'Footfall', text: `Gem. footfall index ${Math.round(sorted.reduce((a, r) => a + r.footfall, 0) / sorted.length)} — piek in Randstad.` },
{ type: 'warn', label: 'Mode', text: 'Mode categorie 0.8% — herbalanceer assortiment vs elektronica (+2.4%).' },
{ type: 'ok', label: 'Actie', text: 'Scatter-analyse toont waar winkeldichtheid vs index outlier is — expansion ready.' }
];
const contextBlocks = [
{ title: 'Waarom Retail Command Center?', body: 'Retailers moeten snel zien waar omzet groeit, footfall daalt en online kanibaliseert — per regio, categorie en kanaal.' },
{ title: 'Wat u hier ziet', body: 'Regionale omzetindices, categorie mix, 12-maanden trend, footfall vs online — live refresh elke 2 seconden.' },
{ title: 'Technische aanpak Mek-Tech', body: 'CBS StatLine + footfall API + eigen geo-lagen. SSE stream naar browser zonder zware BI stack.' },
{ title: 'ROI voor uw organisatie', body: 'Betere locatiekeuze (15% mislukte openings), snellere category decisions, omnichannel alignment.' },
{ title: 'Productie-architectuur', body: 'Data warehouse + footfall sensors → Kafka → dit dashboard. Store-level drill-down optioneel.' },
{ title: 'Volgende stap', body: 'Pilot met 3 regios + eigen winkeldata overlay — dashboard op maat binnen 34 weken.' }
];
return {
ts: new Date().toISOString(),
refreshMs: 2000,
nationalIndex: 104.3, nationalYoy: 1.2,
regions: sorted,
history, categories, scatter, insights, contextBlocks,
totalStores: regions.reduce((a, r) => a + r.stores, 0),
avgOnlineShare: +(regions.reduce((a, r) => a + r.onlineShare, 0) / regions.length).toFixed(1),
avgFootfall: Math.round(sorted.reduce((a, r) => a + r.footfall, 0) / sorted.length),
storesAtRisk: sorted.filter(r => r.yoy < 0).length,
context: {
pitch: 'Global Retail Operations — regio-intelligence, omnichannel & footfall live.',
deployment: 'CBS StatLine · OpenStreetMap · Footfall API'
}
};
}
module.exports = { getRetailData };