feat(realtime): typed WS topics (enclave/user/admin) + subscribe-time auth (LC-160) #211
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-160-typed-ws-topics"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
LC-160 (follows the LC-156 declarative-subscribe foundation): add a typed WebSocket topic channel so non-room surfaces can receive live updates, with subscribe-time authorization.
How
The hub only keyed subscriptions by
room_id. Rather than rewrite everybroadcast_to_roomcall site, this adds a parallel typed-topic channel, leaving room fan-out untouched (current behavior unchanged, risk contained):topics: DashMap<String, HashSet<ConnId>>alongsiderooms, withsubscribe_topic/broadcast_to_topicand disconnect cleanup mirroring the room path.subscribe_topicclient frame. Each subscription is authorized per kind before joining the set -admin-> admin role,enclave:{id}-> membership (newdb::enclave::is_enclave_member),user:{id}-> must be the caller's own id; unknown/malformed denied. Centralizes subscription auth (the audit flagged some surfaces lacking it).data-lc-live-topic="enclave:5" | "user:abc" | "admin"sends the frame on socket open and on content swap, alongsidedata-lc-live-room.Scope
broadcast_to_topichas no consumers yet - LC-161 wires the stale surfaces (enclave / invitations / admin / settings / saved / inbox / activity) onto these topics. This PR is the transport + auth layer.Test
is_enclave_member(member / non-member / added-member) - the load-bearing enclave-topic auth check.just check/just test/just test-saasgreen (theroutes_uploadsflake is pre-existing and nondeterministic; no upload or hub-room code changed). WS-frame and hub-topic fan-out have no existing unit harness in this repo (consistent with the untested room-subscribe frame); the auth predicate is covered at the db level, matching how room-subscribe auth (is_room_member) is tested.Part of the LC-156 epic / LC-159 post-audit story.
🤖 Generated with Claude Code
Builds on the LC-156 declarative subscribe foundation. The hub keyed subscriptions only by room_id, so non-room surfaces had no live channel. Adds a parallel typed-topic channel without touching the existing room fan-out (so current behavior is unchanged and risk is contained): - Hub: a new `topics: DashMap<String, HashSet<ConnId>>` alongside `rooms`, with subscribe_topic / broadcast_to_topic and disconnect cleanup mirroring the room path. - WS: a new `subscribe_topic` client frame. Each subscription is authorized per kind before the connection joins the topic's set - `admin` requires the admin role, `enclave:{id}` requires membership (new db::enclave::is_enclave_member), `user:{id}` must be the caller's own id; unknown/malformed topics are denied. Centralizes subscription authorization, which the audit flagged as missing on some surfaces. - live.js: `data-lc-live-topic="enclave:5" | "user:abc" | "admin"` sends the subscribe_topic frame on socket open and on content swap, alongside the existing data-lc-live-room. broadcast_to_topic has no consumers yet; LC-161 wires the stale surfaces (enclave/invitations/admin/settings/saved/inbox/activity) onto these topics. Test: is_enclave_member (member/non-member/added-member), the load-bearing enclave-topic auth check. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>