mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-26 01:24:59 +02:00
feat(energy): days of cover global view (Phase 4 PR B) (#2767)
* feat(energy): days of cover analysis key + EnergyComplexPanel oil stocks section - seed-iea-oil-stocks.mjs exports buildOilStocksAnalysis and writes energy:oil-stocks-analysis:v1 via afterPublish hook after main index - Rankings sorted by daysOfCover desc (net-exporters last), vsObligation, obligationMet, regional summaries (Europe/Asia-Pacific/North America) - EnergyComplexPanel.setOilStocksAnalysis() renders IEA member table with below-obligation badges, rank, days vs 90d obligation, regional summary rows - Health monitoring: seed-meta:energy:oil-stocks-analysis (42d maxStaleMin) - Gateway cache tier: static (monthly seed data) - 13 new tests covering sorting, exclusions, regional rollups, obligation logic * feat(energy): add proto + regenerate service for oil stocks analysis RPC - Add get_oil_stocks_analysis.proto with OilStocksAnalysisMember, OilStocksRegionalSummary sub-messages, and GetOilStocksAnalysisResponse - Use proto3 optional fields for nullable int32 (daysOfCover, vsObligation, avgDays, minDays) avoiding google.protobuf.wrappers complexity - Regenerate service_client.ts + service_server.ts via make generate - Update handler fallback and panel null-safety guards for optional fields - Regenerated OpenAPI docs include getOilStocksAnalysis endpoint * fix(energy): preserve oil-stocks-analysis TTL via extraKeys; fix seed-meta TTL to exceed health threshold - Move ANALYSIS_KEY into ANALYSIS_EXTRA_KEY in extraKeys so runSeed() extends its TTL on fetch failure or validation skip (was only written in afterPublish, leaving the key unprotected on the sad path) - afterPublish now writes only the seed-meta for ANALYSIS_KEY with a 50-day TTL (Math.max(86400*50, TTL_SECONDS)) — exceeds the health maxStaleMin threshold - Add optional metaTtlSeconds param to writeExtraKeyWithMeta() (backward-compat, defaults to existing 7-day value for all other callers) - Update health.js oilStocksAnalysis maxStaleMin from 42d to 50d to stay below the new seed-meta TTL and avoid false stale/missing reports * fix(energy): preserve seed-meta:oil-stocks-analysis TTL via extraKeys on seeder failure
This commit is contained in:
@@ -728,6 +728,32 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/api/economic/v1/get-oil-stocks-analysis:
|
||||
get:
|
||||
tags:
|
||||
- EconomicService
|
||||
summary: GetOilStocksAnalysis
|
||||
description: GetOilStocksAnalysis retrieves the IEA oil stocks days-of-cover ranking and regional summary.
|
||||
operationId: GetOilStocksAnalysis
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GetOilStocksAnalysisResponse'
|
||||
"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:
|
||||
@@ -1988,3 +2014,112 @@ components:
|
||||
sugar:
|
||||
type: number
|
||||
format: double
|
||||
GetOilStocksAnalysisRequest:
|
||||
type: object
|
||||
description: GetOilStocksAnalysisRequest is empty — returns the latest global analysis snapshot.
|
||||
GetOilStocksAnalysisResponse:
|
||||
type: object
|
||||
properties:
|
||||
updatedAt:
|
||||
type: string
|
||||
description: UTC ISO-8601 timestamp when this analysis was written.
|
||||
dataMonth:
|
||||
type: string
|
||||
description: 'Data month in YYYY-MM format (source: IEA monthly release).'
|
||||
ieaMembers:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/OilStocksAnalysisMember'
|
||||
belowObligation:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: ISO2 codes of countries currently below the 90-day obligation.
|
||||
regionalSummary:
|
||||
$ref: '#/components/schemas/OilStocksRegionalSummary'
|
||||
unavailable:
|
||||
type: boolean
|
||||
description: True when upstream seed data is unavailable (fallback result).
|
||||
description: GetOilStocksAnalysisResponse contains the IEA oil stocks days-of-cover analysis.
|
||||
OilStocksAnalysisMember:
|
||||
type: object
|
||||
properties:
|
||||
iso2:
|
||||
type: string
|
||||
description: ISO 3166-1 alpha-2 country code.
|
||||
daysOfCover:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Days of supply cover (absent when country is a net exporter or data anomaly).
|
||||
netExporter:
|
||||
type: boolean
|
||||
description: True when the country is classified as a net exporter by IEA.
|
||||
belowObligation:
|
||||
type: boolean
|
||||
description: True when days_of_cover < 90 (IEA 90-day obligation threshold).
|
||||
obligationMet:
|
||||
type: boolean
|
||||
description: True when the 90-day obligation is met (net exporters always true).
|
||||
rank:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Rank within the IEA member ranking (1-indexed, net exporters ranked last).
|
||||
vsObligation:
|
||||
type: integer
|
||||
format: int32
|
||||
description: days_of_cover - 90; absent for net exporters.
|
||||
description: OilStocksAnalysisMember holds days-of-cover data and obligation status for one IEA member country.
|
||||
OilStocksRegionalSummary:
|
||||
type: object
|
||||
properties:
|
||||
europe:
|
||||
$ref: '#/components/schemas/OilStocksRegionalSummaryEurope'
|
||||
asiaPacific:
|
||||
$ref: '#/components/schemas/OilStocksRegionalSummaryAsiaPacific'
|
||||
northAmerica:
|
||||
$ref: '#/components/schemas/OilStocksRegionalSummaryNorthAmerica'
|
||||
description: OilStocksRegionalSummary holds regional aggregates for the three IEA regions.
|
||||
OilStocksRegionalSummaryEurope:
|
||||
type: object
|
||||
properties:
|
||||
avgDays:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Mean days of cover across non-net-exporter European members.
|
||||
minDays:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Minimum days of cover across non-net-exporter European members.
|
||||
countBelowObligation:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Count of European members below the 90-day obligation.
|
||||
description: OilStocksRegionalSummaryEurope aggregates days-of-cover for European IEA members.
|
||||
OilStocksRegionalSummaryAsiaPacific:
|
||||
type: object
|
||||
properties:
|
||||
avgDays:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Mean days of cover across Asia-Pacific members (AU, JP, KR, NZ).
|
||||
minDays:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Minimum days of cover across Asia-Pacific members.
|
||||
countBelowObligation:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Count of Asia-Pacific members below the 90-day obligation.
|
||||
description: OilStocksRegionalSummaryAsiaPacific aggregates days-of-cover for Asia-Pacific IEA members.
|
||||
OilStocksRegionalSummaryNorthAmerica:
|
||||
type: object
|
||||
properties:
|
||||
netExporters:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Count of net exporters in North America (CA, MX, US).
|
||||
avgDays:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Average days of cover for non-exporter North American members (if any).
|
||||
description: OilStocksRegionalSummaryNorthAmerica aggregates data for North American IEA members.
|
||||
|
||||
Reference in New Issue
Block a user