diff --git a/internal/model/alert.go b/internal/model/alert.go index 54fcdfc..141d933 100644 --- a/internal/model/alert.go +++ b/internal/model/alert.go @@ -1,23 +1,24 @@ +// FILE: internal/model/alert.go package model import "time" // Placeholder for NWS alerts (GeoJSON feature properties are rich). type WeatherAlert struct { - ID string + ID string `json:"id"` - Event string - Headline string - Description string - Instruction string + Event string `json:"event,omitempty"` + Headline string `json:"headline,omitempty"` + Description string `json:"description,omitempty"` + Instruction string `json:"instruction,omitempty"` - Severity string - Urgency string - Certainty string + Severity string `json:"severity,omitempty"` + Urgency string `json:"urgency,omitempty"` + Certainty string `json:"certainty,omitempty"` - Sent *time.Time - Effective *time.Time - Expires *time.Time + Sent *time.Time `json:"sent,omitempty"` + Effective *time.Time `json:"effective,omitempty"` + Expires *time.Time `json:"expires,omitempty"` - Areas []string + Areas []string `json:"areas,omitempty"` } diff --git a/internal/model/doc.go b/internal/model/doc.go new file mode 100644 index 0000000..1b8145e --- /dev/null +++ b/internal/model/doc.go @@ -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 diff --git a/internal/model/forecast.go b/internal/model/forecast.go index ce2f251..45089af 100644 --- a/internal/model/forecast.go +++ b/internal/model/forecast.go @@ -1,17 +1,15 @@ +// FILE: internal/model/forecast.go package model import "time" // WeatherForecast identity fields (as you described). type WeatherForecast struct { - IssuedBy string // e.g. "NWS" - IssuedAt time.Time // when forecast product was issued - ForecastType string // e.g. "hourly", "daily" - ForecastStart time.Time // start of the applicable forecast period + IssuedBy string `json:"issuedBy,omitempty"` // e.g. "NWS" + IssuedAt time.Time `json:"issuedAt"` // when forecast product was issued + ForecastType string `json:"forecastType,omitempty"` // e.g. "hourly", "daily" + ForecastStart time.Time `json:"forecastStart"` // start of the applicable forecast period // TODO: You’ll likely want ForecastEnd too. - // 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. } diff --git a/internal/model/observation.go b/internal/model/observation.go index 071f536..5a0b621 100644 --- a/internal/model/observation.go +++ b/internal/model/observation.go @@ -1,72 +1,56 @@ +// FILE: internal/model/observation.go package model import "time" type WeatherObservation struct { // Identity / metadata - StationID string - StationName string - Timestamp time.Time + StationID string `json:"stationId,omitempty"` + StationName string `json:"stationName,omitempty"` + Timestamp time.Time `json:"timestamp"` // Canonical internal representation (provider-independent). - // - // ConditionCode should be populated by all sources. ConditionText should be the - // canonical human-readable string derived from the WMO code (not the provider's - // 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 + ConditionCode WMOCode `json:"conditionCode"` + ConditionText string `json:"conditionText,omitempty"` + IsDay *bool `json:"isDay,omitempty"` // Provider-specific “evidence” for troubleshooting mapping and drift. - // - // This is intentionally limited: it is not intended to be used downstream for - // business logic. Downstream logic should rely on ConditionCode / ConditionText. - ProviderRawDescription string + ProviderRawDescription string `json:"providerRawDescription,omitempty"` // Human-facing (legacy / transitional) - // - // 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 + TextDescription string `json:"textDescription,omitempty"` // Provider-specific (legacy / transitional) - // - // 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 + IconURL string `json:"iconUrl,omitempty"` // Core measurements (nullable) - TemperatureC *float64 - DewpointC *float64 + TemperatureC *float64 `json:"temperatureC,omitempty"` + DewpointC *float64 `json:"dewpointC,omitempty"` - WindDirectionDegrees *float64 - WindSpeedKmh *float64 - WindGustKmh *float64 + WindDirectionDegrees *float64 `json:"windDirectionDegrees,omitempty"` + WindSpeedKmh *float64 `json:"windSpeedKmh,omitempty"` + WindGustKmh *float64 `json:"windGustKmh,omitempty"` - BarometricPressurePa *float64 - SeaLevelPressurePa *float64 - VisibilityMeters *float64 + BarometricPressurePa *float64 `json:"barometricPressurePa,omitempty"` + SeaLevelPressurePa *float64 `json:"seaLevelPressurePa,omitempty"` + VisibilityMeters *float64 `json:"visibilityMeters,omitempty"` - RelativeHumidityPercent *float64 - WindChillC *float64 - HeatIndexC *float64 + RelativeHumidityPercent *float64 `json:"relativeHumidityPercent,omitempty"` + WindChillC *float64 `json:"windChillC,omitempty"` + HeatIndexC *float64 `json:"heatIndexC,omitempty"` - ElevationMeters *float64 - RawMessage string + ElevationMeters *float64 `json:"elevationMeters,omitempty"` + RawMessage string `json:"rawMessage,omitempty"` - PresentWeather []PresentWeather - CloudLayers []CloudLayer + PresentWeather []PresentWeather `json:"presentWeather,omitempty"` + CloudLayers []CloudLayer `json:"cloudLayers,omitempty"` } type CloudLayer struct { - BaseMeters *float64 - Amount string + BaseMeters *float64 `json:"baseMeters,omitempty"` + Amount string `json:"amount,omitempty"` } type PresentWeather struct { - Raw map[string]any + Raw map[string]any `json:"raw,omitempty"` }