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

# Arquitectura

> El publisher de Pusher de horizon-api, el cliente de servidor cargado de forma perezosa, y el modelo de degradación best-effort.

## Componentes

| Componente                          | Ruta                                             |
| ----------------------------------- | ------------------------------------------------ |
| Cliente perezoso + helpers de canal | `lib/integration/pusher/pusher.client.ts`        |
| Publisher (único `trigger`)         | `lib/integration/pusher/pusher.publisher.ts`     |
| Tipos del contrato de eventos       | `lib/integration/pusher/pusher.types.ts`         |
| Autorizador de canales privados     | `app/api/v3/realtime/pusher/auth/route.ts`       |
| Hook de React compartido            | `@bbrandslab/ui` → `hooks/use-pusher-channel.ts` |

## Cliente de servidor perezoso

El SDK de servidor `pusher` se importa **de forma perezosa** dentro de `getPusherClient()`. La
dependencia se mantiene fuera del bundle hasta que las cuatro variables de entorno
requeridas están presentes, de modo que las solicitudes que nunca tocan el tiempo real siguen siendo
ligeras. El cliente se memoiza por proceso.

```ts theme={null}
const client = await getPusherClient();
if (!client) {
  // No credentials → log-only no-op. The business flow continues.
  return;
}
await client.trigger(channels, event, data);
```

<Note>
  `getPusherClient()` devuelve `null` a menos que `INTEGRATION_PUSHER_APP_ID`,
  `INTEGRATION_PUSHER_KEY`, `INTEGRATION_PUSHER_SECRET` e
  `INTEGRATION_PUSHER_CLUSTER` estén todos configurados.
</Note>

## Publisher best-effort

`publishContractEvent()` es el único punto que llama a `trigger`. Absorbe
sus propios fallos con logging estructurado: un publish fallido nunca rompe el
worker, webhook o acción de administración que lo produjo.

```mermaid theme={null}
flowchart TD
    call["publishContractEvent(payload)"] --> get{"getPusherClient()"}
    get -- null --> noop["Log info + return (no-op)"]
    get -- client --> trigger["client.trigger([contract, account], event, data)"]
    trigger -- ok --> health_ok["recordIntegrationOutcome('pusher', true)"]
    trigger -- throws --> classify{"5xx / network?"}
    classify -- yes --> health_down["recordIntegrationOutcome('pusher', false)"]
    classify -- no (4xx) --> health_ok2["recordIntegrationOutcome('pusher', true)"]
    trigger -. warn log .-> log["Structured warn (non-fatal)"]
```

Un único evento se distribuye a **ambos** el canal del contrato y el canal de la
cuenta, de modo que los listeners con alcance de cuenta y con alcance de contrato reciben el mismo
mensaje.

## Contabilidad de salud

Solo un **5xx o un error de red** cuenta contra el veredicto de salud de Pusher. Un
`4xx` significa que nuestra solicitud estaba mal formada (nuestro bug), no que Pusher esté caído, así que
nunca cambia el estado de la integración. Consulta [Operaciones](/es/realtime/operations) para
el health probe.
