model: add explicit JSON tags and document canonical payload contract
Add lowerCamelCase JSON tags to canonical model types (observation, forecast, alert) to stabilize the emitted wire format and make payload structure explicit for downstream sinks. Introduce internal/model/doc.go to document these structs as versioned, schema-governed payloads and clarify compatibility expectations (additive changes preferred; breaking changes require schema bumps). No functional behavior changes; this formalizes the canonical output contract ahead of additional sinks and consumers.
This commit is contained in:
@@ -1,23 +1,24 @@
|
|||||||
|
// FILE: internal/model/alert.go
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// Placeholder for NWS alerts (GeoJSON feature properties are rich).
|
// Placeholder for NWS alerts (GeoJSON feature properties are rich).
|
||||||
type WeatherAlert struct {
|
type WeatherAlert struct {
|
||||||
ID string
|
ID string `json:"id"`
|
||||||
|
|
||||||
Event string
|
Event string `json:"event,omitempty"`
|
||||||
Headline string
|
Headline string `json:"headline,omitempty"`
|
||||||
Description string
|
Description string `json:"description,omitempty"`
|
||||||
Instruction string
|
Instruction string `json:"instruction,omitempty"`
|
||||||
|
|
||||||
Severity string
|
Severity string `json:"severity,omitempty"`
|
||||||
Urgency string
|
Urgency string `json:"urgency,omitempty"`
|
||||||
Certainty string
|
Certainty string `json:"certainty,omitempty"`
|
||||||
|
|
||||||
Sent *time.Time
|
Sent *time.Time `json:"sent,omitempty"`
|
||||||
Effective *time.Time
|
Effective *time.Time `json:"effective,omitempty"`
|
||||||
Expires *time.Time
|
Expires *time.Time `json:"expires,omitempty"`
|
||||||
|
|
||||||
Areas []string
|
Areas []string `json:"areas,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
10
internal/model/doc.go
Normal file
10
internal/model/doc.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// FILE: internal/model/doc.go
|
||||||
|
// Package model defines weatherfeeder's canonical domain payload types.
|
||||||
|
//
|
||||||
|
// These structs are emitted as the Payload of canonical events (schemas "weather.*.vN").
|
||||||
|
// JSON tags are treated as part of the wire contract for sinks (stdout today; others later).
|
||||||
|
//
|
||||||
|
// Compatibility guidance:
|
||||||
|
// - Prefer additive changes.
|
||||||
|
// - Avoid renaming/removing fields without a schema version bump.
|
||||||
|
package model
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
|
// FILE: internal/model/forecast.go
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// WeatherForecast identity fields (as you described).
|
// WeatherForecast identity fields (as you described).
|
||||||
type WeatherForecast struct {
|
type WeatherForecast struct {
|
||||||
IssuedBy string // e.g. "NWS"
|
IssuedBy string `json:"issuedBy,omitempty"` // e.g. "NWS"
|
||||||
IssuedAt time.Time // when forecast product was issued
|
IssuedAt time.Time `json:"issuedAt"` // when forecast product was issued
|
||||||
ForecastType string // e.g. "hourly", "daily"
|
ForecastType string `json:"forecastType,omitempty"` // e.g. "hourly", "daily"
|
||||||
ForecastStart time.Time // start of the applicable forecast period
|
ForecastStart time.Time `json:"forecastStart"` // start of the applicable forecast period
|
||||||
|
|
||||||
// TODO: You’ll likely want ForecastEnd too.
|
// TODO: You’ll likely want ForecastEnd too.
|
||||||
|
|
||||||
// TODO: Add meteorological fields you care about.
|
// TODO: Add meteorological fields you care about.
|
||||||
// Temperature, precip probability, wind, etc.
|
|
||||||
// Decide if you want a single "period" model or an array of periods.
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,72 +1,56 @@
|
|||||||
|
// FILE: internal/model/observation.go
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type WeatherObservation struct {
|
type WeatherObservation struct {
|
||||||
// Identity / metadata
|
// Identity / metadata
|
||||||
StationID string
|
StationID string `json:"stationId,omitempty"`
|
||||||
StationName string
|
StationName string `json:"stationName,omitempty"`
|
||||||
Timestamp time.Time
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
|
||||||
// Canonical internal representation (provider-independent).
|
// Canonical internal representation (provider-independent).
|
||||||
//
|
ConditionCode WMOCode `json:"conditionCode"`
|
||||||
// ConditionCode should be populated by all sources. ConditionText should be the
|
ConditionText string `json:"conditionText,omitempty"`
|
||||||
// canonical human-readable string derived from the WMO code (not the provider's
|
IsDay *bool `json:"isDay,omitempty"`
|
||||||
// original wording).
|
|
||||||
//
|
|
||||||
// IsDay is optional; some providers supply a day/night flag (e.g., Open-Meteo),
|
|
||||||
// while others may not (e.g., NWS observations). When unknown, it can be nil.
|
|
||||||
ConditionCode WMOCode
|
|
||||||
ConditionText string
|
|
||||||
IsDay *bool
|
|
||||||
|
|
||||||
// Provider-specific “evidence” for troubleshooting mapping and drift.
|
// Provider-specific “evidence” for troubleshooting mapping and drift.
|
||||||
//
|
ProviderRawDescription string `json:"providerRawDescription,omitempty"`
|
||||||
// This is intentionally limited: it is not intended to be used downstream for
|
|
||||||
// business logic. Downstream logic should rely on ConditionCode / ConditionText.
|
|
||||||
ProviderRawDescription string
|
|
||||||
|
|
||||||
// Human-facing (legacy / transitional)
|
// Human-facing (legacy / transitional)
|
||||||
//
|
TextDescription string `json:"textDescription,omitempty"`
|
||||||
// TextDescription currently carries provider text in existing drivers.
|
|
||||||
// As we transition to WMO-based normalization, downstream presentation should
|
|
||||||
// switch to using ConditionText. After migration, this may be removed or repurposed.
|
|
||||||
TextDescription string
|
|
||||||
|
|
||||||
// Provider-specific (legacy / transitional)
|
// Provider-specific (legacy / transitional)
|
||||||
//
|
IconURL string `json:"iconUrl,omitempty"`
|
||||||
// IconURL is not part of the canonical internal vocabulary. It's retained only
|
|
||||||
// because current sources populate it; it is not required for downstream systems.
|
|
||||||
IconURL string
|
|
||||||
|
|
||||||
// Core measurements (nullable)
|
// Core measurements (nullable)
|
||||||
TemperatureC *float64
|
TemperatureC *float64 `json:"temperatureC,omitempty"`
|
||||||
DewpointC *float64
|
DewpointC *float64 `json:"dewpointC,omitempty"`
|
||||||
|
|
||||||
WindDirectionDegrees *float64
|
WindDirectionDegrees *float64 `json:"windDirectionDegrees,omitempty"`
|
||||||
WindSpeedKmh *float64
|
WindSpeedKmh *float64 `json:"windSpeedKmh,omitempty"`
|
||||||
WindGustKmh *float64
|
WindGustKmh *float64 `json:"windGustKmh,omitempty"`
|
||||||
|
|
||||||
BarometricPressurePa *float64
|
BarometricPressurePa *float64 `json:"barometricPressurePa,omitempty"`
|
||||||
SeaLevelPressurePa *float64
|
SeaLevelPressurePa *float64 `json:"seaLevelPressurePa,omitempty"`
|
||||||
VisibilityMeters *float64
|
VisibilityMeters *float64 `json:"visibilityMeters,omitempty"`
|
||||||
|
|
||||||
RelativeHumidityPercent *float64
|
RelativeHumidityPercent *float64 `json:"relativeHumidityPercent,omitempty"`
|
||||||
WindChillC *float64
|
WindChillC *float64 `json:"windChillC,omitempty"`
|
||||||
HeatIndexC *float64
|
HeatIndexC *float64 `json:"heatIndexC,omitempty"`
|
||||||
|
|
||||||
ElevationMeters *float64
|
ElevationMeters *float64 `json:"elevationMeters,omitempty"`
|
||||||
RawMessage string
|
RawMessage string `json:"rawMessage,omitempty"`
|
||||||
|
|
||||||
PresentWeather []PresentWeather
|
PresentWeather []PresentWeather `json:"presentWeather,omitempty"`
|
||||||
CloudLayers []CloudLayer
|
CloudLayers []CloudLayer `json:"cloudLayers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CloudLayer struct {
|
type CloudLayer struct {
|
||||||
BaseMeters *float64
|
BaseMeters *float64 `json:"baseMeters,omitempty"`
|
||||||
Amount string
|
Amount string `json:"amount,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PresentWeather struct {
|
type PresentWeather struct {
|
||||||
Raw map[string]any
|
Raw map[string]any `json:"raw,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user