Freshness
Each parameter has an expected reporting interval. An observation is fresh through two expected intervals, delayed through six, and stale after that. Stale records keep their real timestamp but lose “current” and “now” language.
Station relationships
A station and a waterbody are separate entities. A relationship stores type, distance, direction where relevant, confidence, provenance, a display note, and review status. Automated proximity creates only a candidate; it never silently claims equivalence.
Units and datums
Raw values are preserved. Canonical conversions are explicit, tested functions. Streamflow and gage height remain distinct. Elevations from different datums are not compared without a documented normalization.
Trend and historical context
Trend describes a parameter’s change over a stated input window. Percentiles require a sufficient seasonal baseline; the application withholds a percentile when fewer than 20 comparable values are available, while production operations require a stronger multi-year eligibility gate. Derived statements store calculation version, baseline window, input digest, and generation time.
Ingestion and caching
Background jobs batch source requests, use idempotent upserts, and record each source run. Public requests read the database and cache, not an upstream API. On source failure, the last observation remains with an honest stale state.
Alerts
Thresholds use canonical units. After a trigger, the rule disarms until it clears the user’s hysteresis buffer. Event idempotency keys and an email outbox prevent duplicate deliveries during retries.