> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# 0057 — Targeted realtime messages

Status: accepted

## Context

Browser updates need a common delivery mechanism across contexts and languages.
Some state belongs to every authorised member of a Project or Party. Private
asynchronous outcomes belong to one authenticated security subject. Accepting a
channel name from a service or browser would duplicate permission policy outside
the owning authority.

Runs are owned by Projects. A separate Run audience would require independent
membership and revocation rules while conveying the same authority.

## Decision

Every realtime `Publication` carries one typed `DeliveryTarget`: Project ID, Party
ID or principal subject. Context code constructs a typed `RealtimeMessage` with
that target. Its transaction persists the exact Protobuf bytes and delivery intent
with the aggregate change or consumer receipt.

The restricted gateway authenticates the publisher, verifies the envelope owner
and permitted target kinds, and derives the Centrifugo channel. Publisher requests
contain no channel. Execution Core may publish Project targets and sends every
changed Run to its Project audience.

The API authenticates the browser principal and obtains current authorised
audiences through an application outbound port before returning server-side
Centrifugo subscriptions. Its adaptor composes published owner queries. Party
Governance supplies the Party authority available to the principal; Project
supplies current Project access for that Party. Principal is the security subject
for private messages. Project and Party remain domain concepts, and the API does
not duplicate their access rules. Authority-query failures disconnect the client.
The current composition authorises only the principal channel until both owner
queries and the API adaptor are implemented. Connection refresh compares a
server-only fingerprint of the authorised channels and forces a fresh connect when
the owner's access decisions change.

The web application owns one Centrifugo connection in `RealtimeProvider`. Feature
code uses `useRealtimeConnection` and `useRealtimeMessage` with registered decoded
message types. There is no browser channel-selection API.

## Consequences

- Run delivery follows the Project context's current access decision and
  revocation.
- Publisher credentials restrict both context ownership and audience kind.
- Go and Python services expose equivalent target/message application values.
- The browser depends on generated Protobuf schema and typed message decoders.
- Adding a browser message requires a typed payload, target rule, publisher
  permission, owner-authority query coverage and current-state read path.
- Project and Party messages are persisted and relayed only when their browser
  authority path can subscribe eligible principals.
- Party Governance and Project implementation must publish the queries needed by
  the realtime authority adaptor. The adaptor belongs at the API boundary and
  contains no domain access policy.

<details class="page-source"><summary>Page source</summary>

<a href="/source/docs/decisions/0057-targeted-realtime-messages.md.txt">Source snapshot</a> · Revision `f928834c8`.

</details>
