End-to-end CRUD scaffold for per-site, per-antenna RF coverage prediction. Schema, context, antenna registry, Oban worker stub, and three LiveViews are wired up; the actual ITM + LIDAR + buildings compute pipeline lands in a follow-up. - Migration + Coverage schema with full validation (RF params, pixel- budget cap, antenna_slug existence). organization_id excluded from cast (programmatic-only). - Coverages context: org-scoped CRUD, validate_site_in_organization rejects cross-tenant site_id refs at insert/update, queue_compute with PubSub broadcast on per-coverage and per-org topics. - MSI Planet .ant parser + persistent_term registry loaded at boot from priv/antennas/. Two synthetic .ant fixtures (omni + 90deg sector) bundled. - CoverageWorker on new :coverage Oban queue (concurrency 2). Job args carry organization_id; worker refuses to run on org mismatch. Stub flips status to "failed" with "compute not yet implemented" so the UI flow is exercisable. - LiveViews: index (org-wide, live status updates), form (antenna picker grouped by manufacturer), show (status banners, params panel, map placeholder). Sidebar nav link added. - Routes /coverage, /coverage/new, /coverage/:id, /coverage/:id/edit under :require_authenticated_user_with_default_org. - 41 new tests covering schema validation, .ant parsing, context CRUD with cross-org guards, Oban job enqueue.
48 lines
1.5 KiB
Elixir
48 lines
1.5 KiB
Elixir
defmodule Towerops.Repo.Migrations.CreateCoverages do
|
|
use Ecto.Migration
|
|
|
|
def change do
|
|
create table(:coverages, primary_key: false) do
|
|
add :id, :binary_id, primary_key: true
|
|
add :site_id, references(:sites, type: :binary_id, on_delete: :delete_all), null: false
|
|
|
|
add :organization_id, references(:organizations, type: :binary_id, on_delete: :delete_all),
|
|
null: false
|
|
|
|
add :name, :string, null: false
|
|
add :antenna_slug, :string, null: false
|
|
|
|
add :height_agl_m, :float, null: false
|
|
add :azimuth_deg, :float, null: false
|
|
add :downtilt_deg, :float, null: false, default: 0.0
|
|
add :frequency_mhz, :integer, null: false
|
|
add :eirp_dbm, :float, null: false
|
|
|
|
add :radius_m, :integer, null: false
|
|
add :cell_size_m, :integer, null: false
|
|
add :receiver_height_m, :float, null: false, default: 3.0
|
|
add :rx_threshold_dbm, :float, null: false, default: -90.0
|
|
|
|
add :status, :string, null: false, default: "draft"
|
|
add :progress_pct, :integer, null: false, default: 0
|
|
add :error_message, :text
|
|
|
|
add :computed_at, :utc_datetime
|
|
|
|
add :bbox_min_lat, :float
|
|
add :bbox_max_lat, :float
|
|
add :bbox_min_lon, :float
|
|
add :bbox_max_lon, :float
|
|
|
|
add :raster_path, :string
|
|
add :png_path, :string
|
|
|
|
timestamps(type: :utc_datetime)
|
|
end
|
|
|
|
create unique_index(:coverages, [:site_id, :name], name: :coverages_site_id_name_index)
|
|
|
|
create index(:coverages, [:organization_id])
|
|
create index(:coverages, [:status])
|
|
end
|
|
end
|