TL;DR: For chat authorisation, use one logical channel per fleet, depot, room, or other authorization boundary, then filter device updates inside that boundary on the server. Do not put every vehicle on one globally shared channel and ask an untrusted dashboard to discard unauthorized records. Do not create a channel per device by reflex, either. The useful boundary is the smallest scope that a token can authorize cleanly without making reconnect state and telemetry cardinality explode.
For a logistics dashboard, the bill is mostly a multiplication problem: delivered updates, fan-out, bytes per update, and retention. Channel count matters operationally, but storing a label for every channel, vehicle, connection, and reconnect can dominate the observability side long before channel metadata itself matters. Start by reducing what is delivered and retained.
What is the bill actually made of?
Model the data plane before debating names. Let D be active devices, r their mean status updates per second, s the encoded bytes per update, f the mean number of authorized dashboards receiving each update, and T the retention window in seconds. Ignoring protocol overhead and replicas, retained payload bytes are D × r × s × T; delivered payload bytes per second are D × r × s × f. Those equations are capacity estimates, not measured pricing. They expose the dominant terms.
Consider an illustrative fleet with 12,000 active vehicles, one 600-byte status update every 10 seconds, and three dashboard viewers per update. That is 1,200 source updates per second and about 2.16 MB/s of delivered payload before framing, encryption, acknowledgements, retries, indexes, or replication. Keeping every source update for seven days would retain about 435 GB of payload before those same additions. These figures are arithmetic from stated assumptions, not a benchmark.
Now compare the authorization shapes. A global stream that sends all 1,200 updates per second to each depot dashboard and filters in browser code pays for unauthorized delivery and creates a confidentiality failure boundary. A per-device channel can avoid that delivery, but 12,000 channel identities multiplied by connection state, authorization results, and metrics labels creates a different burden. A channel per depot, with server-side filtering for vehicles assigned to that depot, keeps token scope legible while bounding fan-out.
The high-leverage change is refusing unauthorized fan-out before serialization. After that, reduce status frequency when a vehicle is stationary, coalesce superseded states, and retain transitions longer than repetitive heartbeats.
Less enters the meter.
Should fleet chat use one filtering channel or a channel per room?
A team chat token should grant access to a stable business boundary, such as fleet:47 or depot:sea-2. In this logistics example, a room carries vehicle status plus the dispatch conversation for one authorized operating group. The server validates that scope when the client subscribes and again when membership changes affect delivery. Filtering must happen before an event crosses the trust boundary. A browser-side predicate is a presentation feature, not authorisation.
The choice is not literally “many channels” versus “one channel.” It is where the authoritative membership decision lives. One physical connection may carry several logical subscriptions. Conversely, a single named stream can still require a server-side authorization predicate for every event. Transport multiplexing does not weaken the access-control rule.
Tokens also need narrow actions and bounded lifetimes. A dashboard that only reads status should not receive a capability to publish commands. Reconnect makes this discipline visible: the client presents fresh authority, the service reconstructs permitted subscriptions, and replay is limited to those scopes. If a vehicle moves from Depot A to Depot B, cached membership cannot remain valid indefinitely. The exact expiry and revocation interval are policy choices; they should be shorter than the organization's acceptable exposure window.
Choose the coarsest channel whose complete event set every subscriber is allowed to receive. Add server-side row filtering when viewers have narrower subsets. Split the channel when that predicate becomes expensive, difficult to audit, or too broad to express in a token. The limitation of a channel per room is state growth: a dispatcher covering 80 rooms needs 80 logical subscription decisions after reconnect. The limitation of one filtering channel is subtler: every new event type must pass the same server-side authorisation discipline, and one missed predicate widens exposure. This trade-off is why the token boundary, rather than raw channel count, should settle the design.
No topology removes policy work.
Cardinality is part of the security design
Observability labels can quietly recreate the sensitive dataset. A counter labeled by vehicle_id, user_id, channel_id, token_id, and connection_id has a potential Cartesian product far larger than the fleet. Most combinations never occur, but enough do during reconnect storms to make storage and queries unpredictable. Token identifiers in labels also create needless exposure.
Keep bounded dimensions on metrics: region, deployment, result class, and perhaps a coarse subscription type. Put request-scoped identifiers in short-lived structured logs or traces, subject to access controls and redaction. Even there, record a hash or correlation identifier only when an investigation genuinely needs it.
| Signal | Bounded dimensions | Why keep it |
|---|---|---|
| Subscription decisions | region, allow/deny reason | Detect policy changes and denial spikes |
| Delivered updates | region, message class | Measure fan-out and capacity |
| Dropped or coalesced updates | region, reason | Verify load-shedding behavior |
| Reconnect duration | region, outcome bucket | Test recovery without per-client labels |
| Active subscriptions | region, scope type | Track state growth |
Count cardinality before deployment. If there are 40 depots, 6 regions, 4 outcomes, and 5 message classes, those bounded dimensions produce tens or hundreds of active series per metric family, not one series per vehicle-session pair. The exact total depends on which dimensions each metric uses. Multiplying all labels onto every metric is precisely the mistake to avoid. A per-room metric label is acceptable only when the room set is bounded and operators truly act on each value; otherwise, aggregate it by region or scope type and preserve a room identifier only in sampled diagnostic records.
Count first.
Reconnect, replay, and error handling
The hard failure is a reconnect that restores delivery before restoring authorization. Treat connection establishment, authentication, subscription approval, and replay as separate states. No replay cursor should be honored until its requested scope has been authorized. A cursor is position, not permission.
A transport-neutral probe can exercise that contract through an administrative test endpoint:
curl --fail-with-body \
--request POST \
--header 'Authorization: Bearer test-depot-reader' \
--header 'Content-Type: application/json' \
--data '{"scope":"depot:sea-2","cursor":"opaque-test-cursor"}' \
https://realtime.example.test/subscription-check
The test should include a token for another depot, an expired token, a reassigned vehicle, and a cursor created under broader authority. Keep such probes in a non-production fixture with synthetic identifiers. The .test domain is reserved for testing by RFC 2606; it is not a live service.
WebRTC data channels are one possible peer-to-peer transport. The WebRTC 1.0 specification defines RTCDataChannel and its use of SCTP over DTLS, but it does not supply the logistics application's fleet membership policy. That separation matters: transport properties and application authorization require different tests. A WebSocket, server-sent event stream, or data channel cannot make browser-side filtering trustworthy merely by changing protocols.
Deployment needs a deny-first transition. Compare old and new policy decisions without exposing events, then enable enforcement for a bounded scope. Error responses should distinguish retryable transport failures from rejected authority without echoing sensitive policy detail. On rollback, never fall back to a broader stream.
What should we deliberately stop keeping?
Keep durable business events when they support an operational or legal requirement: depot reassignment, alert acknowledgement, or a command decision. Sample or aggregate repetitive presence and position telemetry according to the dashboard's freshness objective. A last-known state table plus a shorter transition log often answers “where is the vehicle now?” without retaining every identical heartbeat. Legal, safety, and contractual rules decide the actual windows.
Sampling has a sharp edge. Uniformly retaining one event in every hundred can erase a short disconnect or temperature excursion. Prefer state-aware rules: retain every transition, every authorization denial, and every rare error class; sample unchanged healthy status. During an incident, temporarily increasing diagnostic capture should require a bounded duration and an explicit owner, because emergency logging tends to become permanent.
What disappears is forensic resolution. Coalescing ten identical status messages into one record means an investigator can prove the observed state across an interval, but not reconstruct every transmission attempt. Removing per-token logs makes broad access-pattern analysis cheaper and safer, but complicates a question about one credential. State that loss before changing retention, identify the questions that must remain answerable, and test them against archived examples.
The final architecture is intentionally uneven: authorization detail is precise and short-lived; operational metrics are aggregated and longer-lived; business transitions follow their own retention policy. Channel boundaries support that separation. They should never be expected to replace it.
Further reading
- W3C, WebRTC 1.0: Real-Time Communication Between Browsers: https://www.w3.org/TR/webrtc/
- IETF, The WebSocket Protocol (RFC 6455): https://www.rfc-editor.org/rfc/rfc6455
- WHATWG, Server-sent events: https://html.spec.whatwg.org/multipage/server-sent-events.html
- IETF, OAuth 2.0 Security Best Current Practice (RFC 9700): https://www.rfc-editor.org/rfc/rfc9700
- IETF, Reserved Top Level DNS Names (RFC 2606): https://www.rfc-editor.org/rfc/rfc2606
Top comments (0)