feat(realtime): live invitations page (LC-161, first surface) #212

Merged
nrupard merged 1 commit from feat/lc-161-live-invitations into main 2026-05-26 16:26:44 +02:00
Owner

What

First stale-surface fill for LC-161: the invitations page now updates live.

Problem

The page was static-on-load - a new invite, or an accept/decline in another tab, did not reflect until reload.

How

EnclaveInvitationCreated / EnclaveInvitationResolved already broadcast_to_user, so every one of the user's tabs already receives them; the only gap was the WS send task had no OOB render arm. Added render_invitations (gated on invitee_id == the connection's user) that re-renders the pending-invitations region as an hx-swap-oob fragment. The dynamic region is extracted into a shared partial (invitations/items.html) used by both the full page (#lc-invitations) and the OOB fragment (ws/invitations_live.html) so they render identically; on tabs not on the invitations page there is no matching id and htmx drops the swap.

No topic subscription needed here - broadcast_to_user already fans out to all the user's connections. The LC-160 typed-topic channel is for surfaces whose events are not already per-user (e.g. the enclave member list, which needs a new enclave: broadcast) - tracked as follow-ups.

Test

just check (Askama templates incl. the shared partial compile), routes_enclave + routes_enclave_nav green (they render the invitations page through the new partial). just test/test-saas otherwise green (the lone saas failure is the pre-existing nondeterministic routes_uploads flake; no upload/room code touched). The WS OOB render path has no unit harness in this repo (consistent with the other send-task arms); the fragment shares the page's partial, so a render regression would fail the page-render route tests.

Part of the LC-156 epic / LC-161.

🤖 Generated with Claude Code

## What First stale-surface fill for LC-161: the invitations page now updates live. ## Problem The page was static-on-load - a new invite, or an accept/decline in another tab, did not reflect until reload. ## How `EnclaveInvitationCreated` / `EnclaveInvitationResolved` already `broadcast_to_user`, so every one of the user's tabs already receives them; the only gap was the WS send task had no OOB render arm. Added `render_invitations` (gated on `invitee_id == the connection's user`) that re-renders the pending-invitations region as an `hx-swap-oob` fragment. The dynamic region is extracted into a shared partial (`invitations/items.html`) used by both the full page (`#lc-invitations`) and the OOB fragment (`ws/invitations_live.html`) so they render identically; on tabs not on the invitations page there is no matching id and htmx drops the swap. **No topic subscription needed here** - `broadcast_to_user` already fans out to all the user's connections. The LC-160 typed-topic channel is for surfaces whose events are *not* already per-user (e.g. the enclave member list, which needs a new `enclave:` broadcast) - tracked as follow-ups. ## Test `just check` (Askama templates incl. the shared partial compile), `routes_enclave` + `routes_enclave_nav` green (they render the invitations page through the new partial). `just test`/`test-saas` otherwise green (the lone saas failure is the pre-existing nondeterministic `routes_uploads` flake; no upload/room code touched). The WS OOB render path has no unit harness in this repo (consistent with the other send-task arms); the fragment shares the page's partial, so a render regression would fail the page-render route tests. Part of the LC-156 epic / LC-161. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(realtime): live invitations page (LC-161, first surface)
All checks were successful
check-secrets / Nosey parker (push) Successful in 5s
check-secrets / TruffleHog (push) Successful in 6s
check-secrets / Kingfisher (push) Successful in 8s
check-secrets / Kingfisher (pull_request) Successful in 5s
check-secrets / TruffleHog (pull_request) Successful in 5s
check-secrets / Nosey parker (pull_request) Successful in 5s
Check / clippy + fmt + tests (pull_request) Successful in 1m29s
Create release / Create release from merged PR (pull_request) Has been skipped
d3fbd2a4d1
First stale-surface fill for LC-161. The invitations page was static-on-load: a new invite or an accept/decline elsewhere did not reflect until reload. The EnclaveInvitationCreated / EnclaveInvitationResolved events already broadcast_to_user, so every one of the user's tabs already receives them - the only gap was that the WS send task had no OOB render arm for them.

Adds a render_invitations arm (gated on invitee_id == the connection's user) that re-renders the pending-invitations region as an hx-swap-oob fragment. The dynamic region is extracted into a shared partial (invitations/items.html) used by both the full page (#lc-invitations) and the OOB fragment (ws/invitations_live.html), so they render identically; on tabs not on the invitations page there is no matching id and htmx drops the swap.

No topic subscription is needed here: broadcast_to_user already fans out to all of the user's connections, so this surface does not use the LC-160 typed-topic channel (that is for surfaces whose events are not already per-user, e.g. the enclave member list -> enclave: topic, which needs a new broadcast and is tracked separately).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
nrupard deleted branch feat/lc-161-live-invitations 2026-05-26 16:26:45 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!212
No description provided.