Skip to content

Chat: show newest messages, load older history on demand - #209

Merged
JanMikes merged 2 commits into
mainfrom
fix/chat-newest-messages-window
Sep 1, 2026
Merged

Chat: show newest messages, load older history on demand#209
JanMikes merged 2 commits into
mainfrom
fix/chat-newest-messages-window

Conversation

@JanMikes

@JanMikes JanMikes commented Sep 1, 2026

Copy link
Copy Markdown
Member

Bug (user report)

"I have chats where no new chats are saved in history. Disappear.." / "Some messages (latest) not showing up, when I open my conversation. Only in preview in list of my conversation last message beginning. But when opened - no latest ones."

GetMessages::forConversation() loaded messages with ORDER BY sent_at ASC LIMIT 50 and no pagination anywhere. Once a conversation passed 50 messages, opening it rendered the oldest 50 and silently dropped everything newer. The conversation list was unaffected (its preview is a separate DESC LIMIT 1 subquery), and a freshly sent message appeared live via the Mercure/Turbo Stream append but vanished on reload — hence "disappearing" messages. No data was ever lost, only hidden.

Confirmed on production: the reporting user's conversation has 64 messages; everything after 2026-07-15 (the day it crossed 50) was invisible to both participants. Two more conversations site-wide (59 and 54 messages) are affected.

Fix

  • GetMessages::forConversation() now selects the newest limit messages (ORDER BY sent_at DESC, id DESC LIMIT :limit+1, re-sorted ASC for display) and returns a MessagesPage result with a hasOlderMessages flag (the +1 row detects whether more history exists).
  • Cursor pagination for history: optional beforeMessageId returns the newest window strictly older than that message, using a (sent_at, id) tuple comparison scoped to the conversation (an id from another conversation yields an empty page).

Load older messages (full history access)

  • New endpoint GET /en/messages/{conversationId}/older-messages?before=<messageId> (ConversationOlderMessagesController, participant-only) renders a batch of older bubbles as an HTML fragment carrying data-has-older / data-oldest-id.
  • Conversation detail shows a Load older messages button pinned at the top of the scroll container when history exists. The messaging Stimulus controller fetches a batch, prepends it below the button (each batch is older than the previous), preserves the scroll position, and hides the button when history is exhausted. The existing auto-scroll-to-bottom MutationObserver is suppressed during prepends.
  • Start-conversation modals now show the newest window too (no load-older button there; the full page has it).

Tests

  • GetMessagesTest rewritten for the new behavior: newest-window selection, chronological order, hasOlderMessages, cursor walk reassembles the entire history exactly, foreign-conversation cursor returns nothing.
  • Full suite: 2253 tests, 11390 assertions, green. PHPStan max level clean, PHPCS clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GcS993Bupy5RapSDEk1SYs

JanMikes and others added 2 commits September 1, 2026 16:49
GetMessages returned the oldest 50 messages (ORDER BY sent_at ASC
LIMIT 50) with no pagination, so any conversation past 50 messages
silently hid everything newer - the list preview (separate DESC
subquery) still showed the latest message, and freshly sent messages
appeared live via Mercure but vanished on reload.

The query now returns the newest window in chronological order plus a
hasOlderMessages flag (fetches limit+1), with a (sent_at, id) cursor
for walking history backwards. Conversation detail gets a "Load older
messages" button that fetches batches from a new endpoint and prepends
them with scroll position preserved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GcS993Bupy5RapSDEk1SYs
load_older_messages (new in this branch) plus 6 pre-existing gaps from
the events picker and API docs work (add_my_time, competition_hint_series,
competition_live_badge, competition_not_selectable, table_section_puzzles,
table_section_library). check-translations now reports 0 missing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GcS993Bupy5RapSDEk1SYs
@JanMikes
JanMikes merged commit 8474a0e into main Sep 1, 2026
5 checks passed
@JanMikes
JanMikes deleted the fix/chat-newest-messages-window branch September 1, 2026 17:23
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.

1 participant