Implementing a link tracking and user click logging system.Implementing a link tracking and user click logging system.

This commit is contained in:
2026-10-01 15:59:18 +03:30
parent ae21d9bbc7
commit 5d5b3a3213
20 changed files with 978 additions and 8211 deletions
+78
View File
@@ -119,6 +119,7 @@ enum AutomationTrigger {
invoice_issued
invoice_paid
activity_done
sms_link_clicked
}
enum AutomationAction {
@@ -215,6 +216,8 @@ model Organization {
conversationRoomMembers ConversationRoomMember[]
conversationRoomUserMutes ConversationRoomUserMute[]
conversationMessageReactions ConversationMessageReaction[]
trackingLinks TrackingLink[]
trackingEvents TrackingEvent[]
}
model User {
@@ -455,6 +458,8 @@ model Person {
accountingDocuments AccountingDocumentLog[]
openingBalances PartyOpeningBalance[]
cheques Cheque[]
trackingLinks TrackingLink[]
trackingEvents TrackingEvent[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -1306,6 +1311,7 @@ enum MessageAutomationTrigger {
invoice_paid
activity_created
activity_done
sms_link_clicked
}
enum MessageAutomationDelayUnit {
@@ -1787,14 +1793,84 @@ model SmsCampaignRecipient {
campaignId String
campaign SmsCampaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
personId String?
/// برای پشتیبانی آینده از Lead (فعلاً کمپین روی Person است)
leadId String?
mobile String?
/// pending | sent | failed | skipped
status String @default("pending")
error String?
sentAt DateTime?
createdAt DateTime @default(now())
trackingLinks TrackingLink[]
@@index([campaignId, status])
@@index([personId])
@@index([leadId])
}
/// لینک ردیابی یکتا — کانال‌خنثی (SMS / Email / …)
model TrackingLink {
id String @id @default(cuid())
organizationId String
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
/// توکن امن و غیرقابل‌حدس (بدون PII)
token String @unique
originalUrl String
/// sms | email | whatsapp | notification | other
channel String @default("sms")
/// sms_campaign | …
sourceType String
sourceId String
/// sms_campaign_recipient | …
recipientType String?
recipientId String?
smsRecipientId String?
smsRecipient SmsCampaignRecipient? @relation(fields: [smsRecipientId], references: [id], onDelete: SetNull)
personId String?
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
leadId String?
lead Lead? @relation(fields: [leadId], references: [id], onDelete: SetNull)
clickCount Int @default(0)
firstClickedAt DateTime?
lastClickedAt DateTime?
createdAt DateTime @default(now())
events TrackingEvent[]
@@index([organizationId, sourceType, sourceId])
@@index([organizationId, personId])
@@index([organizationId, leadId])
@@index([smsRecipientId])
@@index([token])
}
/// رویداد رفتاری عمومی — آمادهٔ Automation
model TrackingEvent {
id String @id @default(cuid())
organizationId String
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
trackingLinkId String?
trackingLink TrackingLink? @relation(fields: [trackingLinkId], references: [id], onDelete: SetNull)
/// مثلاً sms_link_clicked | sms_delivered | sms_failed | …
eventType String
channel String @default("sms")
sourceType String?
sourceId String?
recipientType String?
recipientId String?
personId String?
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
leadId String?
lead Lead? @relation(fields: [leadId], references: [id], onDelete: SetNull)
occurredAt DateTime @default(now())
/// ua / referrer / ipHash (اختیاری، بدون PII خام)
metadata Json?
createdAt DateTime @default(now())
@@index([organizationId, eventType, occurredAt])
@@index([organizationId, sourceType, sourceId, eventType])
@@index([organizationId, personId, eventType])
@@index([organizationId, leadId, eventType])
@@index([trackingLinkId, occurredAt])
}
/// اتصال فروشگاه ووکامرس
@@ -2009,6 +2085,8 @@ model Lead {
convertedAt DateTime?
archivedAt DateTime?
events LeadEvent[]
trackingLinks TrackingLink[]
trackingEvents TrackingEvent[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt