PhoenixKit.Modules.Publishing.PubSub (PhoenixKitPublishing v0.1.6)

Copy Markdown View Source

PubSub integration for real-time publishing updates.

Provides broadcasting and subscription for post changes, enabling live updates across all connected admin clients.

Features

  • Post lifecycle events (create, update, delete, status change)
  • Collaborative editing with real-time form state sync
  • Owner/spectator model for concurrent editing

Summary

Functions

Broadcasts that the cache state has changed (cache regenerated, memory loaded, etc).

Broadcasts a form state change to all subscribers.

Broadcasts that a user started editing a post.

Broadcasts that a user stopped editing a post.

Broadcasts that a post was saved, so other editors can reload.

Broadcasts a sync request for new joiners to get current state.

Broadcasts a sync response with current form state.

Broadcasts a group created event.

Broadcasts a group deleted event.

Broadcasts a group updated event.

Returns the broadcast identifier for a post.

Broadcasts a post created event with a minimal payload (uuid + slug).

Broadcasts a post deleted event.

Broadcasts a post status changed event with a minimal payload (uuid + slug).

Broadcasts a post updated event with a minimal payload (uuid + slug).

Broadcasts that a new version was created for a post (to post-level topic).

Broadcasts that a version was deleted from a post (to post-level topic).

Broadcasts that the live/published version changed (to post-level topic). Includes source_id so receivers can ignore their own broadcasts.

Broadcasts that AI translation has completed (success or partial failure). Sent to both posts_topic (for group listing) and post_translations_topic (for editor).

Broadcasts that a new translation was created for a post.

Broadcasts that a translation was deleted from a post.

Broadcasts AI translation progress (after each language completes). Sent to both posts_topic (for group listing) and post_translations_topic (for editor).

Broadcasts that AI translation has started. Sent to both posts_topic (for group listing) and post_translations_topic (for editor).

Broadcasts that a new version was created for a post.

Broadcasts that a version was deleted from a post.

Broadcasts that the live version changed for a post.

Returns the topic for cache updates for a specific group.

Returns the topic for a specific editor form.

Returns the presence topic for tracking editors of a post.

Generates a form key for a post being edited.

Returns the global topic for editor activity across a group. Used by group listing to show who's editing what.

Returns the topic for global group updates (create, delete).

Returns the topic for a specific post's translation updates. This allows all editors of different language versions to receive updates when new translations are added.

Returns the topic for a specific post's version updates. This allows editors to receive notifications when versions are created/deleted.

Returns the topic for a specific group's posts.

Subscribes the current process to cache updates for a group.

Subscribes to collaborative events for a specific editor form.

Subscribes to editor activity for a group (used by group listing).

Subscribes the current process to group updates (creation/deletion).

Subscribes to translation updates for a specific post.

Subscribes to version updates for a specific post.

Subscribes the current process to post updates for a group.

Unsubscribes the current process from cache updates for a group.

Unsubscribes from collaborative events for a specific editor form.

Unsubscribes from editor activity for a group.

Unsubscribes the current process from group updates.

Unsubscribes from translation updates for a specific post.

Unsubscribes from version updates for a specific post.

Unsubscribes the current process from post updates for a group.

Functions

broadcast_cache_changed(group_slug)

@spec broadcast_cache_changed(String.t()) :: broadcast_result()

Broadcasts that the cache state has changed (cache regenerated, memory loaded, etc).

broadcast_editor_form_change(form_key, payload, opts \\ [])

@spec broadcast_editor_form_change(String.t(), map(), keyword()) :: broadcast_result()

Broadcasts a form state change to all subscribers.

Options:

  • :source - The source identifier to prevent self-echoing

broadcast_editor_joined(group_slug, post_slug, user_info)

@spec broadcast_editor_joined(String.t(), String.t(), map()) :: broadcast_result()

Broadcasts that a user started editing a post.

broadcast_editor_left(group_slug, post_slug, user_info)

@spec broadcast_editor_left(String.t(), String.t(), map()) :: broadcast_result()

Broadcasts that a user stopped editing a post.

broadcast_editor_saved(form_key, source)

@spec broadcast_editor_saved(String.t(), String.t() | nil) :: broadcast_result()

Broadcasts that a post was saved, so other editors can reload.

The source is the socket.id of the saver, so they don't reload their own save.

broadcast_editor_sync_request(form_key, requester_socket_id)

@spec broadcast_editor_sync_request(String.t(), String.t()) :: broadcast_result()

Broadcasts a sync request for new joiners to get current state.

broadcast_editor_sync_response(form_key, requester_socket_id, state)

@spec broadcast_editor_sync_response(String.t(), String.t(), map()) ::
  broadcast_result()

Broadcasts a sync response with current form state.

broadcast_group_created(group)

@spec broadcast_group_created(map()) :: broadcast_result()

Broadcasts a group created event.

broadcast_group_deleted(group_slug)

@spec broadcast_group_deleted(String.t()) :: broadcast_result()

Broadcasts a group deleted event.

broadcast_group_updated(group)

@spec broadcast_group_updated(map()) :: broadcast_result()

Broadcasts a group updated event.

broadcast_id(post)

@spec broadcast_id(map()) :: String.t() | nil

Returns the broadcast identifier for a post.

Always uses uuid — it's present on every post regardless of mode.

broadcast_post_created(group_slug, post)

@spec broadcast_post_created(String.t(), map()) :: broadcast_result()

Broadcasts a post created event with a minimal payload (uuid + slug).

Receivers only need the identifier to refresh their views — sending the full post map risks leaking title/body/metadata into pubsub trace logs.

broadcast_post_deleted(group_slug, post_identifier)

@spec broadcast_post_deleted(String.t(), String.t()) :: broadcast_result()

Broadcasts a post deleted event.

broadcast_post_status_changed(group_slug, post)

@spec broadcast_post_status_changed(String.t(), map()) :: broadcast_result()

Broadcasts a post status changed event with a minimal payload (uuid + slug).

Receivers refresh the post by slug/uuid; the full record never crosses PubSub. See broadcast_post_created/2 for the trust rationale.

broadcast_post_updated(group_slug, post)

@spec broadcast_post_updated(String.t(), map()) :: broadcast_result()

Broadcasts a post updated event with a minimal payload (uuid + slug).

See broadcast_post_created/2 for rationale on the trimmed payload.

broadcast_post_version_created(group_slug, post_slug, version_info)

@spec broadcast_post_version_created(String.t(), String.t(), map()) ::
  broadcast_result()

Broadcasts that a new version was created for a post (to post-level topic).

broadcast_post_version_deleted(group_slug, post_slug, version)

@spec broadcast_post_version_deleted(String.t(), String.t(), pos_integer()) ::
  broadcast_result()

Broadcasts that a version was deleted from a post (to post-level topic).

broadcast_post_version_published(group_slug, post_slug, version, source_id \\ nil)

@spec broadcast_post_version_published(
  String.t(),
  String.t(),
  pos_integer() | nil,
  String.t() | nil
) :: broadcast_result()

Broadcasts that the live/published version changed (to post-level topic). Includes source_id so receivers can ignore their own broadcasts.

broadcast_translation_completed(group_slug, post_slug, results)

@spec broadcast_translation_completed(String.t(), String.t(), map()) ::
  broadcast_result()

Broadcasts that AI translation has completed (success or partial failure). Sent to both posts_topic (for group listing) and post_translations_topic (for editor).

broadcast_translation_created(group_slug, post_slug, language)

@spec broadcast_translation_created(String.t(), String.t(), String.t()) ::
  broadcast_result()

Broadcasts that a new translation was created for a post.

broadcast_translation_deleted(group_slug, post_slug, language)

@spec broadcast_translation_deleted(String.t(), String.t(), String.t()) ::
  broadcast_result()

Broadcasts that a translation was deleted from a post.

broadcast_translation_progress(group_slug, post_slug, completed, total, last_language)

@spec broadcast_translation_progress(
  String.t(),
  String.t(),
  non_neg_integer(),
  non_neg_integer(),
  String.t()
) :: broadcast_result()

Broadcasts AI translation progress (after each language completes). Sent to both posts_topic (for group listing) and post_translations_topic (for editor).

broadcast_translation_started(group_slug, post_slug, target_languages)

@spec broadcast_translation_started(String.t(), String.t(), [String.t()]) ::
  broadcast_result()

Broadcasts that AI translation has started. Sent to both posts_topic (for group listing) and post_translations_topic (for editor).

broadcast_version_created(group_slug, post)

@spec broadcast_version_created(String.t(), map()) :: broadcast_result()

Broadcasts that a new version was created for a post.

Payload is trimmed to %{uuid:, slug:} — receivers re-fetch the post to get the new available_versions/version_statuses/etc.

broadcast_version_deleted(group_slug, post_identifier, version)

@spec broadcast_version_deleted(String.t(), String.t(), pos_integer()) ::
  broadcast_result()

Broadcasts that a version was deleted from a post.

broadcast_version_live_changed(group_slug, post_identifier, version)

@spec broadcast_version_live_changed(String.t(), String.t(), pos_integer() | nil) ::
  broadcast_result()

Broadcasts that the live version changed for a post.

cache_topic(group_slug)

@spec cache_topic(String.t()) :: String.t()

Returns the topic for cache updates for a specific group.

editor_form_topic(form_key)

@spec editor_form_topic(String.t()) :: String.t()

Returns the topic for a specific editor form.

The form_key uniquely identifies a post being edited:

  • For existing posts: "group_slug:post_path" or "group_slug:slug"
  • For new posts: "group_slug:new:language"

editor_presence_topic(form_key)

@spec editor_presence_topic(String.t()) :: String.t()

Returns the presence topic for tracking editors of a post.

generate_form_key(group_slug, post, mode \\ :edit)

@spec generate_form_key(String.t(), map(), :edit | :new) :: String.t()

Generates a form key for a post being edited.

The form key includes the language to allow concurrent editing of different translations of the same post.

Examples

generate_form_key("blog", %{path: "blog/my-post/v1/en"})
# => "blog:blog/my-post/v1/en"

generate_form_key("blog", %{slug: "my-post", language: "en"})
# => "blog:my-post:en"

generate_form_key("blog", %{slug: "my-post", language: "en"}, :new)
# => "blog:new:en"

group_editors_topic(group_slug)

@spec group_editors_topic(String.t()) :: String.t()

Returns the global topic for editor activity across a group. Used by group listing to show who's editing what.

groups_topic()

@spec groups_topic() :: String.t()

Returns the topic for global group updates (create, delete).

post_translations_topic(group_slug, post_slug)

@spec post_translations_topic(String.t(), String.t()) :: String.t()

Returns the topic for a specific post's translation updates. This allows all editors of different language versions to receive updates when new translations are added.

post_versions_topic(group_slug, post_slug)

@spec post_versions_topic(String.t(), String.t()) :: String.t()

Returns the topic for a specific post's version updates. This allows editors to receive notifications when versions are created/deleted.

posts_topic(group_slug)

@spec posts_topic(String.t()) :: String.t()

Returns the topic for a specific group's posts.

subscribe_to_cache(group_slug)

@spec subscribe_to_cache(String.t()) :: subscription_result()

Subscribes the current process to cache updates for a group.

subscribe_to_editor_form(form_key)

@spec subscribe_to_editor_form(String.t()) :: subscription_result()

Subscribes to collaborative events for a specific editor form.

subscribe_to_group_editors(group_slug)

@spec subscribe_to_group_editors(String.t()) :: subscription_result()

Subscribes to editor activity for a group (used by group listing).

subscribe_to_groups()

@spec subscribe_to_groups() :: subscription_result()

Subscribes the current process to group updates (creation/deletion).

subscribe_to_post_translations(group_slug, post_slug)

@spec subscribe_to_post_translations(String.t(), String.t()) :: subscription_result()

Subscribes to translation updates for a specific post.

subscribe_to_post_versions(group_slug, post_slug)

@spec subscribe_to_post_versions(String.t(), String.t()) :: subscription_result()

Subscribes to version updates for a specific post.

subscribe_to_posts(group_slug)

@spec subscribe_to_posts(String.t()) :: subscription_result()

Subscribes the current process to post updates for a group.

unsubscribe_from_cache(group_slug)

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

Unsubscribes the current process from cache updates for a group.

unsubscribe_from_editor_form(form_key)

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

Unsubscribes from collaborative events for a specific editor form.

unsubscribe_from_group_editors(group_slug)

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

Unsubscribes from editor activity for a group.

unsubscribe_from_groups()

@spec unsubscribe_from_groups() :: :ok

Unsubscribes the current process from group updates.

unsubscribe_from_post_translations(group_slug, post_slug)

@spec unsubscribe_from_post_translations(String.t(), String.t()) :: :ok

Unsubscribes from translation updates for a specific post.

unsubscribe_from_post_versions(group_slug, post_slug)

@spec unsubscribe_from_post_versions(String.t(), String.t()) :: :ok

Unsubscribes from version updates for a specific post.

unsubscribe_from_posts(group_slug)

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

Unsubscribes the current process from post updates for a group.