What changed
- Server-owned inbox tabs. Priority requests
featured, General requestsgeneral, and Message Lists requestsbroadcast. Fans requestalland see one list without tab controls. - Rows keep the backend's membership and order. The frontend no longer splits, filters, or sorts each inbox response by featured flags, tips, broadcasts, or an empty last message. Existing badge normalization and row rendering stay in place.
- Inbox scroll loads the next page. Rows append using the returned cursor. A tab change or a new search replaces the list and starts without a cursor. A null or missing cursor ends pagination.
- Unread badges use server counts. Tab badges use their matching
countsfields. The shared Messages total isgeneral + featured + broadcast, independent of the number of loaded rows. Sidebar badge refreshes fetch fresh inbox counts, and the open inbox follows those updates. - History supplies send permissions. The first history request asks for validation and assigns it to
dmValidations. The separateChatUserValidationrequest is gone. Permission retry uses history with validation again. - Scroll-up loads older messages. Older pages prepend using the history cursor and keep the current validation. The scrollbar adjusts by the added content height to preserve the reading position. A null cursor stops further requests.
- Broadcast history keeps its sender. Existing broadcast
fromstays on first and subsequent history requests. - Requests survive rapid navigation. Replacing a tab, search, or conversation cancels its previous request. Old responses cannot replace the new list, messages, or validation. Pending pagination requests cannot start duplicate pages.
- Search handles input and paste. Searches remain debounced. Blank search text is omitted, and query values are URL-encoded.
Request contract
- Inbox first page
GET api/get-chatGroups-and-users?tab=featured&counts=true. Replace the selected tab's rows; storecountsandcursor.- Inbox next page
- Keep the same
taband nonemptysearch_key. Addcursorfrom the last response and appenddata. - History first page
POST api/getpreviousMessagesFromHttpwith{ groupId, include_validation: true }. Useresponsefor messages andvalidationfor send permissions.- History next page
- Send
{ groupId, cursor }. Preserve broadcastfrom. Omitinclude_validationand the old timestamp pagination field.
Verification results
26 checks passed on the running dev server, plus 12 isolated contract checks against the component methods. TypeScript checking and Angular development compilation passed. The table distinguishes real staging responses from controlled responses used to exercise populated lists.
| Check | Result | Evidence |
|---|---|---|
| Required staging setup | Passed | Ran generate-white-label-staging, copied the Rudeus Greyrat staging environment into environment.ts, then ran cleanup-white-label before starting the dev server with the 10 GB Node memory setting. |
| Live creator tabs | Passed live | Signed in to staging. Priority, General, and Message Lists returned successful responses with empty data, zero counts, and null cursors. The empty state rendered correctly. |
| Live search and clearing | Passed live | A search sent search_key on the selected tab. Clearing it omitted both search_key and cursor. |
| Backend membership and ordering | Passed controlled | Rendered 30 Priority rows whose users were not locally featured. Fan rows retained backend order, including a broadcast row with an empty last message. |
| Inbox pagination and stop | Passed controlled | Scrolling requested an encoded cursor and appended two rows, taking the list from 30 to 32. A null cursor prevented more page requests. |
| Unread badges | Passed controlled | Tab counts were 7, 3, and 2. The sidebar showed 12 while the list had 30 rows with zero row unread counts. |
| Sidebar refresh and tab synchronization | Passed controlled | Sidebar refresh requested fresh creator counts. A later response with counts 1, 2, and 3 changed the shared total to 6 and updated the open inbox's tab badges. |
| First history and validation | Passed controlled | The request included include_validation: true. The response supplied dmValidations and unlocked message actions. |
| Older history and reading position | Passed controlled | Scroll-up sent only the group and cursor. Ten older messages prepended to 25 messages. The viewport moved by exactly 867 pixels, matching the added height, while validation remained the same. |
| History termination | Passed controlled | Scrolling up after a null cursor did not send another history request. |
| Fan presentation | Passed controlled | Requested tab=all, retained the returned list, and verified that the tab component was hidden. |
| Broadcast sender | Passed controlled | Both first and subsequent history requests retained from. Only the first request asked for validation. |
| Stale responses and permission retry | Passed controlled | Old tab, search, and conversation responses were ignored. Missing direct-message validation kept actions locked. Retry requested validation through history. |
| Failure and concurrency handling | Passed contract checks | Checked duplicate-page guards, history errors, retained cursors after older-page failures, and permission retry after a failed first page. |
| Compilation and setup cleanup | Passed | TypeScript and Angular development compilation passed. The main project also compiled with its original environment and returned HTTP 200. Temporary environment and generated-file changes were restored after verification. |
| Populated live history and fan account | Needs live data | The supplied creator account had no inbox rows. Real multi-page history, backend validation payloads, nonzero unread transitions, and a signed-in fan account still need the populated-account checks below. Controlled tests cover the frontend contract. |
Live verification checklist
Use a creator and a fan account with enough conversations and history to produce non-null cursors. Inspect the request payloads alongside the visible list.
- Open each creator tab. Confirm
featured,general, andbroadcast, always withcounts=true. Compare each rendered row and its order withdata. - Scroll the inbox to load another page. Confirm the next request keeps the tab and search, sends the previous cursor, and appends rows. Continue until the cursor is null or missing; further scrolling must send no request.
- Switch tabs after loading several pages. The first request for the new tab must omit the cursor. Search, change the search quickly, paste text, and clear it. Confirm stale results never appear and blank
search_keyis omitted. - Compare unread tab badges with
counts. Confirm the sidebar and header Messages total equals their sum. Open an unread conversation, then check the refreshed server counts rather than the number of loaded rows. - Navigate away from Messages and cause an unread badge refresh. Confirm the sidebar requests fresh inbox counts and updates the shared total. Return to Messages and compare the tab badges with the latest counts.
- Open a direct conversation. Confirm a single history request sends
include_validation: true, validation controls the composer, and noapi/chat-user-validationrequest appears. - Scroll up through multiple history pages. Confirm cursor requests, older messages above the current content, stable reading position, and unchanged send permissions. After a null cursor, confirm scrolling sends no additional history request.
- Open broadcast history. Confirm
fromon the first and subsequent pages and no validation flag on subsequent pages. - Switch conversations before history returns. Confirm the old response changes neither the messages nor the new conversation's send permissions.
- Simulate a history failure. First-page failure must keep actions locked until retry succeeds through history. An older-page failure must preserve the conversation and allow the same cursor to be retried.
- Sign in as a fan. Confirm one list, no creator tabs,
tab=all, and the same search and scroll behavior.
Changed files
- Messages component
src/app/modules/messages/components/message-container/message-container.component.tsand its HTML template contain the inbox requests, cursor state, scrolling, validation, cancellation, and search event changes.- Constants and response shape
src/app/modules/messages/constants/messages.constant.tsdefines inbox tab values and labels.src/app/modules/messages/interfaces/messages.interface.tsdefinesInboxCounts.- Shared unread counts
src/app/services/core.service.tsstores server counts and their total.src/app/modules/shared/components/sidebar/sidebar.component.tsrefreshes counts and clears them on sign-out.- Verification evidence
docs/messages-chat-pagination-verification-sol-6-1.jsonrecords the dev-server assertions. This report uses the palette from the existing notes pages andCOLORS.md.