Document convective outlook endpoints

This commit is contained in:
2026-06-11 15:46:00 +00:00
parent e897ae52df
commit 993621e3b3
7 changed files with 228 additions and 20 deletions

View File

@@ -8,7 +8,8 @@ This document describes the internal HTTP adapter under
The HTTP adapter turns feedapi route definitions into calls on the application
service boundary. It owns route registration, query binding, request validation,
forecast day-slice filtering, response envelopes, and template names.
forecast day-slice filtering, outlook active/location filter construction,
response envelopes, and template names.
## Inputs and Outputs
@@ -33,7 +34,8 @@ The adapter may:
- bind and validate query parameters;
- call the `Service` interface;
- choose the presenter function for an endpoint;
- filter forecast copies for `/today` and `/tomorrow`.
- filter forecast copies for `/today` and `/tomorrow`;
- construct outlook active/location filters.
The adapter must not:
@@ -59,9 +61,9 @@ declared in endpoint definitions, but `templates.base_dir` is loaded by feedapi.
## State
The adapter has no durable state. `forecastNow` is package-level state only to
make forecast day filtering testable. Do not add request caches or cross-request
mutable state here.
The adapter has no durable state. `forecastNow` and `outlookNow` are
package-level state only to make time-dependent endpoint tests deterministic.
Do not add request caches or cross-request mutable state here.
## Route Registry
@@ -71,6 +73,7 @@ mutable state here.
- active alerts;
- current conditions;
- weather stories;
- convective outlooks;
- forecast discussions;
- hourly and narrative forecasts.
@@ -80,19 +83,25 @@ middleware, and error normalization after definitions are registered.
## Query Binding
There are three binder shapes:
Binder shapes include:
- `bindQuery`: `format` and `units`;
- `bindPrecisionQuery`: `format`, `units`, and `precision`;
- `bindForecastPrecisionQuery`: `format`, `units`, `precision`, and timezone;
- `bindTimezoneQuery`: `format`, `units`, and timezone.
- outlook binders: `format`, `units`, timezone, and outlook filters.
All binders use feedapi binding helpers with `RejectUnknown: true`. Supported
common query values are lowercased and trimmed before binding where applicable.
`precision` defaults to `0` and must be between `0` and `2`. Timezone parsing is
available only through binders used by forecast, discussion, and weather story
routes.
available only through binders used by forecast, discussion, weather story, and
outlook routes.
Outlook routes accept `day`, `outlookType`, and, except for
`/outlooks/convective/location`, `containsLocation`. The location route always
adds `containsLocation=true` after binding and rejects an explicit
`containsLocation` query value.
## Timezone Parsing
@@ -122,6 +131,19 @@ Filtering behavior:
The package variable `forecastNow` exists so endpoint tests can make day-slice
behavior deterministic.
## Outlook Filters
Outlook route filters are built at the HTTP boundary and passed to the
application service:
- `/outlooks/convective` uses only user-supplied filters;
- `/outlooks/convective/active` adds `ActiveAt=outlookNow().UTC()`;
- `/outlooks/convective/location` adds the same active timestamp and
`ContainsLocation=true`.
The package variable `outlookNow` exists so endpoint tests can make active and
location filtering deterministic.
## Failure Behavior
Binder failures become feedapi invalid-parameter responses. Handler service

View File

@@ -21,8 +21,8 @@ Inputs:
Outputs:
- latest observation, forecast, discussion, weather story, alert, and current
conditions read models;
- latest observation, forecast, discussion, weather story, alert, convective
outlook, and current conditions read models;
- nil data with nil error when the latest resource does not exist;
- contextual errors for query, scan, iteration, and JSON decode failures.
@@ -89,6 +89,8 @@ successful responses with `data: null`.
- `LatestWeatherStoryRun`: latest row from `weather_story_runs`, then child
`weather_stories`.
- `LatestWeatherStory`: latest individual row from `weather_stories`.
- `LatestConvectiveOutlookRun`: latest row from `outlook_runs`, then child
`outlooks`.
Latest parent rows are selected by descending weather timestamp and
`event_emitted_at` where that tie-breaker is available in the query.
@@ -102,7 +104,8 @@ Child queries preserve stored order:
- alert references by `alert_index`, then `reference_index`;
- forecast periods by `period_index`;
- discussion key messages by `message_index`;
- weather stories by `story_index`.
- weather stories by `story_index`;
- outlooks by `outlook_index`.
Alert references are attached after both alert and reference rows are loaded.
References are grouped by alert index and attached to their corresponding alert.
@@ -126,6 +129,10 @@ Observation present-weather rows store raw JSON text. Empty or null text maps
to an empty present-weather value. Invalid JSON returns a contextual decode
error with the weather index.
Outlook rows store `geometry_json` as compact GeoJSON text. The repository
validates and copies the JSON bytes into `json.RawMessage` without parsing or
reserializing the geometry.
## Failure Behavior
Repository methods wrap failures with operation context, for example:

View File

@@ -93,9 +93,9 @@ Latitude and longitude are copied but not rounded by forecast presenters.
timezone is supplied. Without a timezone, timestamps are preserved as returned
by the repository.
Timezone conversion is applied by forecast, discussion, and weather story
presenters. Observations and current conditions do not currently receive
timezone input from their routes.
Timezone conversion is applied by forecast, discussion, weather story, and
outlook presenters. Observations and current conditions do not currently
receive timezone input from their routes.
## Optional Fields and Copy Semantics
@@ -118,6 +118,9 @@ response envelope so renderers can produce `data: null`.
- Discussions: full or focused payload shapes, section copy, key-message copy,
timezone conversion.
- Weather stories: run/story copy and timezone conversion.
- Convective outlooks: canonical model copy, pointer and geometry copy, and
timezone conversion. `units` is accepted by routes but ignored by the
presenter because outlook fields are not unit-bearing.
## Templates