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
@spec broadcast_cache_changed(String.t()) :: broadcast_result()
Broadcasts that the cache state has changed (cache regenerated, memory loaded, etc).
Broadcasts a form state change to all subscribers.
Options:
:source- The source identifier to prevent self-echoing
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.
The source is the socket.id of the saver, so they don't reload their own save.
Broadcasts a sync request for new joiners to get current state.
Broadcasts a sync response with current form state.
@spec broadcast_group_created(map()) :: broadcast_result()
Broadcasts a group created event.
@spec broadcast_group_deleted(String.t()) :: broadcast_result()
Broadcasts a group deleted event.
@spec broadcast_group_updated(map()) :: broadcast_result()
Broadcasts a group updated event.
Returns the broadcast identifier for a post.
Always uses uuid — it's present on every post regardless of mode.
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.
Broadcasts a post deleted event.
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.
Broadcasts a post updated event with a minimal payload (uuid + slug).
See broadcast_post_created/2 for rationale on the trimmed payload.
Broadcasts that a new version was created for a post (to post-level topic).
@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).
@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.
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.
@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).
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.
Payload is trimmed to %{uuid:, slug:} — receivers re-fetch the post
to get the new available_versions/version_statuses/etc.
@spec broadcast_version_deleted(String.t(), String.t(), pos_integer()) :: broadcast_result()
Broadcasts that a version was deleted from a post.
@spec broadcast_version_live_changed(String.t(), String.t(), pos_integer() | nil) :: broadcast_result()
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.
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"
Returns the presence topic for tracking editors of a post.
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"
Returns the global topic for editor activity across a group. Used by group listing to show who's editing what.
@spec groups_topic() :: String.t()
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.
@spec subscribe_to_cache(String.t()) :: subscription_result()
Subscribes the current process to cache updates for a group.
@spec subscribe_to_editor_form(String.t()) :: subscription_result()
Subscribes to collaborative events for a specific editor form.
@spec subscribe_to_group_editors(String.t()) :: subscription_result()
Subscribes to editor activity for a group (used by group listing).
@spec subscribe_to_groups() :: subscription_result()
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.
@spec subscribe_to_posts(String.t()) :: subscription_result()
Subscribes the current process to post updates for a group.
@spec unsubscribe_from_cache(String.t()) :: :ok
Unsubscribes the current process from cache updates for a group.
@spec unsubscribe_from_editor_form(String.t()) :: :ok
Unsubscribes from collaborative events for a specific editor form.
@spec unsubscribe_from_group_editors(String.t()) :: :ok
Unsubscribes from editor activity for a group.
@spec unsubscribe_from_groups() :: :ok
Unsubscribes the current process from group updates.
Unsubscribes from translation updates for a specific post.
Unsubscribes from version updates for a specific post.
@spec unsubscribe_from_posts(String.t()) :: :ok
Unsubscribes the current process from post updates for a group.