Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Feature ID: PF-67
Status: ✅ Implemented (All 3 Phases Complete)
Last Updated: 2026-04-09 Spec: PF-67-internal-real-time-messaging.md
Plan: PF-67-internal-real-time-messaging-PLAN.md
Purpose: Documents integration points for the Platform Messaging layer. All cores consume messaging via @/platform/messaging (Pattern 1: Platform Integration Layer).

Integration Type

Pattern 1: Platform Integration Layer
  • Location: src/platform/messaging/ (implemented)
  • Public API: Hooks and components exported from @/platform/messaging
  • Consumers: All cores (RH, HR, FA, GR, FW, FM, LO, IT, CE) for record threads and internal chat

Platform Foundation Dependencies (Upstream)

SpecIntegration TypePurpose
PF-66 (Realtime Layer)DirectuseRealtimeSubscription, useRealtimeBroadcast, useRealtimePresence
PF-10 (Notifications)Platform LayerOffline/mention notifications via outbox + edge function
PF-02 (RBAC)DirectUser authentication, sender identity
PF-06 (Profiles)DirectDisplay names, avatars for message bubbles and presence
PF-30 (Permissions)DirectPermission keys: pf.messaging.view, .create_group, .create_channel, .moderate, .manage_settings
PF-56 (File Upload)Platform LayerFile/image sharing in messages
PF-42 (Rate Limiting)Direct60 messages/min/user rate limiting

Consumer Core Integration (Downstream)

CoreUsageRecord Thread Entity Examples
RHIncident discussions, bed coordinationrh_significant_events, rh_beds
HRCandidate feedback, onboardinghr_employees, hr_candidates
FWApproval discussionsfw_approval_requests
FAInvoice/expense discussionsfa_invoices, fa_bills
GRAudit remediation, contractsgr_audit_findings, gr_contracts
FMWork order coordinationfm_work_orders
LOIssue discussions (migration from LO discussions)lo_issues, lo_todos
ITTicket discussionsit_tickets
CELead follow-up (internal only)ce_contacts, ce_leads
Contract: Cores embed <ChatPanel recordType="…" recordId="…" /> from @/platform/messaging; no direct table access.

API Contract (Implemented)

Hooks

HookSignaturePurpose
useConversations(options?) => { conversations, isLoading, error }List user’s conversations
useMessages(options) => { messages, isLoading, hasMore, loadMore, isConnected, realtimeLastUpdated, realtimeError }Paginated messages + PF-66 subscription
useSendMessage() => { sendMessage, isSending }Send message mutation (invalidates active thread on success)
useCreateConversation() => { createConversation, isCreating }Create DM/group/channel
useRecordThread(recordType, recordId) => { conversation, getOrCreate, isLoading }Get or create record thread
useUnreadCounts() => { globalCount, perConversation }Unread count tracking
useTypingIndicator(conversationId) => { typingUsers, sendTyping }Typing indicator broadcast
useOnlineStatus() => { onlineUsers, trackPresence }Org-wide presence
useMessageReactions(conversationId) => { toggleReaction, … }Emoji toggle via pf_toggle_message_reaction
useMarkConversationRead(conversationId, messages) => voidDebounced pf_mark_conversation_read for read cursor
useMessageAttachmentUrl(fileUrl) => { displayUrl, … }Signed URL for file_url storage paths
useMessageSearch(conversationId) => { results, isSearching, … }Full-text message search
useChannels(options?) => { channels, isLoading }Browse/discover channels
useConversationMembers(conversationId) => { members, isLoading }Member management
useMessageActions(conversationId) => { editMessage, deleteMessage, togglePin }Edit/delete + pf_toggle_message_pin
useConversationSummarization(conversationId) => { summarize, summary, isLoading }AI conversation summary
useMessageTranslation(messageId) => { translate, translation, isLoading }AI message translation

Components

ComponentPropsPurpose
ChatPanelrecordType?, recordId?, title?Embeddable chat panel for record pages
MessageBubblemessage, currentUserIdSingle message display
MessageThreadconversationIdScrollable message list
MessageComposerconversationId, onSendMessage input area
OnlineStatusBadgeuserIdStatus dot (green/yellow/gray)
ChatNotificationBadgeGlobal unread count badge
ConversationListonSelect, selectedId?Sidebar conversation list
ConversationCreateDialogonCreated?New DM/group dialog
ChannelBrowserDialogonJoined?Channel discovery/join dialog
MemberManageSheetconversationIdMember add/remove sheet
MessageSearchDialogonResultClick?Global message search
EmojiReactionPickeronSelectEmoji reaction selector
FileUploadButtononFileReadyUpload to storage; persists path on send (not signed URL)
FilePreviewfileUploaded file preview

Edge Functions

FunctionTriggerPurpose
messaging-notify-mentionsDB trigger on pf_messages INSERTPF-10 notifications for @mentions
messaging-retention-cleanupCron: daily 2 AM UTCDelete expired messages per retention policy
lo-issue-discussions-to-pf67Manual invocationMigrate LO issue discussions to PF-67 conversations

Event Contracts

EventSourcePayloadConsumers
new_messagepf_messages INSERT (Realtime){ conversation_id, sender_id, content_preview }Messaging UI, notification outbox
typingPF-66 Broadcast{ userId, displayName }Typing indicator UI
presencePF-66 Presence{ userId, displayName, avatarUrl, status }Online status badges

Database Tables

TablePurposeRLS Pattern
pf_conversationsConversation containers (DM, group, channel, record_thread)SECURITY DEFINER: pf_can_view_conversation()
pf_conversation_membersMembership, roles, read stateSECURITY DEFINER: pf_can_view_conversation()
pf_messagesIndividual messagesSECURITY DEFINER: pf_is_conversation_member()
pf_message_read_receiptsPer-user read tracking (append-only)Org access check

RPCs (SECURITY DEFINER)

FunctionPurpose
pf_toggle_message_reaction(p_message_id, p_emoji)Atomic reaction map update (any member)
pf_toggle_message_pin(p_message_id)Atomic pin toggle (sender or pf.messaging.moderate)
pf_mark_conversation_read(p_conversation_id, p_last_read_message_id)Per-user read cursor + unread reset

Security Considerations

  • Multi-tenant isolation: RLS with SECURITY DEFINER helpers on all tables
  • Organization immutability: BEFORE UPDATE trigger prevents organization_id changes
  • PHI/PII: No PHI in Realtime broadcast/presence payloads; follow constitution §4 for AI and logging
  • Broadcast/Presence payloads: Whitelisted fields only (no PHI/PII)
  • Attachments: Store bucket-relative paths on pf_messages.file_url; issue short-lived signed URLs in the client at read time

Integration Matrix

  • CROSS_CORE_INTEGRATIONS.md: PF-67 is a Platform Integration Layer consumed by all cores via @/platform/messaging.

Utilities

UtilityImportPurpose
parseMentions@/platform/messagingExtract @mentions from message content
hasMentions@/platform/messagingCheck if content contains mentions
sanitizeContent@/platform/messagingSanitize message content for storage
formatMessageTime@/platform/messagingFormat message timestamps
createMessagePreview@/platform/messagingCreate preview text for conversation list
formatConversationName@/platform/messagingFormat conversation display name
calculateGlobalUnreadCount@/platform/messagingCompute total unread across conversations
isAttachmentStoragePath@/platform/messagingDetect path vs legacy https:// in file_url

References