This file defines the structural abstraction of the system. It includes the main entities, their attributes, relationships, and key operations. The model serves as a blueprint for implementation and guides the design of the database schema, API endpoints, and business logic.
classDiagram
class Workspace {
+int id
+string name
+datetime createdAt
+datetime updatedAt
}
class User {
+int id
+int workspaceId
+string name
+string email
+datetime createdAt
+datetime updatedAt
+me()
}
class Contact {
+int id
+int workspaceId
+string name
+string company
+string segment
+string role
+string phone
+string city
+string state
+datetime createdAt
+datetime updatedAt
+list()
+get()
+create()
+update()
+merge()
+setScore()
+getQualification()
+setQualification()
+templateDownload()
+contactsUpload()
+contactsExcel()
}
class ContactPin {
+int id
+int workspaceId
+int userId
+int contactId
+int slot
+datetime createdAt
+datetime updatedAt
+list()
+set()
+clear()
}
class ContactQualification {
+int id
+int workspaceId
+int userId
+int contactId
+string kindKey
+int score
+datetime createdAt
+datetime updatedAt
}
class ContactScore {
+int id
+int workspaceId
+int userId
+int contactId
+string sourceKey
+int value
+datetime createdAt
+datetime updatedAt
}
class Pipeline {
+int id
+int workspaceId
+string name
+datetime createdAt
+datetime updatedAt
+list()
}
class Stage {
+int id
+int workspaceId
+int pipelineId
+string name
+int sortIndex
+datetime updatedAt
}
class Deal {
+int id
+int workspaceId
+int contactId
+int pipelineId
+int stageId
+string statusKey
+datetime createdAt
+datetime updatedAt
+create()
+changeStage()
+markWon()
+markLost()
}
class Conversation {
+int id
+int workspaceId
+string kindKey
+string statusKey
+datetime createdAt
+datetime updatedAt
+get()
+openForContact()
+openDirect()
+setStatus()
+setScore()
}
class ConversationParticipant {
+int id
+int workspaceId
+int conversationId
+string actorKindKey
+int userId
+int contactId
+datetime createdAt
+datetime updatedAt
}
class ConversationQualification {
+int id
+int workspaceId
+int userId
+int conversationId
+string sourceKey
+string kindKey
+int score
+datetime createdAt
+datetime updatedAt
}
class ConversationScore {
+int id
+int workspaceId
+int userId
+int conversationId
+string sourceKey
+int value
+datetime createdAt
+datetime updatedAt
}
class Message {
+int id
+int workspaceId
+int conversationId
+string authorKindKey
+int authorUserId
+int authorContactId
+string channelKey
+string kindKey
+string body
+string payloadJson
+string externalId
+datetime createdAt
+datetime updatedAt
+list()
+listUnread()
+markRead()
+markReadBatch()
+send()
+ingestInbound()
}
class MessageAttachment {
+int id
+int workspaceId
+int messageId
+string kindKey
+string url
+string fileName
+int sizeBytes
+datetime createdAt
+datetime updatedAt
}
class MessageReceipt {
+int id
+int workspaceId
+int userId
+int messageId
+string statusKey
+datetime createdAt
+datetime updatedAt
}
class Delivery {
+int id
+int workspaceId
+int messageId
+string statusKey
+string providerMessageId
+string errorCode
+string errorMessage
+datetime updatedAt
+retry()
+updateFromProvider()
}
class Call {
+int id
+int workspaceId
+int conversationId
+int startedByUserId
+int startedByContactId
+string channelKey
+string kindKey
+string statusKey
+datetime startedAt
+datetime endedAt
+string payloadJson
+datetime createdAt
+datetime updatedAt
+list()
+start()
+ingestInbound()
+updateStatus()
+end()
}
class Event {
+int id
+int workspaceId
+string typeKey
+string entityTypeKey
+int entityId
+int actorUserId
+string payloadJson
+datetime createdAt
+counters()
+performance()
}
class Job {
+int id
+int workspaceId
+int createdByUserId
+string kindKey
+string statusKey
+string inputJson
+string resultJson
+string fileUrl
+datetime createdAt
+datetime startedAt
+datetime finishedAt
+datetime updatedAt
+get()
}
class ChannelAdapter {
<<abstract>>
+sendMessage()
+ingestInboundMessage()
+startCall()
+ingestInboundCall()
+updateDelivery()
}
class JobRunner {
<<abstract>>
+enqueue()
+run()
+retry()
}
class EventLog {
<<abstract>>
+append()
+listByEntity()
}
class Qualifier {
<<abstract>>
+classifyContact()
+overrideContactQualification()
}
Workspace "1" --> "*" User : has
Workspace "1" --> "*" Contact : has
Workspace "1" --> "*" ContactPin : has
Workspace "1" --> "*" ContactQualification : has
Workspace "1" --> "*" ContactScore : has
Workspace "1" --> "*" Pipeline : has
Workspace "1" --> "*" Stage : has
Workspace "1" --> "*" Deal : has
Workspace "1" --> "*" Conversation : has
Workspace "1" --> "*" ConversationParticipant : has
Workspace "1" --> "*" ConversationQualification : has
Workspace "1" --> "*" ConversationScore : has
Workspace "1" --> "*" Message : has
Workspace "1" --> "*" MessageAttachment : has
Workspace "1" --> "*" MessageReceipt : has
Workspace "1" --> "*" Delivery : has
Workspace "1" --> "*" Call : has
Workspace "1" --> "*" Event : has
Workspace "1" --> "*" Job : has
Contact "1" --> "*" ContactPin : pinned
Contact "1" --> "*" ContactQualification : qualifiedBy
Contact "1" --> "*" ContactScore : scoredBy
Contact "1" --> "*" Deal : has
Contact "1" --> "*" ConversationParticipant : participates
Pipeline "1" --> "*" Stage : includes
Pipeline "1" --> "*" Deal : uses
Stage "1" --> "*" Deal : in
Conversation "1" --> "*" ConversationParticipant : has
Conversation "1" --> "*" ConversationQualification : qualifiedBy
Conversation "1" --> "*" ConversationScore : scoredBy
Conversation "1" --> "*" Message : contains
Conversation "1" --> "*" Call : contains
Message "1" --> "*" MessageAttachment : has
Message "1" --> "*" MessageReceipt : tracks
Message "1" --> "*" Delivery : tracks
User "1" --> "*" ContactPin : sets
User "1" --> "*" ContactQualification : sets
User "1" --> "*" ContactScore : sets
User "1" --> "*" ConversationParticipant : participates
User "1" --> "*" ConversationQualification : sets
User "1" --> "*" ConversationScore : sets
User "1" --> "*" MessageReceipt : recipient
User "1" --> "*" Event : actor
User "1" --> "*" Job : creates
Contact ..> ContactQualification : set/get qualification
Contact ..> ContactScore : set score
Conversation ..> ConversationParticipant : manage participants
Conversation ..> ConversationScore : set score
Message ..> MessageReceipt : unread/read
Message ..> Delivery : send/track
ChannelAdapter ..> Message : message channel adapters
ChannelAdapter ..> Call : call channel adapters
ChannelAdapter ..> Delivery : provider status updates
JobRunner ..> Job : background work state
JobRunner ..> Contact : contact import/export
JobRunner ..> Delivery : message delivery
JobRunner ..> ContactQualification : AI classification outputs
EventLog ..> Event : append-only events
Qualifier ..> ContactQualification : contact qualification
note for Workspace "Workspace: tenant boundary for data and permissions."
note for User "User: CRM member who sends messages and manages contacts."
note for Contact "Contact: person/company; participates in conversations and owns deals."
note for ContactPin "Pin: user-priority contact slot (max 5 in UI)."
note for ContactQualification "Contact Qualification: category assignment for contact."
note for ContactScore "Contact Score: 1-5 rating assigned to a contact."
note for Pipeline "Pipeline: named set of deal stages."
note for Stage "Stage: step in a pipeline for deal position."
note for Deal "Deal: sales opportunity linked to a contact."
note for Conversation "Conversation: thread with participants (contact or direct), contains messages/calls."
note for ConversationParticipant "Conversation Participant: actor membership entry for conversation (user or contact)."
note for ConversationScore "Conversation Score: 1-5 rating assigned to a conversation."
note for Message "Message: authored communication item with channel, kind, body. Author invariant: user => authorUserId set and authorContactId null; contact => authorContactId set and authorUserId null; system => both null."
note for MessageAttachment "Attachment: media metadata plus file reference."
note for MessageReceipt "Message Receipt: per-user read state for message: unread/read."
note for Delivery "Delivery: outbound provider delivery tracking and error details."
note for Call "Call: communication record with channel, kind, status, timestamps."
note for Event "Event: immutable audit/timeline/metrics record."
note for Job "Job: background task record (delivery, classify, import, export)."
note for Message "Message keys: authorKind(user/contact/system), channel(internal/email/sms/whatsapp/telegram), kind(text/media)."
note for Delivery "Delivery status: queued/sent/delivered/read/failed."
note for Call "Call keys: channel(internal/whatsapp/telegram/phone), kind(voice/video), status(initiated/ringing/connected/ended/missed/failed)."
note for Deal "Deal status: open/won/lost."
note for Job "Job status: queued/running/succeeded/failed. Job kind: deliver_message/classify_conversation/import_contacts/export_contacts."
note for ChannelAdapter "Normalize inbound webhooks and send outbound messages/calls per channel."
note for JobRunner "Runs delivery, AI classification, import, and export using job kind keys."
note for EventLog "Append-only event stream used for audit, timelines, counters, and performance metrics."
note for Qualifier "Applies qualification keys and allows user overrides on the latest value."