Realtime browser messages
Centrifugo with Protobuf is the browser update transport. Contexts publish typed messages to an explicit domain or security audience. The API calculates every channel from the authenticated principal's current authority. Browsers neither name nor select channels.
Run applications have a separate Project-private serving gateway. It forwards application HTTP, SSE and WebSocket traffic with continuously checked member authority. Platform projections and notifications use the rules in this document.
Audiences and permissions
DeliveryTarget permits one audience:
Project and Party are domain audiences. Principal is the authenticated security
subject used for private messages, including recorded command rejections and a
per-principal projection. A Run is Project-owned, so Run state uses the Project
target. Its payload remains a typed execution_core/run message with the Run ID
and revision. SSH Access writes one principal-targeted publication for every actor
that acts as the member.
The connect proxy authenticates the session and asks an application outbound port for the principal's current authorised realtime audiences. The API adaptor composes published owner queries from Party Governance and Project: Party Governance maps the security principal to the Party authority it may exercise, and Project decides which Projects that Party may currently access. The API maps the returned canonical IDs to server-side Centrifugo subscriptions. It does not reproduce either context's access rules.
The principal target is included for ordinary authorised connections. A limited
API-owned session awaiting AUP receives only its own Party readiness channel.
Invalid or unavailable session/Party authority fails closed. The connection carries a server-only audience fingerprint. Refresh asks
the owners again and expires the connection when that fingerprint changes; the
client reconnects to receive the new subscription set. Limited sessions use the
canonical Party already revalidated by authentication. The registered Party
payload is currently readiness only; adding other Party projections requires
reviewing limited-session delivery authority. Once AUP is current, party.Audiences
asks GetCurrentParty and traverses ListPartyProjectAudiences, whose Project
owner checks runs.view for the exact API Party actor and authentication
generation. A page may contain no allowed Projects and still supply a continuation
cursor. Refresh retains its one-minute maximum and is capped by the earliest
absolute valid_until returned by Beto. Expired, malformed or incomplete authority
closes the connection. Development operator/CLI sessions without canonical Party
authority retain only their principal channel.
The connect grant starts before owner reads to preserve the logout fence. If those
reads exhaust its lifetime, the API refuses the attempt with retryable disconnect
code 4001; a fresh attempt checks authority again. Invalid sessions and unresolved
audiences retain terminal code 4501. Expired grants supply no subscriptions.
The dashboard navigation qualification records the regression and live authentication results.
Publishing
The aggregate transaction records its current state, receipt, outgoing message
bytes and dispatch intent atomically. Each message supplies a RealtimeTarget and
a context-owned typed snapshot. The relay sends only the encoded publication and
its idempotency key:
The restricted gateway authenticates the publisher, verifies the envelope owner
and permitted target kinds, derives the channel and forwards the original bytes to
Centrifugo. Publisher code has no channel parameter. Execution Core may publish
Project-targeted Run messages. Support publishes principal-targeted Ticket and
TicketMessage messages, each to its owner. Party Governance publishes
PartyProfileProjection to the owning principal, including private profiles.
Profile data never uses the Party readiness channel available to limited sessions.
The API records technical session-readiness notifications atomically in its owned
Valkey state; its session credential can publish only the typed Party-targeted
notification described in the authentication guide.
Beto and Themelio expose the same typed
RealtimeMessage/RealtimeTarget application API; Support and Party Governance
explicitly enable their context-owned browser delivery in composition.
Metallo constructs Run changes with application.realtime.run_change, which
selects RealtimeTarget.project(run.project_id). Beto publishers use
application.ProjectTarget, PartyTarget or PrincipalTarget. Themelio uses the
corresponding RealtimeTarget class methods. Rejection messages require a
principal target in both technical foundations.
SSH Access records its typed projection with every committed root revision,
including Site results and propagation completion. Its actor mapping creates one
principal-targeted envelope per actor; a member with no actor receives no
publication. The ssh_access publisher credential is accepted only for principal
targets.
Frontend API
The new web application owns the connection in RealtimeProvider. Feature code
observes connection state and typed messages through hooks:
useRealtimeMessage registers a local typed handler. It does not subscribe to a
Centrifugo channel. messages.ts decodes the common envelope and its registered
payload, checks the target against payload identity and rejects unknown contracts.
The checked-in protobufjs schema is generated from the Protobuf sources by
pnpm generate:contracts.
The retained web keeps its Run connection in the authenticated RunNoticeProvider.
It observes every server-authorised Project while the member navigates between
pages. Resource managers select their Project's refresh counter; consent notices
remain one per Run for its initiating member, including on the dashboard. Replacing
the canonical member closes the old connection and clears its notices.
An authorised current-state read remains the initial source of truth. A feature applies only newer revisions and tolerates duplicate delivery. Recoverable Centrifugo history resumes by epoch and offset. An unrecoverable gap requires one fresh owner query before later messages are applied.
The SSH Access view registers a recovery callback with RealtimeProvider. The
principal channel's first subscription reads GET /api/v1/ssh-access/sites/{siteId}/projection;
recovered history needs no second read, and loss of history triggers one
reconciliation. A view mounted after the principal subscription is ready receives
its initial read immediately. Views mounted during an outage read once on the
next subscription, including when existing views resume from recovered history.
Browser HTTP reads use the generated OpenAPI client. The initial Project directory is loaded once after session establishment; it is not a polling source or a substitute for an owner-authorised realtime audience.
Security rules
- Client publish, client-selected subscriptions, polling, SSE and raw WebSocket business transports are prohibited. The one exception is the Run log panel, which polls its logs route every 5 seconds for now (decision).
- Publisher credentials are context-scoped and never reach the browser.
- The gateway forwards exact persisted Protobuf bytes; it does not reconstruct a later snapshot.
- Realtime delivery carries committed state or an outcome. It grants no business authority.
- Session revocation disconnects every connection for that principal. Connect authority is short-lived and refreshed through the authenticated API proxy.
The browser edge serves /auth, /api/v1 and /connection/websocket at
https://platform.localtest.me. Internal proxy, diagnostics and Centrifugo
administration endpoints remain private.
Page source
Source snapshot ยท Revision f928834c8.