Adding SMS automation

This commit is contained in:
2026-09-13 19:11:47 +03:30
parent bd63d2ab76
commit 45b0d46cfe
26 changed files with 1724 additions and 31 deletions
@@ -0,0 +1,84 @@
CREATE TYPE "MessageAutomationTrigger" AS ENUM (
'person_created',
'lead_submitted',
'deal_created',
'deal_stage_changed',
'deal_won',
'deal_lost',
'ticket_created',
'ticket_resolved',
'invoice_issued',
'invoice_paid',
'activity_created',
'activity_done'
);
CREATE TYPE "MessageAutomationDelayUnit" AS ENUM ('minutes', 'hours', 'days');
CREATE TYPE "MessageAutomationChannel" AS ENUM ('app', 'sms', 'both');
CREATE TYPE "MessageAutomationTarget" AS ENUM ('staff', 'person', 'both');
CREATE TYPE "MessageAutomationJobStatus" AS ENUM ('pending', 'sent', 'cancelled', 'failed');
CREATE TABLE "MessageAutomationRule" (
"id" TEXT NOT NULL,
"organizationId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"trigger" "MessageAutomationTrigger" NOT NULL,
"startDelayValue" INTEGER NOT NULL DEFAULT 0,
"startDelayUnit" "MessageAutomationDelayUnit" NOT NULL DEFAULT 'minutes',
"repeatCount" INTEGER NOT NULL DEFAULT 1,
"intervalValue" INTEGER NOT NULL DEFAULT 1,
"intervalUnit" "MessageAutomationDelayUnit" NOT NULL DEFAULT 'days',
"notifyTarget" "MessageAutomationTarget" NOT NULL DEFAULT 'person',
"channel" "MessageAutomationChannel" NOT NULL DEFAULT 'sms',
"title" TEXT NOT NULL,
"body" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "MessageAutomationRule_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "MessageAutomationJob" (
"id" TEXT NOT NULL,
"organizationId" TEXT NOT NULL,
"ruleId" TEXT NOT NULL,
"trigger" "MessageAutomationTrigger" NOT NULL,
"entityType" TEXT NOT NULL,
"entityId" TEXT NOT NULL,
"entityTitle" TEXT NOT NULL,
"personId" TEXT,
"ownerId" TEXT,
"assigneeId" TEXT,
"attemptIndex" INTEGER NOT NULL,
"sendAt" TIMESTAMP(3) NOT NULL,
"status" "MessageAutomationJobStatus" NOT NULL DEFAULT 'pending',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"sentAt" TIMESTAMP(3),
CONSTRAINT "MessageAutomationJob_pkey" PRIMARY KEY ("id")
);
CREATE INDEX "MessageAutomationRule_organizationId_isActive_trigger_idx"
ON "MessageAutomationRule"("organizationId", "isActive", "trigger");
CREATE UNIQUE INDEX "MessageAutomationJob_ruleId_entityId_attemptIndex_key"
ON "MessageAutomationJob"("ruleId", "entityId", "attemptIndex");
CREATE INDEX "MessageAutomationJob_status_sendAt_idx"
ON "MessageAutomationJob"("status", "sendAt");
CREATE INDEX "MessageAutomationJob_organizationId_entityType_entityId_status_idx"
ON "MessageAutomationJob"("organizationId", "entityType", "entityId", "status");
ALTER TABLE "MessageAutomationRule"
ADD CONSTRAINT "MessageAutomationRule_organizationId_fkey"
FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "MessageAutomationJob"
ADD CONSTRAINT "MessageAutomationJob_organizationId_fkey"
FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "MessageAutomationJob"
ADD CONSTRAINT "MessageAutomationJob_ruleId_fkey"
FOREIGN KEY ("ruleId") REFERENCES "MessageAutomationRule"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+89
View File
@@ -176,6 +176,8 @@ model Organization {
loyaltyRewards LoyaltyReward[]
loyaltyRedemptions LoyaltyRedemption[]
automationRules AutomationRule[]
messageAutomationRules MessageAutomationRule[]
messageAutomationJobs MessageAutomationJob[]
memoryItems MemoryItem[]
noteAiSuggestions NoteAiSuggestion[]
accountingConnections AccountingConnection[]
@@ -1083,6 +1085,93 @@ model AutomationRule {
@@index([organizationId, isActive, trigger])
}
enum MessageAutomationTrigger {
person_created
lead_submitted
deal_created
deal_stage_changed
deal_won
deal_lost
ticket_created
ticket_resolved
invoice_issued
invoice_paid
activity_created
activity_done
}
enum MessageAutomationDelayUnit {
minutes
hours
days
}
enum MessageAutomationChannel {
app
sms
both
}
enum MessageAutomationTarget {
staff
person
both
}
enum MessageAutomationJobStatus {
pending
sent
cancelled
failed
}
model MessageAutomationRule {
id String @id @default(cuid())
organizationId String
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
name String
isActive Boolean @default(true)
trigger MessageAutomationTrigger
startDelayValue Int @default(0)
startDelayUnit MessageAutomationDelayUnit @default(minutes)
repeatCount Int @default(1)
intervalValue Int @default(1)
intervalUnit MessageAutomationDelayUnit @default(days)
notifyTarget MessageAutomationTarget @default(person)
channel MessageAutomationChannel @default(sms)
title String
body String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
jobs MessageAutomationJob[]
@@index([organizationId, isActive, trigger])
}
model MessageAutomationJob {
id String @id @default(cuid())
organizationId String
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
ruleId String
rule MessageAutomationRule @relation(fields: [ruleId], references: [id], onDelete: Cascade)
trigger MessageAutomationTrigger
entityType String
entityId String
entityTitle String
personId String?
ownerId String?
assigneeId String?
attemptIndex Int
sendAt DateTime
status MessageAutomationJobStatus @default(pending)
createdAt DateTime @default(now())
sentAt DateTime?
@@unique([ruleId, entityId, attemptIndex])
@@index([status, sendAt])
@@index([organizationId, entityType, entityId, status])
}
/// چالش OTP برای ثبت‌نام / ورود پنل
model AuthChallenge {
id String @id @default(cuid())