# Realtime (Mercure)

> How FeatherPanel pushes live updates through the Mercure hub in FrankenPHP: turning it on or off, the JWT keys, private topics, proxies and the polling fallback.

Source: https://featherpanel.com/docs/panel/realtime/

FeatherPanel uses the [Mercure](https://mercure.rocks) hub built into FrankenPHP to tell browsers that something
changed, so pages refresh at once instead of polling. Events only say what changed, never the data itself; the browser
fetches the new data through the normal API.

## What uses it

| Topic | Events |
| --- | --- |
| `/servers/<uuidShort>` | Server state and backup changes. |
| `/notifications` | Announcements created, edited or deleted by an admin. |
| `/users/<uuid>` | New items in the user's notification inbox. |
| `/admin/webspaces` | WebSpace changes in the admin list. |

## How it is turned on

On start, the backend sources `caddy/frankenphp-env.sh`, which reads `FEATHERPANEL_MERCURE`:

- `auto` (default): uses `MERCURE_SUBSCRIBER_JWT_KEY` and `MERCURE_PUBLISHER_JWT_KEY` from the environment, else from
  `storage/config/.env`, else generates both once and saves them to `.env`. If both are at least 32 characters, the hub
  is mounted.
- `off`: no hub, the panel polls.

The startup log prints `FrankenPHP: live updates (Mercure) on` or `off`.

## How browsers connect

1. The frontend calls `POST /api/user/realtime/token` with the topics it wants. The backend only grants topics the user
   may see and signs a token valid for one hour.
2. The browser opens one stream per tab to `/api/mercure` and sends the token in the `Authorization` header, never in the
   URL.
3. After a reconnect the page refetches, because the hub stores nothing (`transport local`).

## Reverse proxies

The stream goes through `/api/mercure`, so any proxy that already forwards `/api/*` works. It must not buffer or compress
the response. The hub sends `X-Accel-Buffering: no` for nginx and a heartbeat every 25 seconds to keep idle connections
open. See [Web server](https://featherpanel.com/docs/panel/web-server).

`MERCURE_PUBLIC_URL` overrides the URL the browser uses and `MERCURE_PUBLISH_URL` lets the backend publish to an
external hub over HTTP. Neither is needed with the bundled setup.

## Frequently asked questions

### Do I have to set up Mercure?

No. The backend container generates the two keys on first start and turns the hub on by itself. Set FEATHERPANEL_MERCURE=off to disable it.

### What happens when live updates do not work?

The panel falls back to polling, so pages still refresh, just less quickly. Check that your proxy does not buffer /api/mercure.

### Can someone read other users' events?

No. Topics are private and the subscriber token only lists topics the signed-in user may see.
