Merged SCHEMA.md into API.md and made some tweaks to ensure consistency with the underlying domain model.
All checks were successful
ci/woodpecker/push/build-image Pipeline was successful

This commit is contained in:
2026-02-07 19:36:50 -06:00
parent 190420e908
commit cff8c5f593
2 changed files with 45 additions and 224 deletions

103
API.md
View File

@@ -47,36 +47,22 @@ Each payload is described below using the JSON field names as the contract.
--- ---
## Shared conventions ## Shared Conventions
### Optional fields - Timestamps are JSON strings in RFC3339Nano format.
- Optional fields are omitted when unknown (`omitempty` behavior).
Most non-identity measurements are optional. Optional fields are omitted when unknown (i.e., not present). - Numeric measurements are normalized to metric units:
- `*C` = Celsius
### Units - `*Kmh` = kilometers/hour
- `*Pa` = Pascals
Canonical payloads are normalized to metric units: - `*Meters` = meters
- `*Mm` = millimeters
- Temperature: `*C` (Celsius) - `*Percent` = percent (0-100)
- Wind speed/gust: `*Kmh` (kilometers/hour) - `conditionCode` is a WMO weather interpretation code (`int`).
- Pressure: `*Pa` (Pascals) - Unknown/unmappable is `-1`.
- Visibility / distance / elevation: `*Meters` (meters) - Downstream consumers should treat unknown codes as “unknown conditions” rather than failing decoding.
- Precipitation amount / snowfall depth: `*Mm` (millimeters) - For readability and stability, weatherfeeder rounds floating-point values in canonical payloads to
- Humidity / cloud cover / PoP: `*Percent` (0100) **4 digits after the decimal** during normalization.
### Float rounding
For readability and stability, weatherfeeder rounds floating-point values in canonical payloads to
**2 digits after the decimal** during normalization finalization.
### WMO condition codes
`conditionCode` uses the WMO weather interpretation code vocabulary.
- Type: integer
- Unknown/unmappable: `-1`
Downstream consumers should treat unknown codes as “unknown conditions” rather than failing decoding.
--- ---
@@ -88,31 +74,31 @@ A `WeatherObservation` represents a point-in-time observation for a station/loca
### Fields ### Fields
| Field | Type | Required | Units / Notes | | Field | Type | Required | Notes |
|---|---:|:---:|---| |---|---:|:---:|---|
| `stationId` | string | no | Provider station/location identifier | | `stationId` | string | no | Provider station/location identifier |
| `stationName` | string | no | Human name, if available | | `stationName` | string | no | Human station name |
| `timestamp` | string (timestamp) | yes | Observation time | | `timestamp` | timestamp string | yes | Observation timestamp |
| `conditionCode` | int | yes | WMO code (`-1` for unknown) | | `conditionCode` | int | yes | WMO code (`-1` unknown) |
| `conditionText` | string | no | Canonical short text (often derived from WMO code) | | `conditionText` | string | no | Canonical short condition text |
| `isDay` | bool | no | Day/night hint when available | | `isDay` | bool | no | Day/night hint |
| `providerRawDescription` | string | no | Provider-specific evidence text | | `providerRawDescription` | string | no | Provider-specific evidence text |
| `textDescription` | string | no | Legacy/transitional human text | | `textDescription` | string | no | Legacy/transitional text description |
| `iconUrl` | string | no | Legacy/transitional icon URL | | `iconUrl` | string | no | Legacy/transitional icon URL |
| `temperatureC` | number | no | °C | | `temperatureC` | number | no | Celsius |
| `dewpointC` | number | no | °C | | `dewpointC` | number | no | Celsius |
| `windDirectionDegrees` | number | no | Degrees (meteorological) | | `windDirectionDegrees` | number | no | Degrees |
| `windSpeedKmh` | number | no | km/h | | `windSpeedKmh` | number | no | km/h |
| `windGustKmh` | number | no | km/h | | `windGustKmh` | number | no | km/h |
| `barometricPressurePa` | number | no | Pa | | `barometricPressurePa` | number | no | Pascals |
| `seaLevelPressurePa` | number | no | Pa | | `seaLevelPressurePa` | number | no | Pascals |
| `visibilityMeters` | number | no | meters | | `visibilityMeters` | number | no | Meters |
| `relativeHumidityPercent` | number | no | percent (0100) | | `relativeHumidityPercent` | number | no | Percent |
| `apparentTemperatureC` | number | no | °C | | `apparentTemperatureC` | number | no | Celsius |
| `elevationMeters` | number | no | meters | | `elevationMeters` | number | no | Meters |
| `rawMessage` | string | no | Provider raw message (e.g. METAR), if available | | `rawMessage` | string | no | Provider raw message (for example METAR) |
| `presentWeather` | array | no | Provider-specific structured fragments | | `presentWeather` | array | no | Provider-specific structured weather fragments |
| `cloudLayers` | array | no | Cloud layers (base + amount) | | `cloudLayers` | array | no | Cloud layer details |
### Nested: `cloudLayers[]` ### Nested: `cloudLayers[]`
@@ -156,7 +142,7 @@ A `WeatherForecastRun` is a single issued forecast snapshot for a location and a
| `locationName` | string | no | Human name, if available | | `locationName` | string | no | Human name, if available |
| `issuedAt` | string (timestamp) | yes | When this run was generated/issued | | `issuedAt` | string (timestamp) | yes | When this run was generated/issued |
| `updatedAt` | string (timestamp) | no | Optional later update time | | `updatedAt` | string (timestamp) | no | Optional later update time |
| `product` | string | yes | `"hourly"`, `"narrative"`, or `"daily"` | | `product` | string | yes | One of `hourly`, `narrative`, `daily` |
| `latitude` | number | no | Degrees | | `latitude` | number | no | Degrees |
| `longitude` | number | no | Degrees | | `longitude` | number | no | Degrees |
| `elevationMeters` | number | no | meters | | `elevationMeters` | number | no | meters |
@@ -220,14 +206,15 @@ A run may contain zero, one, or many alerts.
| Field | Type | Required | Notes | | Field | Type | Required | Notes |
|---|---:|:---:|---| |---|---:|:---:|---|
| `id` | string | yes | Provider-stable identifier (often a URL/URI) | | `id` | string | yes | Provider-stable identifier (often a URL/URI) |
| `event` | string | no | Classification | | `event` | string | no | Classification/event label |
| `headline` | string | no | Short headline | | `headline` | string | no | Alert headline |
| `severity` | string | no | e.g. Extreme/Severe/Moderate/Minor/Unknown | | `severity` | string | no | Example: Extreme/Severe/Moderate/Minor/Unknown |
| `urgency` | string | no | e.g. Immediate/Expected/Future/Past/Unknown | | `urgency` | string | no | Example: Immediate/Expected/Future/Past/Unknown |
| `certainty` | string | no | e.g. Observed/Likely/Possible/Unlikely/Unknown | | `certainty` | string | no | Example: Observed/Likely/Possible/Unlikely/Unknown |
| `status` | string | no | e.g. Actual/Exercise/Test/System/Unknown | | `status` | string | no | Example: Actual/Exercise/Test/System/Unknown |
| `messageType` | string | no | e.g. Alert/Update/Cancel | | `messageType` | string | no | Example: Alert/Update/Cancel |
| `category` | string | no | e.g. Met/Geo/Safety/... | | `category` | string | no | Example: Met/Geo/Safety/Rescue/Fire/Health/Env/Transport/Infra/CBRNE/Other |
| `response` | string | no | Example: Shelter/Evacuate/Prepare/Execute/Avoid/Monitor/Assess/AllClear/None |
| `response` | string | no | e.g. Shelter/Evacuate/Prepare/... | | `response` | string | no | e.g. Shelter/Evacuate/Prepare/... |
| `description` | string | no | Narrative | | `description` | string | no | Narrative |
| `instruction` | string | no | What to do | | `instruction` | string | no | What to do |

166
SCHEMA.md
View File

@@ -1,166 +0,0 @@
# weatherfeeder Canonical Schemas
This document expressly defines the JSON payload schemas emitted by weatherfeeder for:
- `weather.observation.v1`
- `weather.forecast.v1`
- `weather.alert.v1`
These schemas are defined by the `internal/model` structs and their JSON tags.
## Shared Conventions
- Timestamps are JSON strings in RFC3339Nano format.
- Optional fields are omitted when unknown (`omitempty` behavior).
- Numeric measurements are normalized to metric units:
- `*C` = Celsius
- `*Kmh` = kilometers/hour
- `*Pa` = Pascals
- `*Meters` = meters
- `*Mm` = millimeters
- `*Percent` = percent (0-100)
- `conditionCode` is a WMO weather interpretation code (`int`).
- Unknown/unmappable is `-1`.
## `weather.observation.v1`
Payload type: `model.WeatherObservation`
| Field | Type | Required | Notes |
|---|---:|:---:|---|
| `stationId` | string | no | Provider station/location identifier |
| `stationName` | string | no | Human station name |
| `timestamp` | timestamp string | yes | Observation timestamp |
| `conditionCode` | int | yes | WMO code (`-1` unknown) |
| `conditionText` | string | no | Canonical short condition text |
| `isDay` | bool | no | Day/night hint |
| `providerRawDescription` | string | no | Provider-specific evidence text |
| `textDescription` | string | no | Legacy/transitional text description |
| `iconUrl` | string | no | Legacy/transitional icon URL |
| `temperatureC` | number | no | Celsius |
| `dewpointC` | number | no | Celsius |
| `windDirectionDegrees` | number | no | Degrees |
| `windSpeedKmh` | number | no | km/h |
| `windGustKmh` | number | no | km/h |
| `barometricPressurePa` | number | no | Pascals |
| `seaLevelPressurePa` | number | no | Pascals |
| `visibilityMeters` | number | no | Meters |
| `relativeHumidityPercent` | number | no | Percent |
| `apparentTemperatureC` | number | no | Celsius |
| `elevationMeters` | number | no | Meters |
| `rawMessage` | string | no | Provider raw message (for example METAR) |
| `presentWeather` | array | no | Provider-specific structured weather fragments |
| `cloudLayers` | array | no | Cloud layer details |
### `cloudLayers[]` (`model.CloudLayer`)
| Field | Type | Required | Notes |
|---|---:|:---:|---|
| `baseMeters` | number | no | Cloud base altitude in meters |
| `amount` | string | no | Provider amount code/text |
### `presentWeather[]` (`model.PresentWeather`)
| Field | Type | Required | Notes |
|---|---:|:---:|---|
| `raw` | object | no | Provider-specific object |
## `weather.forecast.v1`
Payload type: `model.WeatherForecastRun`
`product` values are:
- `"hourly"`
- `"narrative"`
- `"daily"`
| Field | Type | Required | Notes |
|---|---:|:---:|---|
| `locationId` | string | no | Provider location identifier |
| `locationName` | string | no | Human location name |
| `issuedAt` | timestamp string | yes | Forecast run issue/generated time |
| `updatedAt` | timestamp string | no | Optional later update time |
| `product` | string | yes | One of `hourly`, `narrative`, `daily` |
| `latitude` | number | no | Degrees |
| `longitude` | number | no | Degrees |
| `elevationMeters` | number | no | Meters |
| `periods` | array | yes | Forecast periods, intended chronological order |
### `periods[]` (`model.WeatherForecastPeriod`)
| Field | Type | Required | Notes |
|---|---:|:---:|---|
| `startTime` | timestamp string | yes | Start of validity window |
| `endTime` | timestamp string | yes | End of validity window |
| `name` | string | no | Human label (for example "Tonight") |
| `isDay` | bool | no | Day/night hint |
| `conditionCode` | int | yes | WMO code (`-1` unknown) |
| `conditionText` | string | no | Canonical short condition text |
| `providerRawDescription` | string | no | Provider-specific evidence text |
| `textDescription` | string | no | Short narrative text |
| `detailedText` | string | no | Longer narrative text |
| `iconUrl` | string | no | Legacy/transitional icon URL |
| `temperatureC` | number | no | Celsius |
| `temperatureCMin` | number | no | Celsius (aggregated periods) |
| `temperatureCMax` | number | no | Celsius (aggregated periods) |
| `dewpointC` | number | no | Celsius |
| `relativeHumidityPercent` | number | no | Percent |
| `windDirectionDegrees` | number | no | Degrees |
| `windSpeedKmh` | number | no | km/h |
| `windGustKmh` | number | no | km/h |
| `barometricPressurePa` | number | no | Pascals |
| `visibilityMeters` | number | no | Meters |
| `apparentTemperatureC` | number | no | Celsius |
| `cloudCoverPercent` | number | no | Percent |
| `probabilityOfPrecipitationPercent` | number | no | Percent |
| `precipitationAmountMm` | number | no | Liquid-equivalent millimeters |
| `snowfallDepthMm` | number | no | Millimeters |
| `uvIndex` | number | no | Unitless UV index |
## `weather.alert.v1`
Payload type: `model.WeatherAlertRun`
| Field | Type | Required | Notes |
|---|---:|:---:|---|
| `locationId` | string | no | Provider location identifier |
| `locationName` | string | no | Human location name |
| `asOf` | timestamp string | yes | Snapshot timestamp |
| `latitude` | number | no | Degrees |
| `longitude` | number | no | Degrees |
| `alerts` | array | yes | Active alerts in the snapshot |
### `alerts[]` (`model.WeatherAlert`)
| Field | Type | Required | Notes |
|---|---:|:---:|---|
| `id` | string | yes | Provider-stable ID, often URL/URI |
| `event` | string | no | Classification/event label |
| `headline` | string | no | Alert headline |
| `severity` | string | no | Example: Extreme/Severe/Moderate/Minor/Unknown |
| `urgency` | string | no | Example: Immediate/Expected/Future/Past/Unknown |
| `certainty` | string | no | Example: Observed/Likely/Possible/Unlikely/Unknown |
| `status` | string | no | Example: Actual/Exercise/Test/System/Unknown |
| `messageType` | string | no | Example: Alert/Update/Cancel |
| `category` | string | no | Example: Met/Geo/Safety/Rescue/Fire/Health/Env/Transport/Infra/CBRNE/Other |
| `response` | string | no | Example: Shelter/Evacuate/Prepare/Execute/Avoid/Monitor/Assess/AllClear/None |
| `description` | string | no | Narrative description |
| `instruction` | string | no | Recommended actions |
| `sent` | timestamp string | no | Provider-dependent |
| `effective` | timestamp string | no | Provider-dependent |
| `onset` | timestamp string | no | Provider-dependent |
| `expires` | timestamp string | no | Provider-dependent |
| `areaDescription` | string | no | Provider area text |
| `senderName` | string | no | Alert sender/source name |
| `references` | array | no | Related alerts |
### `references[]` (`model.AlertReference`)
| Field | Type | Required | Notes |
|---|---:|:---:|---|
| `id` | string | no | Related alert ID/URI |
| `identifier` | string | no | Provider identifier when distinct |
| `sender` | string | no | Sender |
| `sent` | timestamp string | no | Timestamp |