Messages module features

A source-based inventory of direct messaging, message lists, attachments, payments, sharing, and automated messages in TopFan.

Reviewed 30 September 2026 · Frontend revision d885efb055 · src/app/modules/messages/

Availability depends on account permissions, creator status, age, backend validation, and tenant configuration. This document describes the checked-out implementation; it does not certify live backend behavior.

Inbox and conversations

  • Direct conversations. Open existing one-to-one threads or start a conversation by selecting a user in the new-message modal. Existing channels are reused; new channels are created when needed.
  • Creator inbox tabs. Creators have Priority, General, and Message Lists views. Non-creators use the General conversation view.
  • Priority classification. A thread enters Priority when its user has the backend featured flag or it has an unread tip. Broadcast threads go into Message Lists. Sorting places recent conversations first.
  • Conversation search. Search the inbox through a debounced API query. New-recipient and participant searches also debounce input and cancel the previous request.
  • Conversation previews. Rows show the person's name, avatar or fallback icon, recent text or a Media label, unread count, and selected-thread highlighting.
  • Identity and fan badges. Display creator verification, qualifying subscriber indicators, and normalized fan badges with tooltips in the list and conversation header.
  • Tip and reply indicators. Mark unread tips and pending guaranteed replies in conversation rows.
  • Unread counts. Track conversation and tab counts plus the shared app message count. Opening a thread clears its local unread count and unread-tip indicator.
  • Online presence. Show online/offline indicators from WebSocket membership data, both in inbox rows and in the selected direct conversation.
  • Conversation history. Fetch stored messages for the selected channel. Group them by Today, Yesterday, or a calendar date; show local timestamps and sender avatars where the sender changes.
  • Live updates. Receive messages through the shared WebSocket service. Append messages in the active thread, refresh inbox ordering, and increase unread counts for other threads. The service contains reconnect handling.
  • Deep links and return flows. Select a conversation through the user query parameter, a route/query id for payment return handling, or router state carrying a user key or group ID.
  • Profile navigation. Open the selected user's profile from the conversation header.
  • Responsive layout. Desktop displays the list and thread together. Mobile selection opens the thread, with a back control to return to the list.
  • Loading and empty states. Show inbox and conversation loaders, a no-messages state, and an empty-automation state.

Source: inbox and thread logic, WebSocket service.

Message composition and sending

  • Text, attachments, or both. Send text-only, attachment-only, or mixed messages. Empty and whitespace-only text without attachments or shared content does not send.
  • Growing text area. The composer grows as text fills it, up to four rows. Message URLs render as clickable links in the thread.
  • Emoji picker. Insert the chosen emoji at the current cursor position. Selecting an emoji or clicking outside closes the picker.
  • First-name personalization. Broadcast composition offers an Insert First Name action that inserts [First Name] at the cursor. The automated-message text field also exposes first-name insertion.
  • Local sending queue. Add an outgoing message locally, upload attachments, then send the completed payload. The UI tracks submission and upload progress and resets composition after sending.
  • Navigation protection during sending. Pending queue entries prevent route deactivation, and switching to another conversation is restricted while the queue is occupied. This protection concerns queued sends, not every unsent draft.

Source: composer and send pipeline, route protection.

Media and file attachments

  • Images, videos, audio, and other files. The main composer classifies selected files into these four types. Generic files show their filename and formatted size.
  • Multiple attachments. Select multiple files, inspect previews, and remove individual items before sending.
  • Images. Compress selected images, create thumbnails, and open sent or received images in a lightbox overlay.
  • Video playback. Preview attached videos and play conversation videos in a player modal. Portrait video metadata controls the player presentation.
  • Audio playback. Play uploaded audio and recorded voice messages. The composer has an audio preview that can be cleared before sending.
  • Voice recording. Start, stop, cancel, and discard microphone recordings. Show elapsed recording time and a live waveform; a nonzero recording becomes an audio attachment.
  • Downloads. Available recipient media has download actions. In the mobile app, downloads pass to the native bridge; browser downloads use a file download flow.
  • Upload feedback and moderation. Track image and file upload progress. Images flagged by the upload service open a restricted-content carousel. Upload errors return user-facing feedback.
  • Mobile file selection. File inputs integrate with the mobile bridge. The automated-message attachment component also handles files supplied by the native app.
  • Media presentation. Images use lazy loading and mobile image optimization. Media elements use the shared right-click restriction directive where configured.

Source: selection and previews, uploads.

Tips and guaranteed replies

  • Tip with a direct message. Eligible direct conversations with creators expose a tip amount panel. Tips can include text and media and use the shared checkout flow.
  • Preset and custom amounts. Generate suggested amounts from the minimum tip and multipliers of 1, 5, 10, 20, and 50. Support a custom amount with numeric, minimum, and currency-range validation.
  • Local currency. Display converted suggestions, a currency symbol, and local prices; convert the tip to its USD base amount for payment.
  • Tip receipts in the thread. Render the amount and distinguish an ordinary tip from a guaranteed-reply payment.
  • Guaranteed-reply offer. Backend validation supplies the offer flag and minimum qualifying tip. A modal explains the offer and lets the sender add a tip or send without the guarantee.
  • Refund terms displayed to the sender. The offer copy says that a qualifying tip is automatically refunded within seven days if the creator does not reply. Refund processing is a backend/payment responsibility.
  • Pending-reply fulfillment. A creator reply to a pending guaranteed-reply message calls the redemption endpoint. On successful redemption, clear the pending indicator, display the credited-wallet notice, and send the reply.
  • Composition restrictions. Tip controls apply to direct creator conversations, rather than broadcast or follower-list sends. A positive attachment price or inserted share content disables tip selection. Delegate mode has additional permission handling.

Source: offer and redemption, tip amounts and checkout.

Free DM credits and pay-per-message

  • Creator-specific validation. Fetch the selected recipient's DM price, free-message allowance, unlimited allowance flag, guaranteed-reply status, and currency data.
  • Credit status. Display remaining free messages, Unlimited where applicable, or the paid DM price when no free messages remain.
  • Consume free credits. When a priced creator conversation still qualifies for a free message and has no attached tip, call the consume-credit endpoint and update the allowance before sending.
  • Pay after credits run out. Route the message and its attachments to pay-per-message checkout when the recipient charges for DMs and the finite free allowance is exhausted.
  • Combined DM price and tip. A combined checkout payload carries the DM charge and tip separately while charging their total. Preserve message text, media, channel, and guarantee context.

Source: credit-aware send decisions, paid DM payloads.

Message lists and broadcast sending

  • Create a named message list. Select individual users or audience groups, then enter a list name and optionally upload a cropped list icon.
  • Two audience types. Lists can contain individual users or predefined/subscription groups. The selection UI prevents mixing those two types in one list.
  • Predefined audiences. Choose Fans and Subscribers, Current Fans, All Current Subscribers, Previously Paid Subscribers, Top 20 Spenders, or Prior Paid DM Users. The frontend maps display labels to backend audience keys.
  • Subscription audiences. Select subscription-plan audiences returned by the new-chat API. Preserve the plan ID when creating or editing the group list.
  • Bulk conversation view. Show saved message lists with their name, icon, recipient details, unread count, and recent activity. Select a list to open its broadcast history.
  • Broadcast delivery. Send text and attachments through the public/broadcast WebSocket action using the list's broadcast ID.
  • Edit list details. Rename a list and update its icon through the list-details modal.
  • Edit recipients. Search current and available participants, add or remove users or audience groups, and save the changes. The selected conversation reflects the updated participants.
  • Recipient count. Show the selected list's recipient count in the thread header; selecting it opens participant editing.
  • Delete a list. Confirm deletion in a modal, remove it through the API, and refresh the message-list view.
  • Personalized broadcast text. Insert the first-name token into list messages. Recipient expansion and delivery are backend responsibilities.

Source: new lists and audience selection, participant editing.

Store, portfolio, and event sharing

Creators have separate composer actions for inserting store items, portfolio content, and event tickets. These become typed message attachments with short share links.

  • Store item selection. The shared picker has All, Courses, Experiences, Merchandise, NFTs, and Downloadables tabs. Insert a selected item with its metadata and generated share URL.
  • Store previews. Conversation messages use the shared item-preview component. Selecting an inserted item navigates to its share route.
  • Portfolio selection. Browse All, Music, Podcasts, Videos, and Custom content. Pick albums, series, collections, or individual songs, episodes, videos, and custom items.
  • Portfolio drill-down. Browse the contents of a selected collection in the shared picker. Insert selected items as portfolio-share attachments; individual links include the player-open parameter.
  • Portfolio presentation. Render the shared portfolio preview with content-appropriate actions, such as viewing an album or playing an individual item.
  • Event selection. Browse the shared picker's Upcoming and Past tabs. Insert selected event options as event-ticket-share attachments with generated ticket-purchase links.
  • Event previews. Show an event image or fallback icon, title, venue/address, available date and time, and a View Ticket action.
  • Duplicate prevention. Pass already attached store, portfolio, and event IDs to their pickers so those options are disabled.
  • Mixed attachment composition. Share links can accompany text and uploaded files, appear in the attachment preview, and be removed before sending. Store and event insertion check the five-item capacity; the portfolio insertion path has a limit caveat below.

Source: share-link creation and insertion, portfolio picker.

Automated messages

  • Automation management. An Automated Messages tab lists each configured event type and its message text, with add, edit, and delete actions.
  • Four configured triggers. Fan Registers, Fan Purchases Subscription, Fan Purchases Content Post, and Fan's Birthday. The registration label maps to the backend FOLLOW_MESSAGE type.
  • One configuration per trigger. Disable event types already present in the automation list. Editing keeps the existing event type fixed.
  • Required text. Event type and message text are required. Text has a 1,000-character maximum and supports first-name insertion.
  • Image and audio attachments. The automation attachment component supports image uploads, audio uploads, voice recording, and audio preview. Its current file classifier does not accept newly selected video or generic files.
  • Paid automated attachments. Set a lock price with the automation's separate price modal and optionally provide a free preview. A positive price requires at least one main attachment.
  • Edit existing media. Restore existing paid/main and free-preview attachments. Existing attachments are marked as patched and reused without uploading them again.
  • Save and refresh. Create through POST, update through PUT, and delete by event type through DELETE. Refresh the table and show success or error feedback.
  • Cancel and reset. Closing clears form values, attachments, pricing, and audio previews, and aborts an active recording.

Source: triggers and form validation, automation editor, accepted automation media.

Permissions, safety, and white-label behavior

CapabilityAvailability in the frontend
Enter MessagesThe lazy-loaded route uses authentication, permission, and creator-approval guards. Delegate access references Send Reply to Direct Messages. The Messages tab also checks its permission key.
Send or start a messageThe new-message action and composer require the profile's 18-or-older flag. Younger users see an age notice and a customer-support link.
Lock attachmentsRequires Lock Message permission in the main composer, attached items, and a compatible composition state.
Manage automated messagesRequires Automated Messages permission. On a white-label site, the tab additionally requires the profile's host-owner flag.
Insert creator contentStore, portfolio, and event actions display for creator accounts.
Block a userThe main TopFan site exposes Block User from inbox and direct-thread menus. It opens a confirmation dialog and refreshes the inbox. These menus are hidden on white-label sites.
Hidden or exclusive creatorOn the main site, backend is_hidden validation hides composition and displays the creator-unavailable notice. White-label conversation behavior bypasses that particular display condition.
White-label conversation listShow the list on the main site, to the tenant owner, or when tenant DM settings allow it. Otherwise, select the tenant owner as the default conversation target.
Start a chat on a tenant siteThe New Message action is available to the tenant owner rather than other tenant visitors. Explicit incoming chat targets are respected, and self-targets are cleared.
Tenant contextUse white-label configuration for owner identity and waveform color; outgoing messages carry the white-label owner ID. Share URLs use environment configuration.
Delegate purchase actionsAttachment unlocking and the subscription purchase helper check delegate-user permission before starting payment. Tip handling also has delegate-specific conditions.

Source: route guards, composer and tab permissions, tenant targeting.

Limits and validation

ItemCurrent check
Main attachmentsFive items in the regular/paid attachment area. This check also applies when the message is free. Store and event links share this capacity. Portfolio insertion does not call the same capacity check.
Free previewsOne item in the separate free-preview area.
File sizeThe picker checks the first selected file against 512 MB and displays a video-size error if exceeded. It does not check every selected file individually in this method.
Main unlock priceThe main pricing modal disables Save below $1 or above $10,000 and uses two-decimal input formatting.
Automation unlock priceThe separate V2 modal uses a keypress limiter intended to cap entry at $1,000. It does not use the main modal's $1-to-$10,000 Save validation or currency-adjustment control.
Automated message textRequired, with a maximum of 1,000 characters.
Message list nameRequired, with a maximum of 25 characters.
List membershipAn individual-user list requires at least two selected users. An audience-group list requires at least one selected group. Participant editing preserves these minimums.
TipsSuggested amounts use a default minimum of $1 or the guaranteed-reply minimum. Custom amounts are checked against numeric format, qualifying minimums, and currency-derived bounds.
Empty messagesRequire nonblank text, an attachment, or share content.

Source: main pricing validation, automation pricing limiter, list form limits.

Implementation boundaries and related flows

  • Older-message scrolling is inactive. The template wires an upward-scroll event, but onUp() has its history-fetch call commented out. Initial history retrieval exists; working infinite history loading is not established by this implementation.
  • Reporting has a helper only. reportUser() opens the shared chat-report dialog, but the messages template has no call to it. The visible moderation action is Block User.
  • Dispute messages can be displayed. The thread recognizes dispute payloads and renders the product image, product name, price, and reason. It does not expose a dispute-creation form here.
  • Subscription helpers exist. The container can fetch a creator's plans, open a subscription picker, and launch subscription checkout. The current template does not call these helpers, so they are not counted as an exposed Messages action.
  • Welcome-message editing is separate. The profile welcome-message editor lives under Edit Preference. Its preview, enable/disable state, and upload controls are outside this module. The automation trigger labeled Fan Registers is part of Messages.
  • Purchase history is separate. Wallet's purchased-direct-messages view tracks purchased messages and redirects into a thread. Messages initiates attachment checkout and displays message content.
  • Feed-sharing copy is not evidence of a feature. Constants include a label for adding feed content, but this composer exposes store, portfolio, and event pickers. No separate feed-content picker is wired in its template.
  • No exposed message editing or deletion. The reviewed template has no per-message edit, delete, or unsend action. Message-list and automation deletion are separate supported operations.
  • Backend-driven execution. Automated trigger timing, audience resolution, guaranteed-reply refunds, payment settlement, and durable message delivery are not implemented by this frontend module.

Source: inactive scroll handler, report helper, actual UI bindings.

Source map

Main page and conversation behavior
messages.routes.ts and components/message-container/ cover inboxes, composition, media, payments, tenant rules, and live events.
List creation and editing
components/new-message-model/, components/edit-participants-modal/, and constants/messages.constant.ts define list fields, membership editing, and audience mappings.
Pricing and automation
components/message-price-model/, components/message-price-model-v2/, components/automated-message-modal/, and components/image-audo-message/ implement the two pricing flows and the automation editor.
Shared dependencies
services/chat.service.ts, shared/services/audio-recording.service.ts, and the shared store, portfolio, event, preview, and video-player components supply messaging integrations.