Thread, message, encryption, polling, and chat_write behavior.
Messaging provides 1:1 threads between accepted friends. It supports text messages and article-share messages with inline article previews.
Primary tables:
threadsthread_messagesSupporting tables:
friendships for accepted-friend authorization.shares for article-share inbox rows.content for inline article previews.users for thread participant display names and avatars.ThreadModel reads:
idpairKeyparticipantIdscreatedAtlastMessageAtIf pairKey is absent, the model derives it by sorting and joining participantIds with :.
Thread creation writes:
pairKey: sorted participant IDs joined by :contentId: dm:{pairKey} for compatibilityparticipantIdscreatedAtThreadMessageModel reads:
threadIdauthorIdtype: text or articlebodycontentIdsentAtIf typed article columns are absent, it can parse legacy article messages from body values beginning with __ponder_article__: followed by content ID and optional caption.
FriendsService uses ThreadMessageCipher before writes and after reads:
postMessage.shareArticle.ThreadMessageCipher uses AES-GCM with 256-bit keys and HKDF/HMAC-SHA256. Encrypted values are prefixed with __ponder_encrypted_v1__: and store base64-url encoded nonce, ciphertext, and MAC bytes. The derived key context is based on sorted participant IDs, with a legacy thread-ID context fallback during decryption.
chat_write is the preferred write path for:
getOrCreateThreadpostMessageshareArticleThe function validates:
POST method.It writes row permissions for participants and authors where row security applies.
ThreadScreen watches threadMessagesProvider(threadId).
threadMessagesProvider:
threadMessagesPollingIntervalProvider, currently two seconds.Message reads use FriendsService.getThreadMessages, which queries thread_messages by threadId, orders by sentAt ascending, fetches the thread, decrypts rows, and maps them to ThreadMessageModel.
ThreadScreen:
contentId.The code intentionally supports current and legacy schemas. Current rows use pairKey, type, and contentId; legacy fallbacks use contentId thread lookup and encoded article-message bodies.