Files
worldmonitor/docs/api/ClimateService.openapi.yaml
Fayez Bast 9d94ad36aa feat(climate+health):add shared air quality seed and mirrored health (#2634)
* feat(climate+health):add shared air quality seed and mirrored health/climate RPCs

* feat(climate+health):add shared air quality seed and mirrored health/climate RPCs

* fix(air-quality): address review findings — TTL, seed-health, FAST_KEYS, shared meta

- Raise CACHE_TTL from 3600 to 10800 (3× the 1h cron cadence; gold standard)
- Add health:air-quality to api/seed-health.js SEED_DOMAINS so monitoring dashboard tracks freshness
- Remove climateAirQuality and healthAirQuality from FAST_KEYS (large station payloads; load in slow batch)
- Point climateAirQuality SEED_META to same meta key as healthAirQuality (same seeder run, one source of truth)

* fix(bootstrap): move air quality keys to SLOW tier — large station payloads avoid critical-path batch

* fix(air-quality): fix malformed OpenAQ URL and remove from bootstrap until panel exists

- Drop deprecated first URL attempt (parameters=pm25, order_by=lastUpdated, sort=desc);
  use correct v3 params (parameters_id=2, sort_order=desc) directly — eliminates
  guaranteed 4xx retry cycle per page on 20-page crawl
- Remove climateAirQuality and healthAirQuality from BOOTSTRAP_CACHE_KEYS, SLOW_KEYS,
  and BOOTSTRAP_TIERS — no panel consumes these yet; adding thousands of station records
  to every startup bootstrap is pure payload bloat
- Remove normalizeAirQualityPayload helpers from bootstrap.js (no longer called)
- Update service wrappers to fetch via RPC directly; re-add bootstrap hydration
  when a panel actually needs it

* fix(air-quality): raise lock TTL to 3600s to cover 20-page crawl worst case

2 OpenAQ calls × 20 pages × (30s timeout × 3 attempts) = 3600s max runtime.
Previous 600s TTL allowed concurrent cron runs on any degraded upstream.

---------

Co-authored-by: Elie Habib <elie.habib@gmail.com>
2026-04-03 10:27:37 +04:00

400 lines
16 KiB
YAML

openapi: 3.1.0
info:
title: ClimateService API
version: 1.0.0
paths:
/api/climate/v1/list-climate-anomalies:
get:
tags:
- ClimateService
summary: ListClimateAnomalies
description: ListClimateAnomalies retrieves temperature and precipitation anomalies from ERA5 data.
operationId: ListClimateAnomalies
parameters:
- name: page_size
in: query
description: Maximum items per page (1-100).
required: false
schema:
type: integer
format: int32
- name: cursor
in: query
description: Cursor for next page.
required: false
schema:
type: string
- name: min_severity
in: query
description: Optional filter by anomaly severity.
required: false
schema:
type: string
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListClimateAnomaliesResponse'
"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/climate/v1/get-co2-monitoring:
get:
tags:
- ClimateService
summary: GetCo2Monitoring
description: GetCo2Monitoring retrieves seeded NOAA greenhouse gas monitoring data.
operationId: GetCo2Monitoring
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetCo2MonitoringResponse'
"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/climate/v1/list-air-quality-data:
get:
tags:
- ClimateService
summary: ListAirQualityData
description: ListAirQualityData retrieves recent PM2.5 station data from the shared air-quality seed.
operationId: ListAirQualityData
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListAirQualityDataResponse'
"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/climate/v1/list-climate-news:
get:
tags:
- ClimateService
summary: ListClimateNews
description: ListClimateNews retrieves latest climate/environment intelligence headlines from seeded RSS feeds.
operationId: ListClimateNews
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListClimateNewsResponse'
"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.
ListClimateAnomaliesRequest:
type: object
properties:
pageSize:
type: integer
format: int32
description: Maximum items per page (1-100).
cursor:
type: string
description: Cursor for next page.
minSeverity:
type: string
enum:
- ANOMALY_SEVERITY_UNSPECIFIED
- ANOMALY_SEVERITY_NORMAL
- ANOMALY_SEVERITY_MODERATE
- ANOMALY_SEVERITY_EXTREME
description: |-
AnomalySeverity represents the severity of a climate anomaly.
Maps to existing TS union: 'normal' | 'moderate' | 'extreme'.
description: ListClimateAnomaliesRequest specifies filters for retrieving climate anomaly data.
ListClimateAnomaliesResponse:
type: object
properties:
anomalies:
type: array
items:
$ref: '#/components/schemas/ClimateAnomaly'
pagination:
$ref: '#/components/schemas/PaginationResponse'
description: ListClimateAnomaliesResponse contains the list of climate anomalies.
ClimateAnomaly:
type: object
properties:
zone:
type: string
minLength: 1
description: Climate zone name (e.g., "Northern Europe", "Sahel").
location:
$ref: '#/components/schemas/GeoCoordinates'
tempDelta:
type: number
format: double
description: Temperature deviation from normal in degrees Celsius.
precipDelta:
type: number
format: double
description: Precipitation deviation from normal in millimeters.
severity:
type: string
enum:
- ANOMALY_SEVERITY_UNSPECIFIED
- ANOMALY_SEVERITY_NORMAL
- ANOMALY_SEVERITY_MODERATE
- ANOMALY_SEVERITY_EXTREME
description: |-
AnomalySeverity represents the severity of a climate anomaly.
Maps to existing TS union: 'normal' | 'moderate' | 'extreme'.
type:
type: string
enum:
- ANOMALY_TYPE_UNSPECIFIED
- ANOMALY_TYPE_WARM
- ANOMALY_TYPE_COLD
- ANOMALY_TYPE_WET
- ANOMALY_TYPE_DRY
- ANOMALY_TYPE_MIXED
description: |-
AnomalyType represents the type of climate anomaly.
Maps to existing TS union: 'warm' | 'cold' | 'wet' | 'dry' | 'mixed'.
period:
type: string
minLength: 1
description: Time period covered (e.g., "2024-W03", "2024-01").
required:
- zone
- period
description: |-
ClimateAnomaly represents a temperature or precipitation deviation from historical norms.
Sourced from Open-Meteo / ERA5 reanalysis data.
GeoCoordinates:
type: object
properties:
latitude:
type: number
maximum: 90
minimum: -90
format: double
description: Latitude in decimal degrees (-90 to 90).
longitude:
type: number
maximum: 180
minimum: -180
format: double
description: Longitude in decimal degrees (-180 to 180).
description: GeoCoordinates represents a geographic location using WGS84 coordinates.
PaginationResponse:
type: object
properties:
nextCursor:
type: string
description: Cursor for fetching the next page. Empty string indicates no more pages.
totalCount:
type: integer
format: int32
description: Total count of items matching the query, if known. Zero if the total is unknown.
description: PaginationResponse contains pagination metadata returned alongside list results.
GetCo2MonitoringRequest:
type: object
GetCo2MonitoringResponse:
type: object
properties:
monitoring:
$ref: '#/components/schemas/Co2Monitoring'
Co2Monitoring:
type: object
properties:
currentPpm:
type: number
format: double
yearAgoPpm:
type: number
format: double
annualGrowthRate:
type: number
format: double
preIndustrialBaseline:
type: number
format: double
monthlyAverage:
type: number
format: double
trend12m:
type: array
items:
$ref: '#/components/schemas/Co2DataPoint'
methanePpb:
type: number
format: double
nitrousOxidePpb:
type: number
format: double
measuredAt:
type: string
format: int64
station:
type: string
Co2DataPoint:
type: object
properties:
month:
type: string
ppm:
type: number
format: double
anomaly:
type: number
format: double
description: Year-over-year delta vs same calendar month, in ppm.
ListAirQualityDataRequest:
type: object
ListAirQualityDataResponse:
type: object
properties:
stations:
type: array
items:
$ref: '#/components/schemas/AirQualityStation'
fetchedAt:
type: integer
format: int64
description: 'Warning: Values > 2^53 may lose precision in JavaScript'
AirQualityStation:
type: object
properties:
city:
type: string
countryCode:
type: string
lat:
type: number
format: double
lng:
type: number
format: double
pm25:
type: number
format: double
aqi:
type: integer
format: int32
riskLevel:
type: string
pollutant:
type: string
measuredAt:
type: integer
format: int64
description: 'Warning: Values > 2^53 may lose precision in JavaScript'
source:
type: string
ListClimateNewsRequest:
type: object
ListClimateNewsResponse:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/ClimateNewsItem'
fetchedAt:
type: integer
format: int64
description: 'Warning: Values > 2^53 may lose precision in JavaScript'
ClimateNewsItem:
type: object
properties:
id:
type: string
description: Unique identifier (URL hash + publish timestamp).
title:
type: string
description: Article headline.
url:
type: string
description: Canonical article URL.
sourceName:
type: string
description: Source publication name.
publishedAt:
type: integer
format: int64
description: 'Publication time as Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
summary:
type: string
description: Short summary/description (max 300 chars in seed pipeline).
description: ClimateNewsItem represents a single climate/environment news article.