feat(economic): BLS direct integration for CES/LAUMT/ECI series (#2141)

* feat(economic): BLS direct integration for CES/LAUMT/ECI series (#2046)

* fix(bls-series): add isMain guard, series allowlist, and empty-value filter

- Wrap runSeed() in isMain guard (process.argv[1]) to prevent seed
  from executing when the module is imported by tests or other scripts.
  This is the critical codebase-wide pattern documented in MEMORY.md.
- Add KNOWN_SERIES_IDS allowlist in getBlsSeries handler to block
  arbitrary Redis key enumeration via user-supplied series_id values.
- Fix observation filter in seed script: add d.value truthiness check
  so empty strings from null/undefined BLS values do not pass through
  as valid observations alongside the existing dash-value guard.

* fix(bls-series): align TTL, cache tier, and maxStaleMin with gold standard

- CACHE_TTL: 86400 → 259200 (3× daily interval)
- maxStaleMin: 1440 → 2880 (2× daily interval)
- gateway cache tier: static → daily (CDN s-maxage=86400 for daily-seeded data)
- process.exit(1) → process.exit(0)

* feat(economic): surface BLS series in EconomicPanel Labor Market tab

Adds Labor Market tab to EconomicPanel (TODO-088) consuming the BLS
direct integration from PR #2141. Closes issue #2046 UI gap.

- fetchBlsData() in economic service: parallel getBlsSeries calls
  for all 5 series, adapted to FredSeries shape with sparkline data
- EconomicPanel: Labor Market tab with national section (payrolls,
  ECI) and Metro Unemployment sub-section (SF, Boston, NYC)
- Tab hidden gracefully when BLS data unavailable (cron not yet run)
- loadBlsData() wired in data-loader parallel task list
- DataSourceId + data-freshness metadata for bls source
- All 21 locales: laborMarket + metroUnemployment keys

* fix(generated): restore main-compatible generated files with BLS additions

* fix(generated): correct indentation from manual merge
This commit is contained in:
Elie Habib
2026-03-23 22:40:20 +04:00
committed by GitHub
parent 261d40dfa1
commit bbffbd6998
37 changed files with 643 additions and 4 deletions

View File

@@ -417,6 +417,46 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/get-bls-series:
get:
tags:
- EconomicService
summary: GetBlsSeries
description: GetBlsSeries retrieves BLS-only series not available on FRED (CES, LAUMT, CIU).
operationId: GetBlsSeries
parameters:
- name: series_id
in: query
description: BLS series ID (e.g. "CES0500000001", "CIU1010000000000A").
required: false
schema:
type: string
- name: limit
in: query
description: Maximum number of observations to return. Defaults to 60.
required: false
schema:
type: integer
format: int32
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetBlsSeriesResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Error:
@@ -1230,3 +1270,53 @@ components:
format: double
observedAt:
type: string
GetBlsSeriesRequest:
type: object
properties:
seriesId:
type: string
description: BLS series ID (e.g. "CES0500000001", "CIU1010000000000A").
limit:
type: integer
format: int32
description: Maximum number of observations to return. Defaults to 60.
description: GetBlsSeriesRequest specifies which BLS series to retrieve.
GetBlsSeriesResponse:
type: object
properties:
series:
$ref: '#/components/schemas/BlsSeries'
description: GetBlsSeriesResponse contains the requested BLS series data.
BlsSeries:
type: object
properties:
seriesId:
type: string
description: BLS series ID (e.g. "CES0500000001").
title:
type: string
description: Human-readable series title.
units:
type: string
description: Unit of measure.
observations:
type: array
items:
$ref: '#/components/schemas/BlsObservation'
description: BlsSeries is a BLS time series with metadata and observations.
BlsObservation:
type: object
properties:
year:
type: string
description: Year of the observation.
period:
type: string
description: Period code (e.g. "M01" for January, "A01" for annual).
periodName:
type: string
description: Human-readable period name.
value:
type: string
description: Observed value.
description: BlsObservation is a single BLS data point.