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.
- 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
Backfill page now sums child partition stats for partitioned tables
like hrrr_profiles (relkind 'p') which were excluded by the relkind
'r' filter. Contacts map defers Leaflet init to requestAnimationFrame
so the flex container has dimensions before map initialization.
SRTM profiles no longer abort on missing tiles — water/ocean areas
return 0m elevation instead of failing the entire profile and falling
back to the rate-limited API. Elevation client and viewshed now pass
download: true to auto-fetch missing tiles from S3. NFS mount changed
to writable so downloaded tiles persist across pods.
Replace the JS-built Leaflet control panel with a server-side
sidebar (desktop) and mobile floating controls. Band checkboxes,
callsign filter, and nav links now match the main propagation map
layout. Filter state managed by LiveView, pushed to JS via events.
Registered users can suggest edits to any contact's core fields
(callsigns, grids, band, mode, timestamp). Edits enter an admin
approval queue with field-by-field diff view. On approve, changes
are applied and enrichment re-enqueued if grids/band changed.
Users receive email notification on approve or reject.
Also updates dependabot.yml for mix ecosystem.
- Callsign input filters contacts where either station matches
(case-insensitive substring match, debounced 300ms)
- Band checkboxes now show per-band count of visible contacts
- All/None buttons for quick band selection
- Header count updates dynamically with filters
- Complete rewrite: rebuilds map on any filter change instead of
toggling individual layers (simpler, handles cross-filter correctly)
The sidebar and mobile floating controls overlay the dark map tiles
but inherited light theme colors, making dropdowns, inputs, and
menus invisible (white-on-white). Adding data-theme="dark" forces
all daisyUI components within these containers to use dark variants
regardless of the page's theme setting.
When clicking a grid point, fetches the latest NEXRAD composite
reflectivity and identifies rain cells within 300 km that could
enable rain scatter contacts. Shows:
- Scatter classification (excellent/good/marginal/none)
- Top 3 cells with dBZ, distance, bearing, and relative signal
- Colored circle markers on the map at rain cell locations
- Markers sized by reflectivity, colored by intensity
Uses simplified bistatic radar equation accounting for reflectivity,
frequency-dependent scattering (Rayleigh/Mie), and R^4 path loss.
NEXRAD cells sampled every ~5 km within bounding box for efficiency.
Terrain elevations now include the earth bulge correction, so the
profile visually humps up in the middle relative to the straight
LOS beam — showing how the curved earth rises into the signal path.
Uses actual k-factor from HRRR refractivity when available, otherwise
standard 4/3. For a 300 km path at k=4/3, the midpoint bulge is
~2,650 m (8,700 ft).
When clicking a grid point with ducting, the panel now shows each
duct layer with base-top height in feet, thickness in meters, and
minimum trapped frequency. Data flows from Duct.analyze through
the scoring factors as a ducts array.
- Update all 9 hardcoded weights to match recalibrated values
- Add missing PWAT factor (11.3% weight) to FACTOR_META and FACTOR_ORDER
- Reorder factors by weight (highest first)
- Fix pressure explanation (low pressure is better, not rising)
- Add PWAT factor explanation (beneficial vs harmful by band)
- Show duct info panel when native data detects ducting layers
(count, thickness, minimum trapped frequency)
- Replace stale April 2026 manual weights with recalibrated values
- Document native hybrid-sigma data in data flow section
- Note refractivity factor now uses native 10-50m resolution
- Add hourly grid integration section to Part 12
- Expose duct_info (count, freq, thickness) in scoring factors for UI