POST /api/v1/beacon-monitor/measurements accepts one measurement per integration window from a propmonitor client, authenticated by the BeaconMonitor token. Records noise floor, signal peak/avg dBFS, SNR, signal-active-fraction, gain, and frequency for later correlation against weather and propagation scores. Beacon UUID must resolve to an approved + on-the-air beacon (404 otherwise — the client drops 404s without retry). Retries with the same (monitor, beacon, measured_at) are idempotent: a unique index makes the second insert a 409. Every accepted upload stamps the monitor's last_seen_at — measurements *are* the heartbeat. MonitorAuth is a separate plug from the user API-token Auth plug; monitors are not users. The rate limiter buckets each monitor by id so retry storms after a 5xx don't burn the shared anon-IP bucket.
43 lines
1.7 KiB
Elixir
43 lines
1.7 KiB
Elixir
defmodule Microwaveprop.Repo.Migrations.CreateBeaconMeasurements do
|
|
use Ecto.Migration
|
|
|
|
def change do
|
|
create table(:beacon_measurements, primary_key: false) do
|
|
add :id, :binary_id, primary_key: true
|
|
|
|
add :beacon_id, references(:beacons, type: :binary_id, on_delete: :delete_all), null: false
|
|
|
|
add :monitor_id, references(:beacon_monitors, type: :binary_id, on_delete: :delete_all),
|
|
null: false
|
|
|
|
add :measured_at, :utc_datetime, null: false
|
|
add :frequency_hz, :bigint, null: false
|
|
add :integration_s, :integer, null: false
|
|
add :passband_hz, :float, null: false
|
|
add :gain_db, :float, null: false
|
|
|
|
add :noise_floor_dbfs, :float, null: false
|
|
add :signal_peak_dbfs, :float, null: false
|
|
add :signal_avg_dbfs, :float, null: false
|
|
add :snr_peak_db, :float, null: false
|
|
add :snr_avg_db, :float, null: false
|
|
add :signal_active_fraction, :float, null: false
|
|
|
|
add :propmonitor_version, :string, null: false
|
|
|
|
timestamps(type: :utc_datetime)
|
|
end
|
|
|
|
# Time-series query patterns: latest-N for one monitor, latest-N for one
|
|
# beacon, and joint monitor+beacon trends.
|
|
create index(:beacon_measurements, [:monitor_id, "measured_at DESC"])
|
|
create index(:beacon_measurements, [:beacon_id, "measured_at DESC"])
|
|
|
|
# Idempotency: the client retries on 5xx with the same `measured_at`. A
|
|
# given monitor cannot legitimately produce two distinct measurements for
|
|
# the same beacon at the same start-of-window timestamp.
|
|
create unique_index(:beacon_measurements, [:monitor_id, :beacon_id, :measured_at],
|
|
name: :beacon_measurements_monitor_beacon_measured_at_idx
|
|
)
|
|
end
|
|
end
|