Files

149 lines
5.3 KiB
Markdown
Raw Permalink Normal View History

# Presenters and Templates
This document describes payload shaping in
`internal/adapters/inbound/httpapi/presenter` and its relationship to text
templates. Public response fields are documented in [`docs/api.md`](../api.md).
## Purpose
Presenters translate repository/application read models into response-ready
payloads. They own unit conversion, numeric rounding, timezone conversion,
optional field preservation, and copy semantics.
## Inputs and Outputs
Inputs:
- weatherfeeder model values returned by the repository;
- `app.CurrentConditions` values returned by the application service;
- requested unit mode;
- requested precision;
- optional timezone location.
Outputs:
- JSON/XML/text-ready payload structs or canonical model copies;
- nil payloads for nil inputs.
## Boundaries
Presenters may:
- convert metric values to US-customary response fields;
- round numeric values that are presentation values;
- convert timestamps to a requested timezone;
- copy slices and pointers before changing presentation values;
- add template-only helper fields when they are not serialized.
Presenters must not:
- execute SQL;
- call services or repositories;
- parse HTTP query parameters;
- load templates;
- change canonical repository models in place.
## Config Fields Used
Presenters do not read config directly. They receive unit, precision, and
timezone selections from HTTP binders. Text output depends indirectly on
`templates.base_dir` because feedapi loads templates from that configured
directory.
## External Adapters Used
- `weatherfeeder/model` for canonical weather payloads.
- `weatherfeeder/standards` for current-condition text from WMO codes.
- `internal/app` for the current-conditions read model.
- Feedapi templates indirectly consume presenter output during text rendering.
## State
Presenters are stateless. Helper functions allocate copied values and return
new payloads for each request.
## Unit Conversion
Metric mode generally returns weatherfeeder canonical model shapes or
metric-named fields. US mode uses explicit US response structs for observations
and forecasts and US-specific fields in current conditions.
Conversion constants live in `constants.go`:
- Celsius to Fahrenheit;
- kilometers per hour to miles per hour;
- meters to miles or feet;
- pascals to inches of mercury;
- millimeters to inches.
Non-unit fields such as percentages, directions, text, IDs, and ordering values
keep their existing values.
## Precision
`roundedPtr` and `roundFloat` round numeric presentation values. Precision `0`
rounds to whole numbers. Positive precision uses powers of ten. Nil numeric
pointers remain nil.
Latitude and longitude are copied but not rounded by forecast presenters.
## Timezone Conversion
`inLocationTime` and `inLocationTimePtr` convert timestamps only when a
timezone is supplied. Without a timezone, timestamps are preserved as returned
by the repository.
2026-06-11 15:46:00 +00:00
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
Presenter helpers copy pointer values before changing them. Slices are copied
before inclusion where needed. This preserves nil/omitempty behavior and avoids
mutating repository-returned values.
Nil input payloads return nil. Endpoint handlers wrap those nil payloads in a
response envelope so renderers can produce `data: null`.
## Endpoint Families
- Observations: metric copy or US response shape, including present-weather
slice copy.
- Current conditions: single response shape with either metric or US unit
fields populated, plus a template-only day/night text helper.
- Alerts: pass-through of canonical alert runs, with nil preserved.
- Forecasts: metric copy or US response shape, period copy, unit conversion,
precision, and timezone conversion.
- Discussions: full or focused payload shapes, section copy, key-message copy,
timezone conversion.
- Weather stories: run/story copy and timezone conversion.
2026-06-12 13:07:17 +00:00
- Convective outlooks: canonical model copy, pointer and geometry copy,
run-level discussion copy, and timezone conversion for run, outlook, and
discussion timestamps. Outlook polygon prose is not handled by the presenter;
prose is carried by run-level discussions. `units` is accepted by routes but
ignored by the presenter because outlook fields are not unit-bearing.
## Templates
Text templates consume the same envelope data produced by presenters. Template
files live under `templates/` and are loaded by feedapi from `templates.base_dir`.
Presenter changes can break text output even when JSON and XML still compile.
Check template field references before renaming or removing presenter fields.
## Tests to Inspect Before Changing
- `internal/adapters/inbound/httpapi/presenter/payload_test.go`
- `internal/adapters/inbound/httpapi/endpoints_test.go` for rendered text and
envelope behavior
- affected template files under `templates/`
## Invariants
- Keep unit conversion and rounding out of handlers and repositories.
- Preserve nil pointer and optional field behavior.
- Copy before converting, rounding, or timezone-shifting values.
- Keep text-template helper fields out of JSON/XML when they are not API fields.
- Update `docs/api.md` and templates when payload shape changes.