October 25, 2026
The message system for DMs and official inquiries
Unified messaging for DMs and inquiries.
Introduction
Communication
#Platform
eric

As official arcade accounts expanded, arcades asked for a way to receive and answer inquiries inside Musecat. Visitors needed somewhere to leave a question, while staff needed to respond from the management dashboard. An inquiry also had to remain available when responsibility for an arcade changed hands.

The current Preview uses a common message engine for personal DMs, arcade inquiries and inquiries to the Musecat team. This engine handles storage, ordering and recovery. Participation, the identity represented by a reply and the progress of an inquiry depend on the kind of conversation.

Personal messages and official inquiries

A DM is a private conversation between two users. New messages depend on the recipient’s settings and blocks in both directions. Being an administrator does not grant access to everyone’s private conversations. The conditions for reading a conversation already joined are evaluated separately from permission to receive new messages.

An official inquiry belongs to an inbox rather than to one member of staff. For example, a new arcade representative should be able to continue an inquiry received before the handover. Instead of permanently copying former staff into its participants, the server checks current official-account relationships and operational roles whenever someone reads or sends. The Musecat team inbox applies its own corresponding permissions.

Mermaid
flowchart TD
    accTitle: One message engine with different access policies
    accDescr: Personal DMs and official inquiries use different access rules while sharing message storage queries and updates.
    D[Personal DM] --> P[Two participants plus reception and blocking]
    I[Arcade and team inquiries] --> Q[Requester and current responder authority]
    P --> M[Shared message engine]
    Q --> M
    M --> H[Ordered conversation history]
    M --> A[Authorized attachment access]
    M --> E[Change events and notifications]

An arcade can accept new inquiries on the site, direct visitors to external contact details or close intake. Those choices do not determine who can read existing inquiries. Sharing message storage avoids duplicating retry and attachment handling while allowing each inbox to retain these rules.

How conversations and messages are stored

A conversation is the parent of its messages. It stores its kind and latest message sequence, while the server assigns a sequence to each message to establish order. Read positions belong to individual users: one representative reading a message does not mark it read for everyone else.

An inquiry adds a requester, an inbox and a workflow status to this structure. A DM does not need those fields. The arcade dashboard opens the same conversation rather than maintaining a second copy of its messages.

Mermaid
erDiagram
    accTitle: Conversations messages and inquiry workflow
    accDescr: A shared conversation connects messages parties and personal read positions while inquiry conversations add business status.
    CONVERSATION ||--o{ MESSAGE : "contains messages"
    CONVERSATION ||--o{ PARTY : "connects identities"
    CONVERSATION ||--o{ READ_CURSOR : "tracks each reader"
    CONVERSATION ||--o| INQUIRY : "adds inquiry workflow"
    CONVERSATION {
        string id
        string kind
        int last_sequence
    }
    MESSAGE {
        int sequence
        string sender_user
        string acting_type
        string acting_id
        string client_message_id
    }
    PARTY {
        string party_type
        string party_id
    }
    READ_CURSOR {
        string user
        int last_read_sequence
    }
    INQUIRY {
        string requester
        string inbox_type
        string inbox_id
        string status
    }

The dashboard provides inquiry intake settings and a view of pending work. Even when announcements and opening status appear alongside them, each feature checks its own permissions. Reading a conversation, progressing an inquiry and publishing or closing an arcade describe different aspects of the service.

Authors and official reply identities

A reply displayed under an arcade’s name is still written by a signed-in person. To understand a past exchange after staff change, both identities matter. The server stores the actual account as sender_user, the represented identity as actingAs, and a snapshot of the author’s name and role.

DMs allow only the user’s own identity. Inquiries distinguish the requester from an authorized representative; someone with both roles must explicitly choose which one to use. The interface receives available identities and status actions from the server, and the server checks them again when accepting a message.

Attached photos follow the conversation’s access rules. A same-origin API passes the browser’s session into server authentication, then checks the conversation, message and file relationship before serving protected storage. Knowing a message URL or filename is insufficient. Actual file type and size are validated on the server too.

Message ordering and duplicate sends

After a connection fails, a sender may not know whether a message was saved. For example, the server might have committed it just before the response was lost. Treating a retry as a new message would display the same text twice. The interface therefore assigns a clientMessageId and preserves that ID and the content when retrying.

The server looks up the combination of conversation, actual author and client ID. Matching text and photo hashes return the saved message; reusing the ID with different content or identity produces a conflict. For a new send, sequence allocation, message storage, last-message information, inquiry status, recipient inboxes and delivery queues commit in one database transaction. Failure rolls back the group. External push and conversation-change events follow a successful commit.

Mermaid
sequenceDiagram
    accTitle: Identify retries and commit related records together
    accDescr: A matching retry returns its existing message. A new request saves sequence message inquiry state and notification work together.
    participant C as Conversation UI
    participant A as Message API
    participant D as Database
    participant E as Event connection
    C->>A: Client ID text and photos
    A->>D: Check current access and previous request
    alt Matching committed request
        D-->>A: Existing message
    else New request
        A->>D: Save sequence message and inquiry status
        A->>D: Save recipient inbox and delivery queue
        D-->>A: Commit together
        A-->>E: Conversation changed
    end
    A-->>C: Persisted message

A temporary item shows sending progress. It remains until retrieved history contains the same client ID, when it merges with the stored message. Failed items can be retried or removed. This pending list lives in screen memory, however, and does not provide a persistent offline outbox after the browser closes.

Live updates and conversation recovery

SSE provides the live update signal. It is a connection through which the server sends changes to the browser. A shared page Provider maintains one connection for the signed-in account, used by both message lists and the notification inbox.

A conversation.changed event carries the conversation ID and latest sequence. The interface requests messages after its last sequence, merges by ID and sorts by sequence. Events arriving during the initial query trigger another catch-up. Because history remains on the server, a sleeping tab or interrupted connection can recover missing messages through queries.

Mermaid
flowchart TD
    accTitle: Recover history through a shared event connection
    accDescr: Load history and fetch later sequences after SSE changes. Reconnect and resynchronize after interruptions and clear conversation data when access is lost.
    S[Fetch initial conversation history] --> H[Retain latest known sequence]
    E[Shared SSE change signal] --> F[Fetch after the known sequence]
    H --> F
    F --> M[Merge by message ID and sort by sequence]
    M --> H
    O[Disconnection or returning tab] --> R[Reconnect and resynchronize]
    R --> F
    P[Supplemental queries] --> F
    F -->|Access denied| C[Clear conversation history and pending items]

Reconnection and resynchronization are supplemented by history checks every 30 seconds during a normal connection, or every 5 seconds while a visible screen is disconnected. Catch-up work is bounded and continues on later refreshes. Session expiry or loss of access clears that conversation’s history and temporary sends, so previously cached private content does not remain on screen.

Read positions and inquiry status

Answering an inquiry does not necessarily resolve the issue at the arcade. For example, a representative may reply that they will inspect a cabinet. The visitor can read that reply while still waiting for the repair outcome. The system needs to express both how far each person has read and how the inquiry is progressing.

A read position is the sequence of the last message a user has seen. The server stores it as lastReadSequence and never moves it backwards. The interface updates it when the conversation is active, visible and scrolled to the latest message. Receiving an event or fetching in the background is not enough.

Mermaid
stateDiagram-v2
    accTitle: Inquiry workflow connected to messages
    accDescr: A new inquiry starts waiting and an official reply marks it recognised. A new requester message can reopen a solved inquiry.
    state "Waiting" as Waiting
    state "Recognised" as Recognised
    state "Solved" as Solved
    [*] --> Waiting: New inquiry
    Waiting --> Recognised: Official reply
    Recognised --> Solved: Mark solved
    Waiting --> Solved: Mark solved
    Solved --> Waiting: Requester follow-up
    Recognised --> Waiting: Requester follow-up
    Solved --> Recognised: Official reply

Inquiries have waiting, recognised and solved states. A requester’s message under their own identity returns the inquiry to waiting; an official reply sets recognised. Requesters can choose waiting or solved, while currently authorized representatives can select all three. A follow-up question reopens even a solved inquiry as waiting.

Notifications also follow these roles. Ordinary requester messages in arcade inquiries notify current official representatives, and official replies notify the requester. An explicit Musecat-team mention additionally alerts platform staff. The common message system can therefore support the exchange while retaining meaningful access, notification and workflow rules.

Related articles and sources: Notification inboxes and device push

Musecat
All About Arcades