@danielcok17/prisma-db 1.18.0 → 1.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielcok17/prisma-db",
3
- "version": "1.18.0",
3
+ "version": "1.18.3",
4
4
  "description": "Shared Prisma schema for Legal AI applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/prisma/app.prisma CHANGED
@@ -30,113 +30,113 @@ model Account {
30
30
  }
31
31
 
32
32
  model User {
33
- id String @id @default(cuid())
34
- brand String @default("smartlex") // Multi-brand: "smartlex" | "justi"
35
- name String?
36
- email String?
37
- emailVerified DateTime?
38
- image String?
33
+ id String @id @default(cuid())
34
+ brand String @default("smartlex") // Multi-brand: "smartlex" | "justi"
35
+ name String?
36
+ email String?
37
+ emailVerified DateTime?
38
+ image String?
39
39
  // Credentials authentication fields
40
- password String? // Hashed password pre credentials login
41
- createdAt DateTime @default(now())
42
- agreedToTerms Boolean @default(false)
43
- practiceArea String[]
44
- lawFirm String?
45
- yearsOfExperience Int?
40
+ password String? // Hashed password pre credentials login
41
+ createdAt DateTime @default(now())
42
+ agreedToTerms Boolean @default(false)
43
+ practiceArea String[]
44
+ lawFirm String?
45
+ yearsOfExperience Int?
46
46
  // Nové polia pre schvalovanie používateľov
47
- isApproved Boolean @default(false) // Či je používateľ schválený
48
- isRejected Boolean @default(false) // Či je používateľ zamietnutý
49
- approvedAt DateTime? // Kedy bol schválený
50
- rejectedAt DateTime? // Kedy bol zamietnutý
51
- approvedBy String? // ID admina, ktorý schválil
52
- rejectedBy String? // ID admina, ktorý zamietol
53
- rejectionReason String? // Dôvod zamietnutia
47
+ isApproved Boolean @default(false) // Či je používateľ schválený
48
+ isRejected Boolean @default(false) // Či je používateľ zamietnutý
49
+ approvedAt DateTime? // Kedy bol schválený
50
+ rejectedAt DateTime? // Kedy bol zamietnutý
51
+ approvedBy String? // ID admina, ktorý schválil
52
+ rejectedBy String? // ID admina, ktorý zamietol
53
+ rejectionReason String? // Dôvod zamietnutia
54
54
  // Nové polia pre tracking a žiadosť
55
- referralSource String? // Odkiaľ sa o nás dozvedel (Google, Facebook, LinkedIn, etc.)
56
- applicationText String? // Text žiadosti o prihlásenie
55
+ referralSource String? // Odkiaľ sa o nás dozvedel (Google, Facebook, LinkedIn, etc.)
56
+ applicationText String? // Text žiadosti o prihlásenie
57
57
  // ✨ STRIPE FIELDS (B2C - len pre individuálnych používateľov)
58
- subscriptionTier SubscriptionTier @default(FREE) // Aktuálny subscription tier (cache)
59
- messageCount Int @default(4) // Free tier default
60
- messageCountResetAt DateTime? // Kedy sa má resetovať message count
61
- adminGrantExpiresAt DateTime? // Kedy admin grant expiruje
58
+ subscriptionTier SubscriptionTier @default(FREE) // Aktuálny subscription tier (cache)
59
+ messageCount Int @default(4) // Free tier default
60
+ messageCountResetAt DateTime? // Kedy sa má resetovať message count
61
+ adminGrantExpiresAt DateTime? // Kedy admin grant expiruje
62
62
  // ✨ COMPANY FIELDS (pre SZČO - samostatne zárobkovo činná osoba)
63
- customerType CustomerType @default(INDIVIDUAL) // Typ zákazníka: fyzická osoba alebo SZČO
64
- companyName String? // Obchodné meno (pre SZČO)
65
- companyNumber String? // IČO (povinné pre SZČO, 8 číslic)
66
- vatNumber String? // IČ DPH (SK + 10 číslic, nepovinné)
67
- taxNumber String? // DIČ (10 číslic, nepovinné)
68
- companyStreet String? // Ulica a číslo (pre SZČO)
69
- companyCity String? // Mesto (pre SZČO)
70
- companyPostalCode String? // PSČ (pre SZČO, formát: XXX XX)
71
- companyCountry String? @default("SK") // Krajina (ISO kód, default SK)
63
+ customerType CustomerType @default(INDIVIDUAL) // Typ zákazníka: fyzická osoba alebo SZČO
64
+ companyName String? // Obchodné meno (pre SZČO)
65
+ companyNumber String? // IČO (povinné pre SZČO, 8 číslic)
66
+ vatNumber String? // IČ DPH (SK + 10 číslic, nepovinné)
67
+ taxNumber String? // DIČ (10 číslic, nepovinné)
68
+ companyStreet String? // Ulica a číslo (pre SZČO)
69
+ companyCity String? // Mesto (pre SZČO)
70
+ companyPostalCode String? // PSČ (pre SZČO, formát: XXX XX)
71
+ companyCountry String? @default("SK") // Krajina (ISO kód, default SK)
72
72
  // ✨ UTM TRACKING & ATTRIBUTION FIELDS
73
73
  // First-visit attribution (celý lifecycle)
74
- firstUtmSource String? // Prvý UTM source
75
- firstUtmMedium String? // Prvý UTM medium
76
- firstUtmCampaign String? // Prvá kampaň
77
- firstUtmContent String? // Prvý content/variant
78
- firstUtmTerm String? // Prvé keywords
79
- firstVisitAt DateTime? // Kedy prvýkrát navštívil web
74
+ firstUtmSource String? // Prvý UTM source
75
+ firstUtmMedium String? // Prvý UTM medium
76
+ firstUtmCampaign String? // Prvá kampaň
77
+ firstUtmContent String? // Prvý content/variant
78
+ firstUtmTerm String? // Prvé keywords
79
+ firstVisitAt DateTime? // Kedy prvýkrát navštívil web
80
80
  // Registration attribution
81
- registrationUtmSource String? // UTM source pri registrácii
82
- registrationUtmMedium String? // UTM medium pri registrácii
83
- registrationUtmCampaign String? // Kampaň pri registrácii
84
- registrationUtmContent String? // Content/variant pri registrácii
85
- registrationUtmTerm String? // Keywords pri registrácii
81
+ registrationUtmSource String? // UTM source pri registrácii
82
+ registrationUtmMedium String? // UTM medium pri registrácii
83
+ registrationUtmCampaign String? // Kampaň pri registrácii
84
+ registrationUtmContent String? // Content/variant pri registrácii
85
+ registrationUtmTerm String? // Keywords pri registrácii
86
86
  // Profile fields
87
- phone String? // Mobilný telefón
88
- phoneVerified DateTime? // Kedy bol telefón overený cez OTP
89
- occupation String? // Povolanie (Právnik, Účtovník, etc.)
90
- preferredLanguage String? @default("sk") // Jazyk odpovedi (sk, cs, en)
87
+ phone String? // Mobilný telefón
88
+ phoneVerified DateTime? // Kedy bol telefón overený cez OTP
89
+ occupation String? // Povolanie (Právnik, Účtovník, etc.)
90
+ preferredLanguage String? @default("sk") // Jazyk odpovedi (sk, cs, en)
91
91
  // Email Lifecycle — 360° user view
92
92
  lastActiveAt DateTime?
93
93
  lastLoginAt DateTime?
94
94
  activatedAt DateTime?
95
- lifecycleStage LifecycleStage @default(REGISTERED)
96
- lifetimeValue Int @default(0)
95
+ lifecycleStage LifecycleStage @default(REGISTERED)
96
+ lifetimeValue Int @default(0)
97
97
  lastEmailSentAt DateTime?
98
98
  lastMarketingEmailSentAt DateTime?
99
- isEmailSuppressed Boolean @default(false)
100
- referralCode String? @unique
101
- churnRiskScore Int @default(0)
99
+ isEmailSuppressed Boolean @default(false)
100
+ referralCode String? @unique
101
+ churnRiskScore Int @default(0)
102
102
  churnRiskUpdatedAt DateTime?
103
103
  // Relations
104
- approvalRequest UserApprovalRequest?
105
- stripeCustomer StripeCustomer? // ✨ B2C Stripe customer
106
- ownedOrganizations Organization[] @relation("OrganizationOwner")
107
- organizationMembers OrganizationMember[]
108
- createdInvites OrganizationInvite[] @relation("InviteCreator")
109
- accounts Account[]
110
- answers Answer[]
111
- conversations Conversation[]
112
- feedbacks Feedback[]
113
- pageViews PageView[]
114
- sessions Session[]
115
- workflowLogs WorkflowLog[]
116
- verificationTokens VerificationToken[]
117
- passwordResetTokens PasswordResetToken[]
118
- phoneOtps PhoneOtp[]
119
- canvasDocuments CanvasDocument[]
120
- canvasDocumentVersions CanvasDocumentVersion[]
104
+ approvalRequest UserApprovalRequest?
105
+ stripeCustomer StripeCustomer? // ✨ B2C Stripe customer
106
+ ownedOrganizations Organization[] @relation("OrganizationOwner")
107
+ organizationMembers OrganizationMember[]
108
+ createdInvites OrganizationInvite[] @relation("InviteCreator")
109
+ accounts Account[]
110
+ answers Answer[]
111
+ conversations Conversation[]
112
+ feedbacks Feedback[]
113
+ pageViews PageView[]
114
+ sessions Session[]
115
+ workflowLogs WorkflowLog[]
116
+ verificationTokens VerificationToken[]
117
+ passwordResetTokens PasswordResetToken[]
118
+ phoneOtps PhoneOtp[]
119
+ canvasDocuments CanvasDocument[]
120
+ canvasDocumentVersions CanvasDocumentVersion[]
121
121
  // Folder system relations
122
- ownedFolders Folder[] @relation("FolderOwner")
123
- addedFolderItems FolderItem[] @relation("FolderItemAdder")
124
- folderActivities FolderActivity[] @relation("FolderActivityUser")
125
- folderSharesReceived FolderShare[] @relation("FolderShareUser")
126
- createdFolderShares FolderShare[] @relation("FolderShareCreator")
122
+ ownedFolders Folder[] @relation("FolderOwner")
123
+ addedFolderItems FolderItem[] @relation("FolderItemAdder")
124
+ folderActivities FolderActivity[] @relation("FolderActivityUser")
125
+ folderSharesReceived FolderShare[] @relation("FolderShareUser")
126
+ createdFolderShares FolderShare[] @relation("FolderShareCreator")
127
127
  // UTM tracking relations
128
- touchPoints TouchPoint[]
129
- conversions Conversion[]
128
+ touchPoints TouchPoint[]
129
+ conversions Conversion[]
130
130
  // Ingestion pipeline
131
- ingestedDocuments IngestedDocument[]
132
- adminGrants AdminGrant[]
133
- invoiceGrants InvoiceGrant[]
134
- emailSends EmailSend[]
135
- emailConsent EmailConsent?
136
- userScore UserScore?
137
- sequenceEnrollments EmailSequenceEnrollment[]
138
- referralsSent Referral[] @relation("ReferralsSent")
139
- referralsReceived Referral[] @relation("ReferralsReceived")
131
+ ingestedDocuments IngestedDocument[]
132
+ adminGrants AdminGrant[]
133
+ invoiceGrants InvoiceGrant[]
134
+ emailSends EmailSend[]
135
+ emailConsent EmailConsent?
136
+ userScore UserScore?
137
+ sequenceEnrollments EmailSequenceEnrollment[]
138
+ referralsSent Referral[] @relation("ReferralsSent")
139
+ referralsReceived Referral[] @relation("ReferralsReceived")
140
140
 
141
141
  // Multi-brand: compound unique allows same email across brands
142
142
  @@unique([email, brand])
@@ -197,10 +197,10 @@ model Organization {
197
197
 
198
198
  // Subscription (B2B)
199
199
  subscriptionTier SubscriptionTier @default(FREE) // Tier organizácie (cache)
200
- messageCount Int @default(0) // Spoločný pool správ pre všetkých členov
201
- messageLimit Int @default(4) // Free tier default
202
- messageCountResetAt DateTime? // Kedy sa má resetovať pool
203
- adminGrantExpiresAt DateTime? // Kedy admin grant expiruje
200
+ messageCount Int @default(0) // Spoločný pool správ pre všetkých členov
201
+ messageLimit Int @default(4) // Free tier default
202
+ messageCountResetAt DateTime? // Kedy sa má resetovať pool
203
+ adminGrantExpiresAt DateTime? // Kedy admin grant expiruje
204
204
 
205
205
  // Settings
206
206
  isActive Boolean @default(true)
@@ -287,7 +287,7 @@ model Conversation {
287
287
  updatedAt DateTime @updatedAt
288
288
  summary String?
289
289
  messagesSinceLastSummary Int? @default(0)
290
- integrityHash String? // HMAC-SHA256 hash chain - posledný chainHash pre verifikáciu integrity
290
+ integrityHash String? // HMAC-SHA256 hash chain - posledný chainHash pre verifikáciu integrity
291
291
  // Relácie
292
292
  answers Answer[]
293
293
  user User @relation(fields: [userId], references: [id])
@@ -312,8 +312,8 @@ model Answer {
312
312
  processingTime Int?
313
313
  model String?
314
314
  userId String?
315
- contentHash String? // HMAC-SHA256 hash obsahu správy (content + role + messageId)
316
- chainHash String? // Hash chain - zahŕňa predchádzajúci chainHash pre integritu sekvencie
315
+ contentHash String? // HMAC-SHA256 hash obsahu správy (content + role + messageId)
316
+ chainHash String? // Hash chain - zahŕňa predchádzajúci chainHash pre integritu sekvencie
317
317
  createdAt DateTime @default(now())
318
318
  updatedAt DateTime @updatedAt
319
319
  // Relácie
@@ -334,13 +334,13 @@ model Answer {
334
334
  }
335
335
 
336
336
  model MessageFile {
337
- id String @id @default(cuid())
338
- answerId String?
339
- fileName String
340
- fileType String
341
- base64Data String
342
- uploadedAt DateTime @default(now())
343
- answer Answer? @relation(fields: [answerId], references: [id], onDelete: Cascade)
337
+ id String @id @default(cuid())
338
+ answerId String?
339
+ fileName String
340
+ fileType String
341
+ base64Data String
342
+ uploadedAt DateTime @default(now())
343
+ answer Answer? @relation(fields: [answerId], references: [id], onDelete: Cascade)
344
344
 
345
345
  @@index([answerId])
346
346
  @@index([fileType])
@@ -847,11 +847,11 @@ enum CustomerType {
847
847
 
848
848
  // Stripe: Tier predplatného
849
849
  enum SubscriptionTier {
850
- FREE // Free tier (4 messages/month)
851
- LAWYER // Lawyer tier (1000 messages/month, €29/month, 1 user)
852
- LAWYER_PRO // Lawyer Pro tier (3000 messages/month, €49/month, 1 user) - RECOMMENDED
853
- LAW_FIRM // Law Firm tier (10000 messages/month, €129/month, up to 5 users)
854
- ENTERPRISE // Enterprise tier (unlimited messages, unlimited users, custom pricing)
850
+ FREE // Free tier (4 messages/month)
851
+ LAWYER // Lawyer tier (1000 messages/month, €29/month, 1 user)
852
+ LAWYER_PRO // Lawyer Pro tier (3000 messages/month, €49/month, 1 user) - RECOMMENDED
853
+ LAW_FIRM // Law Firm tier (10000 messages/month, €129/month, up to 5 users)
854
+ ENTERPRISE // Enterprise tier (unlimited messages, unlimited users, custom pricing)
855
855
  }
856
856
 
857
857
  // Stripe: Billing interval
@@ -1033,19 +1033,81 @@ model PasswordResetToken {
1033
1033
 
1034
1034
  // Phone OTP verification (BulkGate)
1035
1035
  model PhoneOtp {
1036
- id String @id @default(cuid())
1037
- userId String
1038
- phone String
1039
- bulkgateId String @unique // OTP ID from BulkGate API response
1040
- expiresAt DateTime
1041
- createdAt DateTime @default(now())
1042
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1036
+ id String @id @default(cuid())
1037
+ userId String
1038
+ phone String
1039
+ bulkgateId String @unique // OTP ID from BulkGate API response
1040
+ expiresAt DateTime
1041
+ createdAt DateTime @default(now())
1042
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1043
1043
 
1044
1044
  @@index([userId])
1045
1045
  @@index([bulkgateId])
1046
1046
  @@index([expiresAt])
1047
1047
  }
1048
1048
 
1049
+ model MeetingSlot {
1050
+ id String @id @default(cuid())
1051
+ startsAt DateTime
1052
+ durationMinutes Int @default(30)
1053
+ status MeetingSlotStatus @default(AVAILABLE)
1054
+ holdExpiresAt DateTime?
1055
+ note String?
1056
+ createdByAdminEmail String?
1057
+ createdAt DateTime @default(now())
1058
+ updatedAt DateTime @updatedAt
1059
+
1060
+ bookings MeetingBooking[]
1061
+
1062
+ @@index([status, startsAt])
1063
+ @@index([startsAt])
1064
+ }
1065
+
1066
+ model MeetingBooking {
1067
+ id String @id @default(cuid())
1068
+ slotId String
1069
+ status MeetingBookingStatus @default(OTP_PENDING)
1070
+ name String?
1071
+ email String
1072
+ phone String
1073
+ visitorNote String?
1074
+ publicToken String @unique
1075
+ bulkgateId String? @unique
1076
+ otpExpiresAt DateTime?
1077
+ holdExpiresAt DateTime?
1078
+ phoneVerifiedAt DateTime?
1079
+ slotStartAt DateTime
1080
+ slotEndAt DateTime
1081
+ adminNote String?
1082
+ adminActionBy String?
1083
+ acceptedAt DateTime?
1084
+ declinedAt DateTime?
1085
+ canceledAt DateTime?
1086
+ completedAt DateTime?
1087
+ noShowAt DateTime?
1088
+ createdAt DateTime @default(now())
1089
+ updatedAt DateTime @updatedAt
1090
+
1091
+ slot MeetingSlot @relation(fields: [slotId], references: [id], onDelete: Cascade)
1092
+
1093
+ @@index([slotId])
1094
+ @@index([status, createdAt])
1095
+ @@index([email])
1096
+ @@index([phone])
1097
+ @@index([slotStartAt])
1098
+ }
1099
+
1100
+ model MeetingBookingSettings {
1101
+ id String @id @default("default")
1102
+ bookingEnabled Boolean @default(true)
1103
+ timezone String @default("Europe/Bratislava")
1104
+ bookingHorizonDays Int @default(30)
1105
+ minLeadHours Int @default(12)
1106
+ adminNotificationEmail String @default("info@smartlex.sk")
1107
+ createdAt DateTime @default(now())
1108
+ updatedAt DateTime @updatedAt
1109
+ }
1110
+
1049
1111
  // ============================================
1050
1112
  // INGESTION PIPELINE MODELS
1051
1113
  // ============================================
@@ -1065,7 +1127,7 @@ model IngestedDocument {
1065
1127
  references String[] // Legal references from classification
1066
1128
  chunkCount Int?
1067
1129
  embeddingCost Float? // EUR
1068
- qdrantDocId String? @unique // doc_id used in Qdrant vector payloads
1130
+ qdrantDocId String? @unique // doc_id used in Qdrant vector payloads
1069
1131
  folderId String? // Optional folder association
1070
1132
  storagePath String? // Local filesystem path (dev/staging)
1071
1133
  storageUrl String? // Cloud storage URL (prod — S3/DigitalOcean Spaces)
@@ -1154,14 +1216,33 @@ enum ReferralStatus {
1154
1216
  }
1155
1217
 
1156
1218
  enum InvoiceGrantStatus {
1157
- PENDING // Faktúra odoslaná, čaká na platbu
1158
- PAID // Zaplatené, grant aktívny
1159
- VOID // Stornovaná (admin alebo Stripe)
1219
+ PENDING // Faktúra odoslaná, čaká na platbu
1220
+ PAID // Zaplatené, grant aktívny
1221
+ VOID // Stornovaná (admin alebo Stripe)
1160
1222
  }
1161
1223
 
1162
1224
  enum CollectionMethod {
1163
1225
  CHARGE_AUTOMATICALLY // Automatické strhnutie kartou
1164
- SEND_INVOICE // Faktúra na email (bank transfer)
1226
+ SEND_INVOICE // Faktúra na email (bank transfer)
1227
+ }
1228
+
1229
+ enum MeetingSlotStatus {
1230
+ AVAILABLE
1231
+ HELD
1232
+ BOOKED
1233
+ BLOCKED
1234
+ ARCHIVED
1235
+ }
1236
+
1237
+ enum MeetingBookingStatus {
1238
+ OTP_PENDING
1239
+ PENDING_ADMIN_REVIEW
1240
+ ACCEPTED
1241
+ DECLINED
1242
+ CANCELED
1243
+ COMPLETED
1244
+ NO_SHOW
1245
+ EXPIRED
1165
1246
  }
1166
1247
 
1167
1248
  // ============================================
@@ -1389,20 +1470,20 @@ model AdminGrant {
1389
1470
  // One-off admin invoice — standalone faktúra pre špeciálne prípady (demo, trial, custom deal)
1390
1471
  // Pre recurring fakturáciu použiť StripeSubscription s collectionMethod=SEND_INVOICE
1391
1472
  model InvoiceGrant {
1392
- id String @id @default(cuid())
1393
- userId String?
1394
- organizationId String?
1395
- stripeInvoiceId String @unique
1396
- tier SubscriptionTier
1397
- durationDays Int // Na koľko dní sa aktivuje grant po platbe
1398
- amount Int // Suma v centoch (EUR)
1399
- status InvoiceGrantStatus @default(PENDING)
1400
- grantId String? // ID AdminGrantu vytvoreného po platbe
1401
- createdBy String // Admin email
1402
- notes String?
1403
- paidAt DateTime?
1404
- createdAt DateTime @default(now())
1405
- updatedAt DateTime @updatedAt
1473
+ id String @id @default(cuid())
1474
+ userId String?
1475
+ organizationId String?
1476
+ stripeInvoiceId String @unique
1477
+ tier SubscriptionTier
1478
+ durationDays Int // Na koľko dní sa aktivuje grant po platbe
1479
+ amount Int // Suma v centoch (EUR)
1480
+ status InvoiceGrantStatus @default(PENDING)
1481
+ grantId String? // ID AdminGrantu vytvoreného po platbe
1482
+ createdBy String // Admin email
1483
+ notes String?
1484
+ paidAt DateTime?
1485
+ createdAt DateTime @default(now())
1486
+ updatedAt DateTime @updatedAt
1406
1487
 
1407
1488
  user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
1408
1489
  organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
@@ -1440,39 +1521,39 @@ model AppInvite {
1440
1521
  // ============================================
1441
1522
 
1442
1523
  model EmailSend {
1443
- id String @id @default(cuid())
1444
- userId String?
1445
- templateSlug String
1446
- campaignId String?
1447
-
1448
- status EmailStatus @default(QUEUED)
1449
- sentAt DateTime?
1450
- deliveredAt DateTime?
1451
- toEmail String
1452
- fromEmail String @default("info@mail.smartlex.sk")
1524
+ id String @id @default(cuid())
1525
+ userId String?
1526
+ templateSlug String
1527
+ campaignId String?
1528
+
1529
+ status EmailStatus @default(QUEUED)
1530
+ sentAt DateTime?
1531
+ deliveredAt DateTime?
1532
+ toEmail String
1533
+ fromEmail String @default("info@mail.smartlex.sk")
1534
+
1535
+ openedAt DateTime?
1536
+ openCount Int @default(0)
1537
+ clickedAt DateTime?
1538
+ clickCount Int @default(0)
1539
+
1540
+ bouncedAt DateTime?
1541
+ bounceType BounceType?
1542
+ complainedAt DateTime?
1543
+ unsubscribedAt DateTime?
1544
+
1545
+ errorMessage String?
1546
+ errorCode String?
1547
+
1548
+ subjectLine String?
1549
+ espMessageId String? @unique
1550
+ idempotencyKey String? @unique
1551
+ isTransactional Boolean @default(false)
1552
+ metadata Json?
1453
1553
 
1454
- openedAt DateTime?
1455
- openCount Int @default(0)
1456
- clickedAt DateTime?
1457
- clickCount Int @default(0)
1458
-
1459
- bouncedAt DateTime?
1460
- bounceType BounceType?
1461
- complainedAt DateTime?
1462
- unsubscribedAt DateTime?
1463
-
1464
- errorMessage String?
1465
- errorCode String?
1466
-
1467
- subjectLine String?
1468
- espMessageId String? @unique
1469
- idempotencyKey String? @unique
1470
- isTransactional Boolean @default(false)
1471
- metadata Json?
1472
-
1473
- createdAt DateTime @default(now())
1554
+ createdAt DateTime @default(now())
1474
1555
 
1475
- user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
1556
+ user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
1476
1557
 
1477
1558
  @@index([userId])
1478
1559
  @@index([templateSlug])
@@ -1486,43 +1567,43 @@ model EmailSend {
1486
1567
  }
1487
1568
 
1488
1569
  model EmailSequence {
1489
- id String @id @default(cuid())
1490
- slug String @unique
1491
- name String
1492
- description String?
1493
- triggerEvent String
1494
- isActive Boolean @default(true)
1570
+ id String @id @default(cuid())
1571
+ slug String @unique
1572
+ name String
1573
+ description String?
1574
+ triggerEvent String
1575
+ isActive Boolean @default(true)
1495
1576
 
1496
- steps EmailSequenceStep[]
1497
- enrollments EmailSequenceEnrollment[]
1577
+ steps EmailSequenceStep[]
1578
+ enrollments EmailSequenceEnrollment[]
1498
1579
 
1499
- createdAt DateTime @default(now())
1500
- updatedAt DateTime @updatedAt
1580
+ createdAt DateTime @default(now())
1581
+ updatedAt DateTime @updatedAt
1501
1582
  }
1502
1583
 
1503
1584
  model EmailSequenceStep {
1504
- id String @id @default(cuid())
1585
+ id String @id @default(cuid())
1505
1586
  sequenceId String
1506
1587
  templateSlug String
1507
1588
  stepOrder Int
1508
- delayMinutes Int @default(0)
1589
+ delayMinutes Int @default(0)
1509
1590
  sendCondition Json?
1510
1591
  skipCondition Json?
1511
- isActive Boolean @default(true)
1592
+ isActive Boolean @default(true)
1512
1593
 
1513
- sequence EmailSequence @relation(fields: [sequenceId], references: [id], onDelete: Cascade)
1594
+ sequence EmailSequence @relation(fields: [sequenceId], references: [id], onDelete: Cascade)
1514
1595
 
1515
- createdAt DateTime @default(now())
1596
+ createdAt DateTime @default(now())
1516
1597
 
1517
1598
  @@unique([sequenceId, stepOrder])
1518
1599
  }
1519
1600
 
1520
1601
  model EmailSequenceEnrollment {
1521
- id String @id @default(cuid())
1522
- userId String
1523
- sequenceId String
1524
- currentStep Int @default(0)
1525
- status EnrollmentStatus @default(ACTIVE)
1602
+ id String @id @default(cuid())
1603
+ userId String
1604
+ sequenceId String
1605
+ currentStep Int @default(0)
1606
+ status EnrollmentStatus @default(ACTIVE)
1526
1607
 
1527
1608
  enrolledAt DateTime @default(now())
1528
1609
  completedAt DateTime?
@@ -1531,51 +1612,51 @@ model EmailSequenceEnrollment {
1531
1612
  nextSendAt DateTime?
1532
1613
  processingLockedAt DateTime?
1533
1614
 
1534
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1535
- sequence EmailSequence @relation(fields: [sequenceId], references: [id])
1615
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1616
+ sequence EmailSequence @relation(fields: [sequenceId], references: [id])
1536
1617
 
1537
1618
  @@index([status, nextSendAt])
1538
1619
  @@index([userId, sequenceId, status])
1539
1620
  }
1540
1621
 
1541
1622
  model EmailConsent {
1542
- id String @id @default(cuid())
1543
- userId String @unique
1623
+ id String @id @default(cuid())
1624
+ userId String @unique
1544
1625
 
1545
- marketingConsent Boolean @default(false)
1546
- productUpdatesConsent Boolean @default(false)
1547
- legalNewsConsent Boolean @default(false)
1626
+ marketingConsent Boolean @default(false)
1627
+ productUpdatesConsent Boolean @default(false)
1628
+ legalNewsConsent Boolean @default(false)
1548
1629
 
1549
- doubleOptinSentAt DateTime?
1550
- doubleOptinConfirmedAt DateTime?
1551
- doubleOptinToken String? @unique
1630
+ doubleOptinSentAt DateTime?
1631
+ doubleOptinConfirmedAt DateTime?
1632
+ doubleOptinToken String? @unique
1552
1633
 
1553
- user User @relation(fields: [userId], references: [id], onDelete: Restrict)
1554
- history EmailConsentHistory[]
1634
+ user User @relation(fields: [userId], references: [id], onDelete: Restrict)
1635
+ history EmailConsentHistory[]
1555
1636
 
1556
- createdAt DateTime @default(now())
1557
- updatedAt DateTime @updatedAt
1637
+ createdAt DateTime @default(now())
1638
+ updatedAt DateTime @updatedAt
1558
1639
  }
1559
1640
 
1560
1641
  model EmailConsentHistory {
1561
- id String @id @default(cuid())
1562
- consentId String
1563
- userId String
1642
+ id String @id @default(cuid())
1643
+ consentId String
1644
+ userId String
1564
1645
 
1565
- action ConsentAction
1566
- channel String
1567
- oldValue Boolean?
1568
- newValue Boolean
1646
+ action ConsentAction
1647
+ channel String
1648
+ oldValue Boolean?
1649
+ newValue Boolean
1569
1650
 
1570
- consentText String
1571
- consentVersion String
1572
- consentMethod String
1573
- ipAddress String?
1574
- userAgent String?
1651
+ consentText String
1652
+ consentVersion String
1653
+ consentMethod String
1654
+ ipAddress String?
1655
+ userAgent String?
1575
1656
 
1576
- consent EmailConsent @relation(fields: [consentId], references: [id], onDelete: Restrict)
1657
+ consent EmailConsent @relation(fields: [consentId], references: [id], onDelete: Restrict)
1577
1658
 
1578
- createdAt DateTime @default(now())
1659
+ createdAt DateTime @default(now())
1579
1660
 
1580
1661
  @@index([userId, createdAt])
1581
1662
  @@index([consentId])
@@ -1583,25 +1664,25 @@ model EmailConsentHistory {
1583
1664
  }
1584
1665
 
1585
1666
  model UserScore {
1586
- id String @id @default(cuid())
1587
- userId String @unique
1588
- score Int @default(0)
1589
- leadSegment LeadSegment @default(COLD)
1590
- churnRisk ChurnRisk @default(NONE)
1667
+ id String @id @default(cuid())
1668
+ userId String @unique
1669
+ score Int @default(0)
1670
+ leadSegment LeadSegment @default(COLD)
1671
+ churnRisk ChurnRisk @default(NONE)
1591
1672
 
1592
- signupScore Int @default(0)
1593
- engagementScore Int @default(0)
1594
- usageScore Int @default(0)
1595
- intentScore Int @default(0)
1596
- decayScore Int @default(0)
1673
+ signupScore Int @default(0)
1674
+ engagementScore Int @default(0)
1675
+ usageScore Int @default(0)
1676
+ intentScore Int @default(0)
1677
+ decayScore Int @default(0)
1597
1678
 
1598
- lastActivityAt DateTime?
1599
- scoreUpdatedAt DateTime @default(now())
1679
+ lastActivityAt DateTime?
1680
+ scoreUpdatedAt DateTime @default(now())
1600
1681
 
1601
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1602
- events UserScoreEvent[]
1682
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1683
+ events UserScoreEvent[]
1603
1684
 
1604
- createdAt DateTime @default(now())
1685
+ createdAt DateTime @default(now())
1605
1686
 
1606
1687
  @@index([score])
1607
1688
  @@index([leadSegment])
@@ -1609,18 +1690,18 @@ model UserScore {
1609
1690
  }
1610
1691
 
1611
1692
  model UserScoreEvent {
1612
- id String @id @default(cuid())
1613
- userScoreId String
1614
- userId String
1615
- eventType String
1616
- pointsDelta Int
1617
- scoreBefore Int
1618
- scoreAfter Int
1619
- metadata Json?
1693
+ id String @id @default(cuid())
1694
+ userScoreId String
1695
+ userId String
1696
+ eventType String
1697
+ pointsDelta Int
1698
+ scoreBefore Int
1699
+ scoreAfter Int
1700
+ metadata Json?
1620
1701
 
1621
- userScore UserScore @relation(fields: [userScoreId], references: [id], onDelete: Cascade)
1702
+ userScore UserScore @relation(fields: [userScoreId], references: [id], onDelete: Cascade)
1622
1703
 
1623
- createdAt DateTime @default(now())
1704
+ createdAt DateTime @default(now())
1624
1705
 
1625
1706
  @@index([userId, createdAt])
1626
1707
  @@index([userScoreId])
@@ -1629,35 +1710,35 @@ model UserScoreEvent {
1629
1710
  }
1630
1711
 
1631
1712
  model EmailSuppression {
1632
- id String @id @default(cuid())
1633
- email String
1634
- reason SuppressionReason
1635
- source String?
1713
+ id String @id @default(cuid())
1714
+ email String
1715
+ reason SuppressionReason
1716
+ source String?
1636
1717
 
1637
- suppressedAt DateTime @default(now())
1718
+ suppressedAt DateTime @default(now())
1638
1719
 
1639
1720
  @@unique([email, reason])
1640
1721
  @@index([email])
1641
1722
  }
1642
1723
 
1643
1724
  model Referral {
1644
- id String @id @default(cuid())
1645
- referrerId String?
1646
- referredUserId String?
1647
- referredEmail String?
1648
- status ReferralStatus @default(PENDING)
1649
- referralCode String @unique
1650
-
1651
- rewardType String?
1652
- rewardedAt DateTime?
1653
- clickCount Int @default(0)
1654
- registeredAt DateTime?
1655
- convertedAt DateTime?
1656
-
1657
- createdAt DateTime @default(now())
1658
-
1659
- referrer User? @relation("ReferralsSent", fields: [referrerId], references: [id], onDelete: SetNull)
1660
- referredUser User? @relation("ReferralsReceived", fields: [referredUserId], references: [id], onDelete: SetNull)
1725
+ id String @id @default(cuid())
1726
+ referrerId String?
1727
+ referredUserId String?
1728
+ referredEmail String?
1729
+ status ReferralStatus @default(PENDING)
1730
+ referralCode String @unique
1731
+
1732
+ rewardType String?
1733
+ rewardedAt DateTime?
1734
+ clickCount Int @default(0)
1735
+ registeredAt DateTime?
1736
+ convertedAt DateTime?
1737
+
1738
+ createdAt DateTime @default(now())
1739
+
1740
+ referrer User? @relation("ReferralsSent", fields: [referrerId], references: [id], onDelete: SetNull)
1741
+ referredUser User? @relation("ReferralsReceived", fields: [referredUserId], references: [id], onDelete: SetNull)
1661
1742
 
1662
1743
  @@index([referrerId])
1663
1744
  @@index([referredUserId])
@@ -0,0 +1,102 @@
1
+ -- CreateEnum
2
+ CREATE TYPE "MeetingSlotStatus" AS ENUM ('AVAILABLE', 'HELD', 'BOOKED', 'BLOCKED', 'ARCHIVED');
3
+
4
+ -- CreateEnum
5
+ CREATE TYPE "MeetingBookingStatus" AS ENUM ('OTP_PENDING', 'PENDING_ADMIN_REVIEW', 'ACCEPTED', 'DECLINED', 'CANCELED', 'COMPLETED', 'NO_SHOW', 'EXPIRED');
6
+
7
+ -- CreateTable
8
+ CREATE TABLE "MeetingSlot" (
9
+ "id" TEXT NOT NULL,
10
+ "startsAt" TIMESTAMP(3) NOT NULL,
11
+ "durationMinutes" INTEGER NOT NULL DEFAULT 30,
12
+ "status" "MeetingSlotStatus" NOT NULL DEFAULT 'AVAILABLE',
13
+ "holdExpiresAt" TIMESTAMP(3),
14
+ "note" TEXT,
15
+ "createdByAdminEmail" TEXT,
16
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
17
+ "updatedAt" TIMESTAMP(3) NOT NULL,
18
+
19
+ CONSTRAINT "MeetingSlot_pkey" PRIMARY KEY ("id")
20
+ );
21
+
22
+ -- CreateTable
23
+ CREATE TABLE "MeetingBooking" (
24
+ "id" TEXT NOT NULL,
25
+ "slotId" TEXT NOT NULL,
26
+ "status" "MeetingBookingStatus" NOT NULL DEFAULT 'OTP_PENDING',
27
+ "name" TEXT,
28
+ "email" TEXT NOT NULL,
29
+ "phone" TEXT NOT NULL,
30
+ "visitorNote" TEXT,
31
+ "publicToken" TEXT NOT NULL,
32
+ "bulkgateId" TEXT,
33
+ "otpExpiresAt" TIMESTAMP(3),
34
+ "holdExpiresAt" TIMESTAMP(3),
35
+ "phoneVerifiedAt" TIMESTAMP(3),
36
+ "slotStartAt" TIMESTAMP(3) NOT NULL,
37
+ "slotEndAt" TIMESTAMP(3) NOT NULL,
38
+ "adminNote" TEXT,
39
+ "adminActionBy" TEXT,
40
+ "acceptedAt" TIMESTAMP(3),
41
+ "declinedAt" TIMESTAMP(3),
42
+ "canceledAt" TIMESTAMP(3),
43
+ "completedAt" TIMESTAMP(3),
44
+ "noShowAt" TIMESTAMP(3),
45
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
46
+ "updatedAt" TIMESTAMP(3) NOT NULL,
47
+
48
+ CONSTRAINT "MeetingBooking_pkey" PRIMARY KEY ("id")
49
+ );
50
+
51
+ -- CreateTable
52
+ CREATE TABLE "MeetingBookingSettings" (
53
+ "id" TEXT NOT NULL DEFAULT 'default',
54
+ "bookingEnabled" BOOLEAN NOT NULL DEFAULT true,
55
+ "timezone" TEXT NOT NULL DEFAULT 'Europe/Bratislava',
56
+ "bookingHorizonDays" INTEGER NOT NULL DEFAULT 30,
57
+ "minLeadHours" INTEGER NOT NULL DEFAULT 12,
58
+ "adminNotificationEmail" TEXT NOT NULL DEFAULT 'info@smartlex.sk',
59
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
60
+ "updatedAt" TIMESTAMP(3) NOT NULL,
61
+
62
+ CONSTRAINT "MeetingBookingSettings_pkey" PRIMARY KEY ("id")
63
+ );
64
+
65
+ -- CreateIndex
66
+ CREATE INDEX "MeetingSlot_status_startsAt_idx" ON "MeetingSlot"("status", "startsAt");
67
+
68
+ -- CreateIndex
69
+ CREATE INDEX "MeetingSlot_startsAt_idx" ON "MeetingSlot"("startsAt");
70
+
71
+ -- CreateIndex
72
+ CREATE UNIQUE INDEX IF NOT EXISTS "MeetingSlot_startsAt_duration_active_key"
73
+ ON "MeetingSlot"("startsAt", "durationMinutes")
74
+ WHERE "status" <> 'ARCHIVED';
75
+
76
+ -- CreateIndex
77
+ CREATE UNIQUE INDEX "MeetingBooking_publicToken_key" ON "MeetingBooking"("publicToken");
78
+
79
+ -- CreateIndex
80
+ CREATE UNIQUE INDEX "MeetingBooking_bulkgateId_key" ON "MeetingBooking"("bulkgateId");
81
+
82
+ -- CreateIndex
83
+ CREATE INDEX "MeetingBooking_slotId_idx" ON "MeetingBooking"("slotId");
84
+
85
+ -- CreateIndex
86
+ CREATE INDEX "MeetingBooking_status_createdAt_idx" ON "MeetingBooking"("status", "createdAt");
87
+
88
+ -- CreateIndex
89
+ CREATE INDEX "MeetingBooking_email_idx" ON "MeetingBooking"("email");
90
+
91
+ -- CreateIndex
92
+ CREATE INDEX "MeetingBooking_phone_idx" ON "MeetingBooking"("phone");
93
+
94
+ -- CreateIndex
95
+ CREATE INDEX "MeetingBooking_slotStartAt_idx" ON "MeetingBooking"("slotStartAt");
96
+
97
+ -- AddForeignKey
98
+ ALTER TABLE "MeetingBooking" ADD CONSTRAINT "MeetingBooking_slotId_fkey" FOREIGN KEY ("slotId") REFERENCES "MeetingSlot"("id") ON DELETE CASCADE ON UPDATE CASCADE;
99
+
100
+ INSERT INTO "MeetingBookingSettings" ("id", "updatedAt")
101
+ VALUES ('default', CURRENT_TIMESTAMP)
102
+ ON CONFLICT ("id") DO NOTHING;