Files
worldmonitor/docs/api/SupplyChainService.openapi.yaml
Elie Habib a09f49ff9c feat(supply-chain): energy flow estimates per chokepoint (mb/d card row) (#2780)
* feat(supply-chain): energy flow estimates per chokepoint (mb/d card row)

- Add FlowEstimate proto message + ChokepointInfo field 15; regenerate stubs
- Add baselineId mapping to _chokepoint-ids.ts (7 of 13 chokepoints)
- Add relayId to seed-chokepoint-baselines.mjs CHOKEPOINTS entries
- New seed-chokepoint-flows.mjs: reads portwatch + baselines, computes
  7d tanker avg vs 90d baseline, outputs flow_ratio and current_mbd;
  prefers DWT (capTanker) when available; flags disruption if last 3 days
  each below 0.85 threshold; writes energy:chokepoint-flows:v1 (TTL 3d)
- get-chokepoint-status.ts: parallel-reads flows key, attaches flowEstimate
- SupplyChainPanel: compact card gains mb/d row (red <85%, amber <95%)
- 19 new unit tests for flow computation and seeder contract

* fix(chokepoint-flows): base useDwt on 90d baseline window, not recent 7 days

Zero recent capTanker is the disruption signal, not a reason to fall back
to vessel counts. Switching metrics during peak disruption caused the seeder
to report a higher (less accurate) flow estimate exactly when oil-flow
collapse is most acute. useDwt is now locked to whether the baseline window
has DWT data -- stable across disruption events.

Adds regression test covering DWT-collapse scenario.

* fix(chokepoint-flows): require majority DWT coverage in baseline before activating DWT mode

capBaselineSum > 0 would activate DWT on a single non-zero day during
partial data roll-out, pulling down the baseline average via zero-filled
gaps. Now requires >= ceil(prev90.length / 2) days with DWT data.
ArcGIS data is all-or-nothing per chokepoint in practice, so this
guard catches edge cases without affecting normal operation.
2026-04-07 12:43:54 +04:00

446 lines
16 KiB
YAML
Raw 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.
openapi: 3.1.0
info:
title: SupplyChainService API
version: 1.0.0
paths:
/api/supply-chain/v1/get-shipping-rates:
get:
tags:
- SupplyChainService
summary: GetShippingRates
operationId: GetShippingRates
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetShippingRatesResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/supply-chain/v1/get-chokepoint-status:
get:
tags:
- SupplyChainService
summary: GetChokepointStatus
operationId: GetChokepointStatus
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetChokepointStatusResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/supply-chain/v1/get-critical-minerals:
get:
tags:
- SupplyChainService
summary: GetCriticalMinerals
operationId: GetCriticalMinerals
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetCriticalMineralsResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/supply-chain/v1/get-shipping-stress:
get:
tags:
- SupplyChainService
summary: GetShippingStress
description: GetShippingStress returns carrier market data and a composite stress index.
operationId: GetShippingStress
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetShippingStressResponse'
"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:
type: object
properties:
message:
type: string
description: Error message (e.g., 'user not found', 'database connection failed')
description: Error is returned when a handler encounters an error. It contains a simple error message that the developer can customize.
FieldViolation:
type: object
properties:
field:
type: string
description: The field path that failed validation (e.g., 'user.email' for nested fields). For header validation, this will be the header name (e.g., 'X-API-Key')
description:
type: string
description: Human-readable description of the validation violation (e.g., 'must be a valid email address', 'required field missing')
required:
- field
- description
description: FieldViolation describes a single validation error for a specific field.
ValidationError:
type: object
properties:
violations:
type: array
items:
$ref: '#/components/schemas/FieldViolation'
description: List of validation violations
required:
- violations
description: ValidationError is returned when request validation fails. It contains a list of field violations describing what went wrong.
GetShippingRatesRequest:
type: object
GetShippingRatesResponse:
type: object
properties:
indices:
type: array
items:
$ref: '#/components/schemas/ShippingIndex'
fetchedAt:
type: string
upstreamUnavailable:
type: boolean
ShippingIndex:
type: object
properties:
indexId:
type: string
name:
type: string
currentValue:
type: number
format: double
previousValue:
type: number
format: double
changePct:
type: number
format: double
unit:
type: string
history:
type: array
items:
$ref: '#/components/schemas/ShippingRatePoint'
spikeAlert:
type: boolean
ShippingRatePoint:
type: object
properties:
date:
type: string
value:
type: number
format: double
GetChokepointStatusRequest:
type: object
GetChokepointStatusResponse:
type: object
properties:
chokepoints:
type: array
items:
$ref: '#/components/schemas/ChokepointInfo'
fetchedAt:
type: string
upstreamUnavailable:
type: boolean
ChokepointInfo:
type: object
properties:
id:
type: string
name:
type: string
lat:
type: number
format: double
lon:
type: number
format: double
disruptionScore:
type: integer
format: int32
status:
type: string
activeWarnings:
type: integer
format: int32
congestionLevel:
type: string
affectedRoutes:
type: array
items:
type: string
description:
type: string
aisDisruptions:
type: integer
format: int32
directions:
type: array
items:
type: string
directionalDwt:
type: array
items:
$ref: '#/components/schemas/DirectionalDwt'
transitSummary:
$ref: '#/components/schemas/TransitSummary'
flowEstimate:
$ref: '#/components/schemas/FlowEstimate'
DirectionalDwt:
type: object
properties:
direction:
type: string
dwtThousandTonnes:
type: number
format: double
wowChangePct:
type: number
format: double
TransitSummary:
type: object
properties:
todayTotal:
type: integer
format: int32
todayTanker:
type: integer
format: int32
todayCargo:
type: integer
format: int32
todayOther:
type: integer
format: int32
wowChangePct:
type: number
format: double
history:
type: array
items:
$ref: '#/components/schemas/TransitDayCount'
riskLevel:
type: string
incidentCount7d:
type: integer
format: int32
disruptionPct:
type: number
format: double
riskSummary:
type: string
riskReportAction:
type: string
TransitDayCount:
type: object
properties:
date:
type: string
tanker:
type: integer
format: int32
cargo:
type: integer
format: int32
other:
type: integer
format: int32
total:
type: integer
format: int32
container:
type: integer
format: int32
dryBulk:
type: integer
format: int32
generalCargo:
type: integer
format: int32
roro:
type: integer
format: int32
capContainer:
type: number
format: double
capDryBulk:
type: number
format: double
capGeneralCargo:
type: number
format: double
capRoro:
type: number
format: double
capTanker:
type: number
format: double
FlowEstimate:
type: object
properties:
currentMbd:
type: number
format: double
baselineMbd:
type: number
format: double
flowRatio:
type: number
format: double
disrupted:
type: boolean
source:
type: string
hazardAlertLevel:
type: string
hazardAlertName:
type: string
GetCriticalMineralsRequest:
type: object
GetCriticalMineralsResponse:
type: object
properties:
minerals:
type: array
items:
$ref: '#/components/schemas/CriticalMineral'
fetchedAt:
type: string
upstreamUnavailable:
type: boolean
CriticalMineral:
type: object
properties:
mineral:
type: string
topProducers:
type: array
items:
$ref: '#/components/schemas/MineralProducer'
hhi:
type: number
format: double
riskRating:
type: string
globalProduction:
type: number
format: double
unit:
type: string
MineralProducer:
type: object
properties:
country:
type: string
countryCode:
type: string
productionTonnes:
type: number
format: double
sharePct:
type: number
format: double
GetShippingStressRequest:
type: object
GetShippingStressResponse:
type: object
properties:
carriers:
type: array
items:
$ref: '#/components/schemas/ShippingStressCarrier'
stressScore:
type: number
format: double
description: Composite stress score 0100 (higher = more disruption).
stressLevel:
type: string
description: '"low" | "moderate" | "elevated" | "critical".'
fetchedAt:
type: integer
format: int64
description: 'Warning: Values > 2^53 may lose precision in JavaScript'
upstreamUnavailable:
type: boolean
description: Set to true when upstream data source is unavailable and cached data is stale.
ShippingStressCarrier:
type: object
properties:
symbol:
type: string
description: Ticker or identifier (e.g., "BDRY", "ZIM").
name:
type: string
description: Human-readable name.
price:
type: number
format: double
description: Current price.
changePct:
type: number
format: double
description: Percentage change from previous close.
carrierType:
type: string
description: 'Carrier type: "etf" | "carrier" | "index".'
sparkline:
type: array
items:
type: number
format: double
description: 30-day price sparkline.
description: ShippingStressCarrier represents market stress data for a carrier or shipping index.