defmodule ToweropsWeb.GraphQL.Subscriptions do @moduledoc """ Publishes events to GraphQL subscriptions. Each function builds the subscription payload and calls `Absinthe.Subscription.publish/3` to push to connected subscribers. """ @doc """ Publishes a device status change event. Publishes to both org-wide and device-specific subscription topics. """ def publish_device_status(device_id, org_id, %{device_name: device_name, status: status}) do payload = %{ device_id: device_id, device_name: device_name, status: status, changed_at: to_string(DateTime.utc_now()) } Absinthe.Subscription.publish( ToweropsWeb.Endpoint, payload, device_status_changed: "gql:device_status:#{org_id}", device_status_changed: "gql:device_status:#{org_id}:#{device_id}" ) end @doc """ Publishes an alert lifecycle event (created, acknowledged, resolved). Accepts both Alert structs and plain maps. """ def publish_alert_event(alert, event_type) do payload = %{ alert_id: Map.get(alert, :id), alert_type: Map.get(alert, :alert_type), severity: Map.get(alert, :severity), message: Map.get(alert, :message), device_id: Map.get(alert, :device_id), event_type: event_type, triggered_at: to_string(Map.get(alert, :triggered_at)) } org_id = Map.get(alert, :organization_id) Absinthe.Subscription.publish( ToweropsWeb.Endpoint, payload, alert_event: "gql:alerts:#{org_id}" ) end @doc """ Publishes a batch of sensor readings for a device. """ def publish_sensor_readings(device_id, org_id, device_name, readings) do payload = %{ device_id: device_id, device_name: device_name, readings: readings } Absinthe.Subscription.publish( ToweropsWeb.Endpoint, payload, sensor_readings_updated: "gql:sensor_readings:#{org_id}:#{device_id}" ) end end