chore: initial project import
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
This commit is contained in:
570
prisma/schema.prisma
Normal file
570
prisma/schema.prisma
Normal file
@ -0,0 +1,570 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum TenantStatus {
|
||||
ACTIVE
|
||||
SUSPENDED
|
||||
TRIAL
|
||||
INACTIVE
|
||||
}
|
||||
|
||||
enum UserStatus {
|
||||
ACTIVE
|
||||
INVITED
|
||||
DISABLED
|
||||
}
|
||||
|
||||
enum RoleCode {
|
||||
SUPER_ADMIN
|
||||
ADMIN_CLIENT
|
||||
AGENT
|
||||
}
|
||||
|
||||
enum ChannelStatus {
|
||||
CONNECTED
|
||||
DISCONNECTED
|
||||
PENDING
|
||||
ERROR
|
||||
}
|
||||
|
||||
enum ConversationStatus {
|
||||
OPEN
|
||||
PENDING
|
||||
RESOLVED
|
||||
ARCHIVED
|
||||
SPAM
|
||||
}
|
||||
|
||||
enum ConversationPriority {
|
||||
LOW
|
||||
NORMAL
|
||||
HIGH
|
||||
URGENT
|
||||
}
|
||||
|
||||
enum MessageDirection {
|
||||
INBOUND
|
||||
OUTBOUND
|
||||
}
|
||||
|
||||
enum AuthTokenType {
|
||||
PASSWORD_RESET
|
||||
INVITE_ACCEPTANCE
|
||||
}
|
||||
|
||||
enum MessageType {
|
||||
TEXT
|
||||
IMAGE
|
||||
VIDEO
|
||||
AUDIO
|
||||
DOCUMENT
|
||||
TEMPLATE
|
||||
INTERACTIVE
|
||||
}
|
||||
|
||||
enum DeliveryStatus {
|
||||
QUEUED
|
||||
SENT
|
||||
DELIVERED
|
||||
READ
|
||||
FAILED
|
||||
}
|
||||
|
||||
enum OptInStatus {
|
||||
UNKNOWN
|
||||
OPTED_IN
|
||||
OPTED_OUT
|
||||
}
|
||||
|
||||
enum TemplateApprovalStatus {
|
||||
DRAFT
|
||||
PENDING
|
||||
APPROVED
|
||||
REJECTED
|
||||
DISABLED
|
||||
}
|
||||
|
||||
enum CampaignStatus {
|
||||
DRAFT
|
||||
SCHEDULED
|
||||
PROCESSING
|
||||
COMPLETED
|
||||
PARTIAL_FAILED
|
||||
FAILED
|
||||
CANCELED
|
||||
}
|
||||
|
||||
enum CampaignAudienceType {
|
||||
SEGMENT
|
||||
IMPORT
|
||||
MANUAL
|
||||
}
|
||||
|
||||
enum CampaignType {
|
||||
BROADCAST
|
||||
BULK_FOLLOWUP
|
||||
}
|
||||
|
||||
enum PaymentStatus {
|
||||
UNPAID
|
||||
PAID
|
||||
OVERDUE
|
||||
VOID
|
||||
}
|
||||
|
||||
model SubscriptionPlan {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
code String @unique
|
||||
priceMonthly Int
|
||||
messageQuota Int
|
||||
seatQuota Int
|
||||
broadcastQuota Int
|
||||
featuresJson String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenants Tenant[]
|
||||
invoices BillingInvoice[]
|
||||
}
|
||||
|
||||
model Tenant {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String @unique
|
||||
companyName String
|
||||
timezone String
|
||||
status TenantStatus @default(TRIAL)
|
||||
planId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
plan SubscriptionPlan @relation(fields: [planId], references: [id])
|
||||
users User[]
|
||||
roles Role[]
|
||||
channels Channel[]
|
||||
contacts Contact[]
|
||||
tags Tag[]
|
||||
conversations Conversation[]
|
||||
messages Message[]
|
||||
notes ConversationNote[]
|
||||
activities ConversationActivity[]
|
||||
segments ContactSegment[]
|
||||
templates MessageTemplate[]
|
||||
campaigns BroadcastCampaign[]
|
||||
auditLogs AuditLog[]
|
||||
webhookEvents WebhookEvent[]
|
||||
usageMetrics UsageMetric[]
|
||||
billingInvoices BillingInvoice[]
|
||||
}
|
||||
|
||||
model Role {
|
||||
id String @id @default(cuid())
|
||||
tenantId String?
|
||||
name String
|
||||
code RoleCode
|
||||
permissionsJson String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
||||
users User[]
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
fullName String
|
||||
email String @unique
|
||||
passwordHash String
|
||||
roleId String
|
||||
status UserStatus @default(INVITED)
|
||||
avatarUrl String?
|
||||
lastLoginAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
role Role @relation(fields: [roleId], references: [id])
|
||||
assignedConversations Conversation[]
|
||||
notes ConversationNote[]
|
||||
sentMessages Message[]
|
||||
activities ConversationActivity[] @relation("ActorActivities")
|
||||
campaigns BroadcastCampaign[]
|
||||
auditLogs AuditLog[]
|
||||
}
|
||||
|
||||
model AuthToken {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
tenantId String
|
||||
tokenType AuthTokenType
|
||||
tokenHash String @unique
|
||||
expiresAt DateTime
|
||||
consumedAt DateTime?
|
||||
createdByUser String?
|
||||
createdAt DateTime @default(now())
|
||||
metadataJson String?
|
||||
|
||||
@@index([userId, tokenType])
|
||||
@@index([tenantId, tokenType, expiresAt])
|
||||
}
|
||||
|
||||
model Channel {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
channelName String
|
||||
provider String
|
||||
wabaId String?
|
||||
phoneNumberId String?
|
||||
displayPhoneNumber String?
|
||||
status ChannelStatus @default(PENDING)
|
||||
webhookStatus String?
|
||||
lastSyncAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
contacts Contact[]
|
||||
conversations Conversation[]
|
||||
messages Message[]
|
||||
templates MessageTemplate[]
|
||||
campaigns BroadcastCampaign[]
|
||||
webhookEvents WebhookEvent[]
|
||||
}
|
||||
|
||||
model Contact {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
channelId String?
|
||||
externalRef String?
|
||||
fullName String
|
||||
phoneNumber String
|
||||
email String?
|
||||
avatarUrl String?
|
||||
countryCode String?
|
||||
optInStatus OptInStatus @default(UNKNOWN)
|
||||
lastInteractionAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
channel Channel? @relation(fields: [channelId], references: [id])
|
||||
conversations Conversation[]
|
||||
messages Message[]
|
||||
contactTags ContactTag[]
|
||||
segmentMembers SegmentMember[]
|
||||
campaignRecipients CampaignRecipient[]
|
||||
|
||||
@@unique([tenantId, phoneNumber])
|
||||
}
|
||||
|
||||
model Tag {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
name String
|
||||
color String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
contactTags ContactTag[]
|
||||
conversationTags ConversationTag[]
|
||||
|
||||
@@unique([tenantId, name])
|
||||
}
|
||||
|
||||
model ContactTag {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
contactId String
|
||||
tagId String
|
||||
createdAt DateTime @default(now())
|
||||
contact Contact @relation(fields: [contactId], references: [id])
|
||||
tag Tag @relation(fields: [tagId], references: [id])
|
||||
|
||||
@@unique([contactId, tagId])
|
||||
}
|
||||
|
||||
model Conversation {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
channelId String
|
||||
contactId String
|
||||
subject String?
|
||||
status ConversationStatus @default(OPEN)
|
||||
priority ConversationPriority @default(NORMAL)
|
||||
assignedUserId String?
|
||||
firstMessageAt DateTime?
|
||||
lastMessageAt DateTime?
|
||||
lastInboundAt DateTime?
|
||||
lastOutboundAt DateTime?
|
||||
resolvedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
channel Channel @relation(fields: [channelId], references: [id])
|
||||
contact Contact @relation(fields: [contactId], references: [id])
|
||||
assignedUser User? @relation(fields: [assignedUserId], references: [id])
|
||||
messages Message[]
|
||||
notes ConversationNote[]
|
||||
activities ConversationActivity[]
|
||||
conversationTags ConversationTag[]
|
||||
|
||||
@@index([tenantId, status])
|
||||
@@index([tenantId, assignedUserId])
|
||||
@@index([tenantId, lastMessageAt])
|
||||
}
|
||||
|
||||
model Message {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
conversationId String
|
||||
channelId String
|
||||
contactId String?
|
||||
direction MessageDirection
|
||||
type MessageType @default(TEXT)
|
||||
providerMessageId String? @unique
|
||||
replyToMessageId String?
|
||||
contentText String?
|
||||
mediaUrl String?
|
||||
mimeType String?
|
||||
deliveryStatus DeliveryStatus @default(QUEUED)
|
||||
failedReason String?
|
||||
sentByUserId String?
|
||||
sentAt DateTime?
|
||||
deliveredAt DateTime?
|
||||
readAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
conversation Conversation @relation(fields: [conversationId], references: [id])
|
||||
channel Channel @relation(fields: [channelId], references: [id])
|
||||
contact Contact? @relation(fields: [contactId], references: [id])
|
||||
sentByUser User? @relation(fields: [sentByUserId], references: [id])
|
||||
}
|
||||
|
||||
model ConversationNote {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
conversationId String
|
||||
userId String
|
||||
content String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
conversation Conversation @relation(fields: [conversationId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
}
|
||||
|
||||
model ConversationTag {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
conversationId String
|
||||
tagId String
|
||||
createdAt DateTime @default(now())
|
||||
conversation Conversation @relation(fields: [conversationId], references: [id])
|
||||
tag Tag @relation(fields: [tagId], references: [id])
|
||||
|
||||
@@unique([conversationId, tagId])
|
||||
}
|
||||
|
||||
model ConversationActivity {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
conversationId String
|
||||
actorUserId String?
|
||||
activityType String
|
||||
metadataJson String?
|
||||
createdAt DateTime @default(now())
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
conversation Conversation @relation(fields: [conversationId], references: [id])
|
||||
actorUser User? @relation("ActorActivities", fields: [actorUserId], references: [id])
|
||||
}
|
||||
|
||||
model ContactSegment {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
name String
|
||||
description String?
|
||||
rulesJson String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
members SegmentMember[]
|
||||
campaigns BroadcastCampaign[]
|
||||
}
|
||||
|
||||
model SegmentMember {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
segmentId String
|
||||
contactId String
|
||||
createdAt DateTime @default(now())
|
||||
segment ContactSegment @relation(fields: [segmentId], references: [id])
|
||||
contact Contact @relation(fields: [contactId], references: [id])
|
||||
|
||||
@@unique([segmentId, contactId])
|
||||
}
|
||||
|
||||
model MessageTemplate {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
channelId String
|
||||
name String
|
||||
category String
|
||||
languageCode String
|
||||
templateType String?
|
||||
bodyText String
|
||||
headerType String?
|
||||
footerText String?
|
||||
buttonsJson String?
|
||||
providerTemplateId String?
|
||||
approvalStatus TemplateApprovalStatus @default(DRAFT)
|
||||
rejectedReason String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
channel Channel @relation(fields: [channelId], references: [id])
|
||||
campaigns BroadcastCampaign[]
|
||||
}
|
||||
|
||||
model BroadcastCampaign {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
channelId String
|
||||
templateId String
|
||||
createdByUserId String
|
||||
name String
|
||||
campaignType CampaignType @default(BROADCAST)
|
||||
audienceType CampaignAudienceType
|
||||
segmentId String?
|
||||
scheduledAt DateTime?
|
||||
startedAt DateTime?
|
||||
finishedAt DateTime?
|
||||
status CampaignStatus @default(DRAFT)
|
||||
totalRecipients Int @default(0)
|
||||
totalSent Int @default(0)
|
||||
totalDelivered Int @default(0)
|
||||
totalRead Int @default(0)
|
||||
totalFailed Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
channel Channel @relation(fields: [channelId], references: [id])
|
||||
template MessageTemplate @relation(fields: [templateId], references: [id])
|
||||
createdByUser User @relation(fields: [createdByUserId], references: [id])
|
||||
segment ContactSegment? @relation(fields: [segmentId], references: [id])
|
||||
recipients CampaignRecipient[]
|
||||
|
||||
@@index([tenantId, status])
|
||||
@@index([status, scheduledAt])
|
||||
}
|
||||
|
||||
model CampaignRecipient {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
campaignId String
|
||||
contactId String
|
||||
phoneNumber String
|
||||
sendStatus DeliveryStatus @default(QUEUED)
|
||||
sendAttempts Int @default(0)
|
||||
maxSendAttempts Int @default(3)
|
||||
lastAttemptAt DateTime?
|
||||
nextRetryAt DateTime?
|
||||
failureReason String?
|
||||
providerMessageId String?
|
||||
sentAt DateTime?
|
||||
deliveredAt DateTime?
|
||||
readAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
campaign BroadcastCampaign @relation(fields: [campaignId], references: [id])
|
||||
contact Contact @relation(fields: [contactId], references: [id])
|
||||
|
||||
@@index([campaignId, sendStatus, nextRetryAt])
|
||||
@@index([campaignId, sendStatus])
|
||||
}
|
||||
|
||||
model BackgroundJobState {
|
||||
id String @id @default(cuid())
|
||||
jobName String @unique
|
||||
lockedBy String
|
||||
lockedUntil DateTime?
|
||||
runs Int @default(0)
|
||||
consecutiveFailures Int @default(0)
|
||||
lastRunStartedAt DateTime?
|
||||
lastRunCompletedAt DateTime?
|
||||
lastRunStatus String?
|
||||
lastRunSummaryJson String?
|
||||
lastError String?
|
||||
lastFailureAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model AuditLog {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
actorUserId String?
|
||||
entityType String
|
||||
entityId String
|
||||
action String
|
||||
metadataJson String?
|
||||
ipAddress String?
|
||||
userAgent String?
|
||||
createdAt DateTime @default(now())
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
actorUser User? @relation(fields: [actorUserId], references: [id])
|
||||
}
|
||||
|
||||
model WebhookEvent {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
channelId String?
|
||||
eventType String
|
||||
providerEventId String?
|
||||
eventHash String?
|
||||
payloadJson String
|
||||
processStatus String
|
||||
failedReason String?
|
||||
createdAt DateTime @default(now())
|
||||
processedAt DateTime?
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
channel Channel? @relation(fields: [channelId], references: [id])
|
||||
|
||||
@@index([tenantId, channelId, eventHash])
|
||||
}
|
||||
|
||||
model UsageMetric {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
metricDate DateTime
|
||||
inboundMessages Int @default(0)
|
||||
outboundMessages Int @default(0)
|
||||
activeContacts Int @default(0)
|
||||
activeAgents Int @default(0)
|
||||
broadcastSent Int @default(0)
|
||||
storageUsedMb Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
|
||||
@@unique([tenantId, metricDate])
|
||||
}
|
||||
|
||||
model BillingInvoice {
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
planId String
|
||||
invoiceNumber String @unique
|
||||
periodStart DateTime
|
||||
periodEnd DateTime
|
||||
subtotal Int
|
||||
taxAmount Int
|
||||
totalAmount Int
|
||||
paymentStatus PaymentStatus @default(UNPAID)
|
||||
dueDate DateTime
|
||||
paidAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id])
|
||||
plan SubscriptionPlan @relation(fields: [planId], references: [id])
|
||||
}
|
||||
Reference in New Issue
Block a user