Real-time messaging between posters and contractors. Job-based conversations with attachments, AI assistant, and read receipts.
Messages will appear here when you connect with contractors on your jobs.
messages: defineTable({
jobId: v.id("jobs"),
senderId: v.string(), // posterUsers | contractorUsers | adminUsers ID
senderType: v.string(), // "poster" | "contractor" | "admin"
receiverId: v.string(),
receiverType: v.string(),
content: v.string(),
isRead: v.boolean(),
isDeleted: v.optional(v.boolean()),
attachmentUrl: v.optional(v.string()),
attachmentName: v.optional(v.string()),
editedAt: v.optional(v.number()),
createdAt: v.number(),
})
.index("by_job_id", ["jobId"])
.index("by_receiver_unread", ["receiverId", "isRead"])
// Messages update in real-time via Convex reactive queries.
// useQuery() auto-subscribes to changes on the messages table.
// When a new message is inserted, all subscribed clients
// receive the update instantly — no polling needed.
// Poster
useQuery(api.poster.jobs.getMyJobs) // Inbox: jobs with contractors
useQuery(api.messaging.messages.getUnreadCount) // Unread badge count
useQuery(api.messaging.messages.listForJob) // Thread: messages for a job
// Contractor
useQuery(api.contractor.messages.listUnifiedInbox) // Unified DM + Q&A inbox
useQuery(api.messaging.messages.listForJob) // Thread: messages for a job
// Shared
useMutation(api.messaging.messages.send) // Send a message
useMutation(api.messaging.messages.markRead) // Mark conversation as read
useMutation(api.features.storage.generateUploadUrl) // File upload URL
components/messaging/
MessageBubble.tsx // Sent/received/system bubble with read receipts
MessageInput.tsx // Input bar with attachment, quick replies, send
ConversationHeader.tsx // Chat header with avatar, job context, actions
ConversationItem.tsx // Inbox list card with unread badge, preview
DateSeparator.tsx // "Today", "Yesterday" date dividers
TypingIndicator.tsx // Animated 3-dot typing indicator
index.ts // Barrel exports
text Standard text message
image Photo attachment (via expo-image-picker)
video Video attachment (max 60s)
document File attachment
quote Bid/estimate card (structured: amount + description)
system "Contract signed", "Payment received" etc.
ai_response AI assistant response (distinct styling)
app/(poster)/messages/index.tsx // Poster inbox
app/(poster)/messages/[id].tsx // Poster chat thread
app/(contractor)/(tabs)/messages/index.tsx // Contractor unified inbox
app/(contractor)/(tabs)/messages/[id].tsx // Contractor chat thread
app/messages/[jobId].tsx // Shared job chat (generic)