Skip to content

Fix messenger read receipts never updating - #92

Merged
HafizMMoaz merged 1 commit into
mainfrom
fix/messenger-read-receipts
Jul 27, 2026
Merged

Fix messenger read receipts never updating#92
HafizMMoaz merged 1 commit into
mainfrom
fix/messenger-read-receipts

Conversation

@HafizMMoaz

Copy link
Copy Markdown
Member

Fixes #90

Root cause

Two separate gaps, both on the sender's side:

  1. Nothing reported the read back. getMessages() flips seen when the recipient opens the conversation, but no event, no poll, nothing told the sender. The frontend only polls online status. That is the "sometimes it is working" in the report: reopening the chat refetches messages and the ticks look correct again, so the state was never wrong in the database, only on screen.
  2. The sender's message had no id to update. handleSendMessage renders optimistically with id: temp-<timestamp> and send() returned only {success, message}, so the row never picked up its stored id. Even with a read receipt arriving, nothing could match it to the message on screen.

Changes

  • MessengerController::send() returns the stored id (plus the saved attachment path), and the client swaps the temp id for it.
  • checkNewMessages() was in the routes and the controller but no caller anywhere. It now also reports seen_message_ids for the open conversation, scoped to from_id = auth id and bounded to the 50 most recent.
  • The messenger polls it every 10s while a conversation is open and flips is_read, which is what turns the tick into the existing blue CheckCheck.

Verification

  • tests/Feature/MessengerReadReceiptTest.php: send returns the stored id, the sender sees the receipt only after the recipient opens the chat, and another conversation's read state does not leak in. All 3 fail without the controller change.
  • Full suite: 13 failures before and after, all pre-existing; the 3 new tests pass. npm run build and tsc --noEmit clean.
  • Driven live between two logged in users: the sender's poll returns seen_message_ids: [] before the recipient opens the chat and [1] after.

Not covered

A distinct grey "delivered" tick, separate from "sent", needs a delivery ack from the recipient's client that does not exist today. This restores read status, which is what was stuck.

🤖 Generated with Claude Code

Two gaps kept a sent message on a single tick. The recipient marks messages
seen when they open the conversation, but nothing ever told the sender, so
the ticks only caught up on a page reload. That is the "sometimes it works"
in the report: reopening the chat refetches the real state.

The sender's own message was also unreachable. It renders optimistically
with a temp- client id and send() returned nothing, so the row never got its
stored id and no update could ever match it.

send() now returns the stored id and the client swaps it in. The unused
check-new-messages endpoint reports which of the sender's recent messages
have been read, and the open conversation polls it.

Fixes #90
@HafizMMoaz
HafizMMoaz requested a review from a team as a code owner July 27, 2026 00:15
@HafizMMoaz
HafizMMoaz merged commit 3885e1a into main Jul 27, 2026
1 check passed
@HafizMMoaz
HafizMMoaz deleted the fix/messenger-read-receipts branch July 27, 2026 02:24
HafizMMoaz added a commit that referenced this pull request Jul 27, 2026
Follow up to #92, which did not fully fix #90.

The recipient only ever marked a conversation seen on a page load or a page of
getMessages. A message that arrives over the websocket lands in a chat that is
already open and never refetches, so nothing marked it, and the sender's tick
stayed on one until somebody reloaded. That is the remaining half of "sometimes
it works": the reload that fixes it has to be the recipient's. The poll that #92
added now marks the open conversation seen, which is the same thing a page load
does. It runs immediately rather than after a full interval, and skips while the
tab is hidden so a chat left open in a background tab does not report messages
nobody looked at as read.

The conversation query built `(A) or (B) and (C)`. SQL binds `and` tighter than
`or`, so the delete filter only ever applied to received messages and a sender
deleting their own message saw it return on the next load. It only looked deleted
once the recipient deleted it too, which hard deletes the row. Grouping the two
halves of the conversation fixes it in both getMessages and the Inertia index.

Fixes #90
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Messenger Read Receipts Not Updating

1 participant