Real-time updates for CRM interactions, backed by PhoenixKit.PubSub.Manager.
An interaction appears in the feed of every contact it involves — the subject
contact (interactions.contact_uuid) and any resolved party contacts — so
a change fans out to each of their per-contact topics. A contact's
Interactions tab subscribes to its own topic; any add/edit/delete to an
interaction touching that contact pushes a live refresh.
Messages are {:crm, event, payload} tuples where event is one of
:interaction_created | :interaction_updated | :interaction_deleted and
payload is %{interaction_uuid: uuid}.
Topics are global (no tenant partitioning) — but the per-contact topic is keyed
by uuid, so you can't subscribe without already knowing the contact, which
bounds the fan-out. (Mirrors phoenix_kit_projects — tenant scoping is a
framework-wide gap, not a CRM one.)
Summary
Functions
Fans an interaction change out to every involved contact's feed topic.
Broadcasts a CRM list event on the global crm:lists topic — {:crm, event, payload}, same tuple shape as broadcast_interaction/2.
Broadcasts an interaction change to an EXPLICIT set of contact feed topics.
Subject contact + any resolved party contacts (deduped, nils dropped). Tolerates parties not being preloaded (treats them as none).
Subscribes the calling process to a topic.
Topic for the interaction feed of a single contact (as subject or party).
Topic for CRM contact-list live updates (membership changes, counters).
Unsubscribes the calling process from a topic.
Functions
@spec broadcast_interaction(atom(), PhoenixKitCRM.Schemas.Interaction.t()) :: :ok
Fans an interaction change out to every involved contact's feed topic.
Best-effort: never raises out to the caller — a saved interaction must not be reported as failed just because the realtime broadcast hiccuped. Call it AFTER the DB commit.
Broadcasts a CRM list event on the global crm:lists topic — {:crm, event, payload}, same tuple shape as broadcast_interaction/2.
NET-NEW for CRM: PhoenixKitCRM.PartyRoles deliberately doesn't broadcast
(see its moduledoc), but list membership counters are shown live in the
admin UI, so PhoenixKitCRM.Lists broadcasts here on every mutation.
Best-effort: never raises out to the caller. Call it AFTER the DB commit.
Broadcasts an interaction change to an EXPLICIT set of contact feed topics.
Used by updates, which must reach the union of the old and new involved contacts so a contact dropped by an edit still gets a refresh to remove the entry. Best-effort (rescued).
@spec involved_contact_uuids(PhoenixKitCRM.Schemas.Interaction.t()) :: [binary()]
Subject contact + any resolved party contacts (deduped, nils dropped). Tolerates parties not being preloaded (treats them as none).
Subscribes the calling process to a topic.
Topic for the interaction feed of a single contact (as subject or party).
@spec topic_lists() :: String.t()
Topic for CRM contact-list live updates (membership changes, counters).
@spec unsubscribe(String.t()) :: :ok
Unsubscribes the calling process from a topic.