feat(economic): Economic Stress Composite Index panel (FRED 6-series, 0-100 score) (#2461)

* feat(economic): Economic Stress Composite Index panel (FRED 6-series, 0-100 score)

- Add T10Y3M and STLFSI4 to FRED_SERIES in seed-economy.mjs and ALLOWED_SERIES
- Create proto message GetEconomicStressResponse with EconomicStressComponent
- Register GetEconomicStress RPC in EconomicService (GET /api/economic/v1/get-economic-stress)
- Add seed-economic-stress.mjs: reads 6 pre-seeded FRED keys via Redis pipeline, computes weighted composite score (0-100) with labels Low/Moderate/Elevated/Severe/Critical
- Create server handler get-economic-stress.ts reading from economic:stress-index:v1
- Register economicStress in BOOTSTRAP_CACHE_KEYS (both cache-keys.ts and api/bootstrap.js) as slow tier
- Add gateway.ts cache tier entry (slow) for new RPC route
- Create EconomicStressPanel.ts: composite score header, gradient needle bar, 2x3 component grid with score bars, desktop notification on threshold cross (>=70, >=85)
- Wire economic-stress panel in panels.ts (all 4 variants), panel-layout.ts, and data-loader.ts
- Regenerate OpenAPI docs and TypeScript client/server types

* fix(economic-stress): null for missing FRED data + tech variant panel

- Add 'economic-stress' panel to TECH_PANELS defaults (was missing, only appeared in full/finance/commodity variants)
- Seed: write rawValue: null + missing: true when no valid FRED observation found, preventing zero-valued yield curve/bank spread readings from being conflated with missing data
- Proto: add missing bool field to EconomicStressComponent message; regenerate client/server types + OpenAPI docs
- Server handler: propagate missing flag from Redis; pass rawValue: 0 on wire when missing to satisfy proto double type
- Panel: guard on c.missing (not rawValue === 0) to show grey N/A card with no score bar for unavailable components

* fix(economic-stress): add purple Critical zone to gradient bar

Update gradient stops to match the 5 equal tier boundaries (0-20-40-60-80-100),
adding the #8e44ad purple stop at 80% so scores 80-100 render as Critical purple
instead of plain red.
This commit is contained in:
Elie Habib
2026-03-29 11:19:35 +04:00
committed by GitHub
parent ba54dc12d7
commit aa3e84f0ab
18 changed files with 644 additions and 2 deletions

File diff suppressed because one or more lines are too long