feat(feeds): ECB reference FX rates seeder (#2280) (#2337)

* feat(feeds): ECB daily reference FX rates seeder -- EUR/USD/GBP/JPY/CHF (#2280)

- New scripts/seed-ecb-fx-rates.mjs: fetches EUR/USD/GBP/JPY/CHF/CAD/AUD/CNY daily from ECB Data Portal (no API key required)
- New getEcbFxRates RPC in economic service (proto + handler + gateway slow tier)
- api/health.js: ecbFxRates in BOOTSTRAP_KEYS + SEED_META (2880min maxStale)
- api/bootstrap.js: ecbFxRates registered as SLOW_KEYS bootstrap entry
- TTL: 259200s (3x daily interval), isMain guard, CHROME_UA, validate>=3 pairs

* fix(feeds): register ecbFxRates in cache-keys.ts + add frontend hydration consumer

* fix(ecb-fx-rates): use dynamic CURRENCY dim position in series key parsing

CURRENCY is at index 1 in EXR series keys (FREQ:CURRENCY:CURRENCY_DENOM:EXR_TYPE:EXR_SUFFIX).
Using hardcoded keyParts[0] always read the FREQ field (always "0"), so all
series resolved to currencyCodes[0] (AUD) and only 1 pair was written to Redis
instead of all 7. Fix: find CURRENCY position via findIndex() and use
keyParts[currencyDimPos] to extract the correct per-series currency index.

* fix(feeds): hoist obs-dimension lookup + fix ECB UTC publication time

- Hoist obsPeriods/timeDim/timeValues above the series loop (loop-invariant, P2)
- Fix updatedAt timestamp: ECB publishes at 16:00 CET = 14:00 UTC (not 16:00 UTC), use T14:00:00Z (P2)

* chore(generated): fix EcbFxRate schema ordering in EconomicService openapi.json

buf generate places EcbFxRate alphabetically before EconomicEvent; align
committed file with code-generator output so proto freshness hook passes.
This commit is contained in:
Elie Habib
2026-03-27 10:11:47 +04:00
committed by GitHub
parent 8f74288b01
commit b5faffb341
14 changed files with 418 additions and 1 deletions

File diff suppressed because one or more lines are too long