Commit graph

725 commits

Author SHA1 Message Date
6c334d6e18 Cache /contacts, fix map blink, make mode optional
- Add contacts_inserted_at_desc_id_desc_idx so /contacts list runs as an
  Index Scan (~0.4ms) instead of a Seq Scan + top-N heapsort (~77ms on
  58k rows)
- Add Microwaveprop.Cache: tiny ETS-backed TTL cache for memoizing
  expensive-but-stale-tolerant values
- Cache total_entries for unsearched /contacts page loads (30s TTL,
  invalidated on insert)
- Cache the entire /contacts/map payload (pre-encoded JSON + band list),
  moving load_contacts into Radio.contact_map_payload; invalidated on
  new contact insert. Mount goes from ~150-300ms to ~5ms.
- Fix /map overlay blinking on load: reuse the Leaflet GridLayer across
  renderScores calls and just redraw() against the updated ScoreGrid,
  instead of removeLayer + new layer which flashed between tile regens
- Make mode optional on submission: schema change (null: true),
  submission_changeset no longer requires it, blank strings normalise to
  nil, CSV import accepts 6-column (no mode) or 7-column layouts
- core_components .input adds a red asterisk to labels when required,
  giving users a visual cue for which fields must be filled on /submit
2026-04-12 12:47:25 -05:00
FluxCD
8b9d0a29dc chore: update prop image to git.mcintire.me/graham/prop:main-1776014809-7bbd6ad [skip ci] 2026-04-12 17:27:25 +00:00
250709a1b2 Add more caching to make the map feel instant
- ScoreCache stores {band, valid_time} as %{{lat, lon} => score} map so
  point lookups are O(1); adds fetch_point/4 and valid_times/1
- available_valid_times/1 reads directly from ScoreCache when warm,
  falls back to DB on cold start
- point_forecast/3 iterates cached valid_times and uses fetch_point/4
  instead of hitting the DB per click
- NexradCache: node-local ETS cache of decoded n0q PNG pixel buffers
  keyed by 5-minute rounded timestamp; skips ~1-5s HTTP+decode on
  concurrent/repeat clicks within the same window
- MapLive: start_async the rain_scatter fetch so point_detail renders
  immediately with a pending marker; push rain_scatter_update when
  NEXRAD resolves
- MapLive: preload all 18 remaining forecast hours for the current
  viewport after mount/band change/propagation_updated; client caches
  them and renders timeline scrubs instantly without a server roundtrip.
  Adds set_selected_time event for fast-path state sync.
- Propagation map JS: forecastCache map + drawScatterMarkers helper,
  timeline click uses preloaded cache when available
2026-04-12 12:26:25 -05:00
FluxCD
8b407c87ee chore: update prop image to git.mcintire.me/graham/prop:main-1776013912-b322e76 [skip ci] 2026-04-12 17:13:23 +00:00
d880201713 Cache propagation scores in ETS, broadcast across cluster
- Add ScoreCache GenServer with node-local ETS table keyed by
  {band, valid_time}, subscribed to "propagation:cache" PubSub topic so
  every pod stays in sync with a single hourly compute
- scores_at/3 checks cache first, falls back to DB and populates on miss
- PropagationGridWorker warms and broadcasts the cache for each band
  after every forecast hour upsert; prunes >2h old entries
- Replace per-pixel string-keyed Map with flat Int8Array over the CONUS
  grid in propagation_map_hook.ts to eliminate allocations in the tile
  rasterization hot loop (interpolateScore / propagationReach)
2026-04-12 12:11:26 -05:00
FluxCD
6fd0958574 chore: update prop image to git.mcintire.me/graham/prop:main-1776008479-61cb7fb [skip ci] 2026-04-12 15:41:48 +00:00
91fb5cda22 Delay disconnect alerts by 3s to avoid flashing on brief hiccups 2026-04-12 10:40:42 -05:00
FluxCD
e3b2d6315d chore: update prop image to git.mcintire.me/graham/prop:main-1776007906-9cef467 [skip ci] 2026-04-12 15:32:47 +00:00
dd13a5f2a5 Fix three security issues
1. Prevent user_id impersonation in contact submissions
   - Remove user_id from submission_changeset cast fields
   - Pass user_id as a separate server-side argument to create_contact/2
   - Client form params can no longer forge account-linked contacts

2. Restrict flag toggle to admins only
   - Add admin? guard to toggle_flag event handler
   - Hide flag button from non-admin users in template

3. Reset enrichment on timestamp edits
   - Add qso_timestamp to the fields that trigger enrichment reset
   - Prevents stale weather/HRRR/IEMRE data after time changes
2026-04-12 10:31:23 -05:00
FluxCD
361a302736 chore: update prop image to git.mcintire.me/graham/prop:main-1776007679-385cffd [skip ci] 2026-04-12 15:28:45 +00:00
FluxCD
a022321235 chore: update prop image to git.mcintire.me/graham/prop:main-1776007633-515b9fc [skip ci] 2026-04-12 15:27:48 +00:00
163883d0dd Fix donate link contrast on dark mode info alert 2026-04-12 10:27:40 -05:00
7fb340bc35 Fix all remaining credo --strict issues (0 issues)
Aliases: add module aliases for 9 nested module references
Apply: replace apply/3 with direct module attribute calls
Line length: break 1 long spec line
Refactoring: extract helpers to reduce complexity and nesting
in show.ex, radio.ex, weather workers, terrain, duct detection,
backfill dashboard, contact map, and mix tasks
2026-04-12 10:26:53 -05:00
9abbb83469 Fix credo warnings: struct specs, length/1, and test patterns
- Replace %Struct{} with Struct.t() in all @spec annotations
- Replace length(x) > 0 with x != [] in test assertions
- Fix multi-line spec struct references in weather.ex
2026-04-12 10:26:53 -05:00
a07a3c56b4 credo 2026-04-12 10:26:53 -05:00
FluxCD
ae4417d594 chore: update prop image to git.mcintire.me/graham/prop:main-1776004759-c9305f9 [skip ci] 2026-04-12 14:39:31 +00:00
2f7a060f95 Increase test DB query timeout to 60s
The ownership_timeout controls how long a process can hold a checkout,
but the per-query Postgrex timeout (default 15s) is separate. Oban
inline mode chains workers synchronously, so individual queries can
exceed 15s under concurrent test load.
2026-04-12 09:38:59 -05:00
FluxCD
3db8bc85a1 chore: update prop image to git.mcintire.me/graham/prop:main-1776004649-d7acdfe [skip ci] 2026-04-12 14:38:32 +00:00
2769e1a948 Increase test DB ownership timeout to 60s
Prevents sporadic sandbox timeout failures under full concurrent
test load (24 async cases competing for DB connections).
2026-04-12 09:37:08 -05:00
FluxCD
48b365af5e chore: update prop image to git.mcintire.me/graham/prop:main-1776004392-a6efe38 [skip ci] 2026-04-12 14:34:28 +00:00
aba4ca538d Add PayPal donate link to footer and about page 2026-04-12 09:34:01 -05:00
53205d53b4 Remove unused CaptureLog import in elevation client test 2026-04-12 09:32:47 -05:00
e0be0587be Fix backfill stat overflow and select text alignment
- Revert enrichment status cards from daisyUI stat to plain containers
  (tabular status rows don't fit the stat component's layout)
- Add overflow-hidden to DB stat cards for large numbers
- Fix select text centering with display:flex + align-items:center
2026-04-12 09:31:51 -05:00
FluxCD
ccd8aba653 chore: update prop image to git.mcintire.me/graham/prop:main-1776003644-873d5ee [skip ci] 2026-04-12 14:21:09 +00:00
d5d0c32745 Use daisyUI components for stats, alerts, cards, and tabs
- about: stat cards → daisyUI stat, warning/donate boxes → alert
- submit: tab buttons → daisyUI tabs-box, info/instruction boxes → alert
- backfill: enrichment/DB stat boxes → daisyUI stat
- beacon show: stats container → daisyUI card
- contact show: info/status boxes → alert, data source cards → card
- ADIF: strip APP_ prefix from app-defined fields, normalize grid case
2026-04-12 09:20:20 -05:00
FluxCD
2d3da359ee chore: update prop image to git.mcintire.me/graham/prop:main-1776002127-8faae2a [skip ci] 2026-04-12 13:56:04 +00:00
51e390959c Add dialyzer specs and types across the codebase
277 @spec/@type annotations added to 58 files covering all public
APIs: contexts (propagation, radio, weather, terrain, beacons,
commercial), GRIB2 decoders, terrain analysis, duct detection,
rain scatter, CSV/ADIF import, weather clients, and all Ecto
schemas. Dialyzer passes with 0 errors.
2026-04-12 08:55:04 -05:00
FluxCD
7a31d730b4 chore: update prop image to git.mcintire.me/graham/prop:main-1775948922-13b8942 [skip ci] 2026-04-11 23:09:14 +00:00
5f803e4c0d Add 6-char subsquare grid overlay and fix map edge rendering
- Show subsquares (5' x 2.5') at zoom >= 11 with lighter styling
- Pad map bounds by 10% so edge tiles always have score data
- Re-send bounds after 500ms to catch late container layout changes
2026-04-11 18:08:18 -05:00
c3becdac9f Show beacon submitter callsign, add donate link, prefer 8-char grids
- Add belongs_to :user on Beacon schema, preload in get_beacon!/1
- Show "Submitted by {callsign}" on beacon detail page
- Add NTMS donation link on the about page
- Change grid preference text to 8 characters (e.g. EM12kp37)
2026-04-11 18:08:18 -05:00
1174ecd9e5 Fix all 12 dialyzer warnings
- Replace MapSet with plain list + `in` (features.ex, scorer_diff.ex)
- Remove undefined Beacon.t() type reference (range_estimate.ex)
- Remove dead else branch in find_region (inversion.ex)
- Handle Nx special values in to_float catch-all (recalibrator.ex)
- Remove unreachable catch-all clauses (hrrr_native_client.ex, ncei_metar_client.ex)
- Remove unnecessary nil guards on always-typed values (show.ex)
- Remove dead sky_note/wind_note non-nil clauses (show.ex)
- Remove dead if-guard on always-truthy derive result (hrrr_native_derive.ex)
- Add @spec to path_integrated_conditions (scorer.ex)
2026-04-11 18:08:18 -05:00
FluxCD
623bb45aee chore: update prop image to git.mcintire.me/graham/prop:main-1775947504-2cf4c21 [skip ci] 2026-04-11 22:46:09 +00:00
d990884cea Force 24-hour time on UTC timestamp inputs 2026-04-11 17:44:39 -05:00
c6bf333c98 Add dialyxir for static analysis
PLT stored in priv/plts/ (gitignored). Run with `mix dialyzer`.
2026-04-11 17:43:18 -05:00
FluxCD
d137975739 chore: update prop image to git.mcintire.me/graham/prop:main-1775947163-2ecd803 [skip ci] 2026-04-11 22:40:08 +00:00
5bcf579009 Add ADIF file upload for contact submission
Parse ADIF tagged-data format with fuzzy frequency-to-band matching
(nearest microwave band for any freq >= 900 MHz). Supports STATION_CALLSIGN,
OPERATOR, CALL, GRIDSQUARE, MY_GRIDSQUARE, FREQ, BAND, QSO_DATE, TIME_ON.
Same dedup and preview/commit flow as CSV upload.

Also fix select dropdown text alignment in daisyUI.
2026-04-11 17:39:05 -05:00
FluxCD
1111e64bdd chore: update prop image to git.mcintire.me/graham/prop:main-1775946667-67df5fc [skip ci] 2026-04-11 22:32:08 +00:00
25c703401b Link to existing contact on duplicate submission
Return the conflicting contact from create_contact so the UI can redirect
to it with a flash message instead of just showing a form error.
2026-04-11 17:30:46 -05:00
FluxCD
231f1d9a14 chore: update prop image to git.mcintire.me/graham/prop:main-1775946446-9c64d75 [skip ci] 2026-04-11 22:28:06 +00:00
cdb59be6d7 Deduplicate single contact submissions same as CSV import
Check for existing contacts with the same station pair (order-independent),
band, and grids within a 1-hour window before inserting.
2026-04-11 17:27:03 -05:00
FluxCD
3334db5a08 chore: update prop image to git.mcintire.me/graham/prop:main-1775946134-cd14a06 [skip ci] 2026-04-11 22:23:05 +00:00
4ca8c5d3bc Add Q65 contact mode 2026-04-11 17:21:45 -05:00
FluxCD
a37b4cb929 chore: update prop image to git.mcintire.me/graham/prop:main-1775945466-55b12bc [skip ci] 2026-04-11 22:14:01 +00:00
58e4f55ba8 Curved earth surface in elevation profile with ducts following curvature 2026-04-11 17:10:38 -05:00
FluxCD
d99b7a6ea2 chore: update prop image to git.mcintire.me/graham/prop:main-1775944792-4a8d1a1 [skip ci] 2026-04-11 22:02:00 +00:00
1f368f9b61 Convert all JavaScript to TypeScript with type annotations
- Rename all .js files to .ts in assets/js/
- Add interfaces for hook state, data structures, and event payloads
- Add type annotations to function parameters and return types
- Create type declarations for vendor deps (Leaflet, Chart.js, Phoenix, topbar)
- Update tsconfig.json for strict TypeScript checking
- Update esbuild entry point to app.ts
2026-04-11 16:59:28 -05:00
FluxCD
9b4d9d08dd chore: update prop image to git.mcintire.me/graham/prop:main-1775944179-5ad3941 [skip ci] 2026-04-11 21:50:54 +00:00
3d550f24c6 Defer map init and sendBounds to requestAnimationFrame in all map hooks 2026-04-11 16:49:17 -05:00
FluxCD
bfbe077257 chore: update prop image to git.mcintire.me/graham/prop:main-1775944065-d52172c [skip ci] 2026-04-11 21:47:53 +00:00
08ffc7e028 Admin direct edit on contact show page, suggest edit for non-admins 2026-04-11 16:46:46 -05:00