> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bbrands.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Realtime (Pusher)

> How B Brands delivers realtime events over Pusher Channels: best-effort domain events published by horizon-api and consumed by the frontends through a single shared hook.

<Info>
  This section documents the **B Brands realtime layer** built on
  [Pusher Channels](https://pusher.com/channels). `horizon-api` publishes typed
  domain events (digital-contract lifecycle, Maihue Street / NOC telemetry) to
  per-entity channels; frontends subscribe and react to them.
</Info>

## What this is

Realtime is a **best-effort UX enhancement layered on top of the authoritative
REST/query state — never a source of truth**. When a backend action should
reach a connected client immediately (a contract is signed, a totem sends a
telemetry frame, a NOC alert fires), the server triggers a Pusher event on the
channel that owns that entity. The client reacts, typically by invalidating a
cached query.

<CardGroup cols={2}>
  <Card title="What realtime does" icon="bolt">
    Pushes a lightweight notification so the UI refreshes without waiting for
    the next poll.
  </Card>

  <Card title="What realtime does NOT do" icon="circle-xmark">
    It never carries authoritative state and never guarantees delivery. If a
    message is missed, the REST/query layer is still correct.
  </Card>
</CardGroup>

## Graceful degradation

Pusher credentials are **optional in every environment**:

* Without server credentials, the publisher runs in **log-only** mode (the
  trigger is a no-op) and never throws.
* Without a client key, the subscription hook reports `status: "disabled"` and
  consumers fall back to polling.

<Warning>
  Never treat a Pusher event as a transactional signal. Every consumer must
  remain correct if the event is dropped, duplicated or arrives out of order.
</Warning>

## How the signal flows

```mermaid theme={null}
flowchart LR
    subgraph api [horizon-api]
        producer["Worker / webhook / admin service"]
        publisher["publishContractEvent()"]
        authz["POST /api/v3/realtime/pusher/auth"]
    end
    subgraph pusher [Pusher Channels]
        channel["private-contract-{id}<br/>private-account-{id}<br/>totem-{code}"]
    end
    subgraph client [Browser]
        hook["usePusherChannel"]
        query["Invalidate React Query"]
    end

    producer --> publisher --> channel
    hook -->|"subscribe (private → authz)"| authz
    channel --> hook --> query
```

## Where to go next

<CardGroup cols={2}>
  <Card title="Architecture" icon="sitemap" href="/realtime/architecture">
    The publisher, the lazy client and the degradation model.
  </Card>

  <Card title="Channels & Events" icon="list" href="/realtime/channels-and-events">
    Channel naming, the event contract and the private-channel authorizer.
  </Card>

  <Card title="Client Integration" icon="plug" href="/realtime/client-integration">
    The shared `usePusherChannel` hook and the client env contract.
  </Card>

  <Card title="Operations" icon="book" href="/realtime/operations">
    Environment variables, health probe and troubleshooting.
  </Card>
</CardGroup>
