PhoenixKitCRM.PubSub (PhoenixKitCRM v0.2.4)

Copy Markdown View Source

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 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).

Unsubscribes the calling process from a topic.

Functions

broadcast_interaction(event, interaction)

@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.

broadcast_to_contacts(event, interaction_uuid, contact_uuids)

@spec broadcast_to_contacts(atom(), binary(), [binary()]) :: :ok

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).

involved_contact_uuids(interaction)

@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).

subscribe(topic)

@spec subscribe(String.t()) :: :ok | {:error, term()}

Subscribes the calling process to a topic.

topic_contact_interactions(contact_uuid)

@spec topic_contact_interactions(binary()) :: String.t()

Topic for the interaction feed of a single contact (as subject or party).

unsubscribe(topic)

@spec unsubscribe(String.t()) :: :ok

Unsubscribes the calling process from a topic.