Add internal architecture documentation

This commit is contained in:
2026-06-11 14:19:51 +00:00
parent ec027e34cc
commit 9fe480d3ab
4 changed files with 556 additions and 0 deletions

143
docs/internal/presenters.md Normal file
View File

@@ -0,0 +1,143 @@
# 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.
Timezone conversion is applied by forecast, discussion, and weather story
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.
## 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.