prop/lib/microwaveprop_web
Graham McIntire a14f14485e
perf(weather): serve /weather from chunked scalar artifacts
Move the /weather render path off raw HRRR profile decoding + per-cell
SoundingParams + WeatherLayers derivation. The dominant cost was
re-deriving the same scalar fields on every viewport pan and timeline
scrub.

Server side:

- New Microwaveprop.Weather.ScalarFile persists pre-derived scalar
  rows on NFS, bucketed into 5°×5° chunk files under
  <base>/weather_scalars/<iso>/<lat_band>_<lon_band>.etf.gz. Viewport
  reads only decode the chunks that overlap the requested bounds;
  point-detail clicks read exactly one chunk.
- weather_grid_at/2 and weather_point_detail/3 prefer ScalarFile;
  ProfilesFile is now the cold-start fallback only.
- warm_grid_cache_and_broadcast/1 and warm_grid_cache_from_latest_profile/0
  also persist the scalar artifact, and the cold-derive path kicks
  off a per-valid_time-locked async materialization so the next
  reader gets the cheap path.
- NotifyListener.handle_propagation_ready/1 fires
  Weather.materialize_scalar_file/1 in a detached Task on the Rust
  pipeline's NOTIFY propagation_ready, so steady-state forecast hours
  arrive with their scalar artifact already on disk.
- available_weather_valid_times/0 unions ScalarFile + ProfilesFile so
  the timeline survives an aggressive retention sweep on either side.

Browser side (finding #8):

- Mount the legend Leaflet control once and patch its inner content
  on layer changes instead of remove + re-add on every renderLayer.
- renderTimeline now keys off the rendered button set: selection-only
  updates take an applyTimelineSelection patch path that restyles
  existing buttons in place. Full innerHTML rebuild only fires when
  timelineData itself changes.

Also fixes a credo nesting-depth flag in tile_renderer.ex by extracting
interpolate_pair/2 from the inner anonymous function.
2026-04-28 17:15:36 -05:00
..
components chore(layout): move deploy stamp from navbar to footer 2026-04-25 15:20:55 -05:00
controllers perf(weather): serve /weather from chunked scalar artifacts 2026-04-28 17:15:36 -05:00
live perf(weather): serve /weather from chunked scalar artifacts 2026-04-28 17:15:36 -05:00
plugs fix(remote_ip): log IPv6 in canonical hex via :inet.ntoa 2026-04-25 18:05:46 -05:00
endpoint.ex fix(web): suppress HEAD request logs 2026-04-22 16:50:58 -05:00
live_helpers.ex refactor: deduplicate helpers and simplify Scorer 2026-04-28 14:14:34 -05:00
live_table_footer.ex Show windowed page list in live_table footer 2026-04-13 10:02:19 -05:00
live_table_resource.ex fix(dialyzer): actually fix LiveTable warnings instead of hiding them 2026-04-21 12:58:10 -05:00
location_resolver.ex refactor: deduplicate helpers and simplify Scorer 2026-04-28 14:14:34 -05:00
metrics_plug.ex fix(metrics): serve scrape body via PromEx.get_metrics 2026-04-18 16:50:37 -05:00
router.ex perf(weather): serve /weather from chunked scalar artifacts 2026-04-28 17:15:36 -05:00
skew_t.ex Rename ERA5 → NARR across the codebase 2026-04-16 09:22:23 -05:00
telemetry.ex perf(telemetry): cut hot-path overhead on scores_at cache hits 2026-04-20 16:12:01 -05:00
user_auth.ex fix(dialyzer): clear 125+ warnings under strict flags 2026-04-21 10:30:06 -05:00