# `PhoenixKitCatalogue.Catalogue.PubSub`
[🔗](https://github.com/BeamLabEU/phoenix_kit_catalogue/blob/0.1.14/lib/phoenix_kit_catalogue/catalogue/pub_sub.ex#L1)

Real-time fan-out for catalogue mutations.

Every successful write in the Catalogue context broadcasts a small
`{:catalogue_data_changed, kind, uuid, parent_catalogue_uuid}` event
to a single shared topic. List/detail LiveViews `subscribe/0` once in
`mount/3` (after `connected?(socket)`) and re-fetch the affected
slice on any event, so two admins editing the same data converge
without manual refresh.

`parent_catalogue_uuid` lets a detail LV cheaply ignore broadcasts
for unrelated catalogues — without it, *every* item edit anywhere in
the system would force every open detail page to reload its slice.
Global resources (manufacturers, suppliers, manufacturer↔supplier
links) carry `nil` here; consumers that care about them subscribe
to the `kind` regardless of parent.

Payloads are intentionally minimal — UUID + kind + parent, no record
data — to (a) avoid leaking field-level changes through PubSub, and
(b) keep the consumer in charge of how much to re-load (single row
vs full list).

Subscriptions are cleaned up automatically when the LV process
terminates; callers don't need to unsubscribe.

# `event`

```elixir
@type event() ::
  {:catalogue_data_changed, kind(), Ecto.UUID.t() | nil, Ecto.UUID.t() | nil}
```

Event message format for `handle_info/2`.

# `kind`

```elixir
@type kind() ::
  :catalogue
  | :category
  | :item
  | :manufacturer
  | :supplier
  | :smart_rule
  | :links
```

Resource kind that mutated.

# `broadcast`

```elixir
@spec broadcast(kind(), Ecto.UUID.t() | nil, Ecto.UUID.t() | nil) :: :ok
```

Broadcasts a `{:catalogue_data_changed, kind, uuid, parent_catalogue_uuid}`
event after a successful write.

* `uuid` — UUID of the resource that mutated; `nil` when the change
  isn't tied to a specific record (e.g. a bulk link sync).
* `parent_catalogue_uuid` — UUID of the catalogue that contains the
  mutated resource, or the UUID itself for `kind: :catalogue` events.
  Pass `nil` for resources that aren't scoped to a single catalogue
  (`:manufacturer`, `:supplier`, `:links`); detail LVs use this to
  filter out cross-catalogue noise.

# `subscribe`

```elixir
@spec subscribe() :: :ok | {:error, term()}
```

Subscribes the current process to the catalogue PubSub topic.

Call from `mount/3` guarded by `connected?(socket)` so the
disconnected (initial render) pass doesn't subscribe and never
unsubscribes. Do this **after** any subscription requirements but
**before** the initial DB load to avoid a race where a write between
the load and the subscribe leaves the UI stale.

# `topic`

```elixir
@spec topic() :: String.t()
```

Returns the canonical topic name. Useful for tests.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
