@danielcok17/prisma-db 1.11.0 → 1.12.0

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.11.0",
3
+ "version": "1.12.0",
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
@@ -23,91 +23,96 @@ model Account {
23
23
  scope String?
24
24
  id_token String?
25
25
  session_state String?
26
+ brand String @default("smartlex") // Multi-brand: "smartlex" | "justi"
26
27
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
27
28
 
28
- @@unique([provider, providerAccountId])
29
+ @@unique([provider, providerAccountId, brand])
29
30
  }
30
31
 
31
32
  model User {
32
- id String @id @default(cuid())
33
- name String?
34
- email String? @unique
35
- emailVerified DateTime?
36
- 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?
37
39
  // Credentials authentication fields
38
- password String? // Hashed password pre credentials login
39
- createdAt DateTime @default(now())
40
- agreedToTerms Boolean @default(false)
41
- practiceArea String[]
42
- lawFirm String?
43
- 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?
44
46
  // Nové polia pre schvalovanie používateľov
45
- isApproved Boolean @default(false) // Či je používateľ schválený
46
- isRejected Boolean @default(false) // Či je používateľ zamietnutý
47
- approvedAt DateTime? // Kedy bol schválený
48
- rejectedAt DateTime? // Kedy bol zamietnutý
49
- approvedBy String? // ID admina, ktorý schválil
50
- rejectedBy String? // ID admina, ktorý zamietol
51
- 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
52
54
  // Nové polia pre tracking a žiadosť
53
- referralSource String? // Odkiaľ sa o nás dozvedel (Google, Facebook, LinkedIn, etc.)
54
- 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
55
57
  // ✨ STRIPE FIELDS (B2C - len pre individuálnych používateľov)
56
- subscriptionTier SubscriptionTier @default(FREE) // Aktuálny subscription tier (cache)
57
- messageCount Int @default(10) // ✅ OPRAVENÉ z 100 na 10
58
- messageCountResetAt DateTime? // Kedy sa má resetovať message count
59
- adminGrantExpiresAt DateTime? // Kedy admin grant expiruje
58
+ subscriptionTier SubscriptionTier @default(FREE) // Aktuálny subscription tier (cache)
59
+ messageCount Int @default(10) // ✅ OPRAVENÉ z 100 na 10
60
+ messageCountResetAt DateTime? // Kedy sa má resetovať message count
61
+ adminGrantExpiresAt DateTime? // Kedy admin grant expiruje
60
62
  // ✨ COMPANY FIELDS (pre SZČO - samostatne zárobkovo činná osoba)
61
- customerType CustomerType @default(INDIVIDUAL) // Typ zákazníka: fyzická osoba alebo SZČO
62
- companyName String? // Obchodné meno (pre SZČO)
63
- companyNumber String? // IČO (povinné pre SZČO, 8 číslic)
64
- vatNumber String? // IČ DPH (SK + 10 číslic, nepovinné)
65
- taxNumber String? // DIČ (10 číslic, nepovinné)
66
- companyStreet String? // Ulica a číslo (pre SZČO)
67
- companyCity String? // Mesto (pre SZČO)
68
- companyPostalCode String? // PSČ (pre SZČO, formát: XXX XX)
69
- 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)
70
72
  // ✨ UTM TRACKING & ATTRIBUTION FIELDS
71
73
  // First-visit attribution (celý lifecycle)
72
- firstUtmSource String? // Prvý UTM source
73
- firstUtmMedium String? // Prvý UTM medium
74
- firstUtmCampaign String? // Prvá kampaň
75
- firstUtmContent String? // Prvý content/variant
76
- firstUtmTerm String? // Prvé keywords
77
- 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
78
80
  // Registration attribution
79
- registrationUtmSource String? // UTM source pri registrácii
80
- registrationUtmMedium String? // UTM medium pri registrácii
81
- registrationUtmCampaign String? // Kampaň pri registrácii
82
- registrationUtmContent String? // Content/variant pri registrácii
83
- 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
84
86
  // Relations
85
- approvalRequest UserApprovalRequest?
86
- stripeCustomer StripeCustomer? // ✨ B2C Stripe customer
87
- ownedOrganizations Organization[] @relation("OrganizationOwner")
88
- organizationMembers OrganizationMember[]
89
- createdInvites OrganizationInvite[] @relation("InviteCreator")
90
- accounts Account[]
91
- answers Answer[]
92
- conversations Conversation[]
93
- feedbacks Feedback[]
94
- pageViews PageView[]
95
- sessions Session[]
96
- workflowLogs WorkflowLog[]
97
- verificationTokens VerificationToken[]
98
- passwordResetTokens PasswordResetToken[]
99
- canvasDocuments CanvasDocument[]
100
- canvasDocumentVersions CanvasDocumentVersion[]
87
+ approvalRequest UserApprovalRequest?
88
+ stripeCustomer StripeCustomer? // ✨ B2C Stripe customer
89
+ ownedOrganizations Organization[] @relation("OrganizationOwner")
90
+ organizationMembers OrganizationMember[]
91
+ createdInvites OrganizationInvite[] @relation("InviteCreator")
92
+ accounts Account[]
93
+ answers Answer[]
94
+ conversations Conversation[]
95
+ feedbacks Feedback[]
96
+ pageViews PageView[]
97
+ sessions Session[]
98
+ workflowLogs WorkflowLog[]
99
+ verificationTokens VerificationToken[]
100
+ passwordResetTokens PasswordResetToken[]
101
+ canvasDocuments CanvasDocument[]
102
+ canvasDocumentVersions CanvasDocumentVersion[]
101
103
  // Folder system relations
102
- ownedFolders Folder[] @relation("FolderOwner")
103
- addedFolderItems FolderItem[] @relation("FolderItemAdder")
104
- folderActivities FolderActivity[] @relation("FolderActivityUser")
105
- folderSharesReceived FolderShare[] @relation("FolderShareUser")
106
- createdFolderShares FolderShare[] @relation("FolderShareCreator")
104
+ ownedFolders Folder[] @relation("FolderOwner")
105
+ addedFolderItems FolderItem[] @relation("FolderItemAdder")
106
+ folderActivities FolderActivity[] @relation("FolderActivityUser")
107
+ folderSharesReceived FolderShare[] @relation("FolderShareUser")
108
+ createdFolderShares FolderShare[] @relation("FolderShareCreator")
107
109
  // UTM tracking relations
108
- touchPoints TouchPoint[]
109
- conversions Conversion[]
110
+ touchPoints TouchPoint[]
111
+ conversions Conversion[]
110
112
 
113
+ // Multi-brand: compound unique allows same email across brands
114
+ @@unique([email, brand])
115
+ @@index([brand])
111
116
  @@index([customerType])
112
117
  @@index([companyNumber])
113
118
  @@index([email, customerType])
@@ -141,43 +146,43 @@ model UserApprovalRequest {
141
146
 
142
147
  // Organization = Právna kancelária / Firma
143
148
  model Organization {
144
- id String @id @default(cuid())
145
- name String // "Advokátska kancelária XYZ s.r.o."
149
+ id String @id @default(cuid())
150
+ name String // "Advokátska kancelária XYZ s.r.o."
146
151
 
147
152
  // Billing & Legal Information
148
- companyNumber String? // IČO (Identifikačné číslo organizácie)
149
- vatNumber String? // IČ DPH (VAT Number)
150
- taxNumber String? // DIČ (Daňové identifikačné číslo)
151
- legalForm String? // "s.r.o.", "a.s.", "v.o.s.", "k.s.", "SZČO"
152
- billingEmail String
153
+ companyNumber String? // IČO (Identifikačné číslo organizácie)
154
+ vatNumber String? // IČ DPH (VAT Number)
155
+ taxNumber String? // DIČ (Daňové identifikačné číslo)
156
+ legalForm String? // "s.r.o.", "a.s.", "v.o.s.", "k.s.", "SZČO"
157
+ billingEmail String
153
158
 
154
159
  // Address
155
- street String?
156
- city String?
157
- postalCode String?
158
- country String @default("SK")
160
+ street String?
161
+ city String?
162
+ postalCode String?
163
+ country String @default("SK")
159
164
 
160
165
  // Subscription (B2B)
161
166
  subscriptionTier SubscriptionTier @default(FREE) // Tier organizácie (cache)
162
- messageCount Int @default(0) // Spoločný pool správ pre všetkých členov
163
- messageLimit Int @default(100) // Limit správ podľa tieru
164
- messageCountResetAt DateTime? // Kedy sa má resetovať pool
165
- adminGrantExpiresAt DateTime? // Kedy admin grant expiruje
167
+ messageCount Int @default(0) // Spoločný pool správ pre všetkých členov
168
+ messageLimit Int @default(100) // Limit správ podľa tieru
169
+ messageCountResetAt DateTime? // Kedy sa má resetovať pool
170
+ adminGrantExpiresAt DateTime? // Kedy admin grant expiruje
166
171
 
167
172
  // Settings
168
- isActive Boolean @default(true)
169
- maxMembers Int @default(5) // Max počet členov podľa tieru
173
+ isActive Boolean @default(true)
174
+ maxMembers Int @default(5) // Max počet členov podľa tieru
170
175
 
171
176
  // Relations
172
- owner User @relation("OrganizationOwner", fields: [ownerId], references: [id])
177
+ owner User @relation("OrganizationOwner", fields: [ownerId], references: [id])
173
178
  ownerId String
174
179
  members OrganizationMember[]
175
180
  invites OrganizationInvite[]
176
181
  stripeCustomer StripeCustomer?
177
182
  folderShares FolderShare[]
178
183
 
179
- createdAt DateTime @default(now())
180
- updatedAt DateTime @updatedAt
184
+ createdAt DateTime @default(now())
185
+ updatedAt DateTime @updatedAt
181
186
 
182
187
  @@index([ownerId])
183
188
  @@index([vatNumber])
@@ -188,14 +193,14 @@ model Organization {
188
193
 
189
194
  // Many-to-Many: User ↔ Organization
190
195
  model OrganizationMember {
191
- id String @id @default(cuid())
196
+ id String @id @default(cuid())
192
197
  organizationId String
193
198
  userId String
194
- role MemberRole @default(MEMBER)
195
- joinedAt DateTime @default(now())
199
+ role MemberRole @default(MEMBER)
200
+ joinedAt DateTime @default(now())
196
201
 
197
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
198
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
202
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
203
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
199
204
 
200
205
  @@unique([organizationId, userId])
201
206
  @@index([organizationId])
@@ -205,23 +210,23 @@ model OrganizationMember {
205
210
 
206
211
  // Organization Invite System
207
212
  model OrganizationInvite {
208
- id String @id @default(cuid())
213
+ id String @id @default(cuid())
209
214
  organizationId String
210
- token String @unique
211
- email String? // Optional: specific email invite
212
- role MemberRole @default(MEMBER)
215
+ token String @unique
216
+ email String? // Optional: specific email invite
217
+ role MemberRole @default(MEMBER)
213
218
  createdBy String
214
219
  expiresAt DateTime
215
- maxUses Int @default(1) // For multi-use invites
216
- currentUses Int @default(0)
217
- isActive Boolean @default(true)
218
- usedAt DateTime? // Last usage timestamp
219
- usedBy String? // Last user who used it
220
- createdAt DateTime @default(now())
221
- updatedAt DateTime @updatedAt
220
+ maxUses Int @default(1) // For multi-use invites
221
+ currentUses Int @default(0)
222
+ isActive Boolean @default(true)
223
+ usedAt DateTime? // Last usage timestamp
224
+ usedBy String? // Last user who used it
225
+ createdAt DateTime @default(now())
226
+ updatedAt DateTime @updatedAt
222
227
 
223
- organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
224
- creator User @relation("InviteCreator", fields: [createdBy], references: [id])
228
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
229
+ creator User @relation("InviteCreator", fields: [createdBy], references: [id])
225
230
 
226
231
  @@index([token])
227
232
  @@index([organizationId])
@@ -230,26 +235,26 @@ model OrganizationInvite {
230
235
  }
231
236
 
232
237
  enum MemberRole {
233
- OWNER // Zakladateľ/vlastník, plný prístup k billing a settings
234
- ADMIN // Administrátor, môže pridávať/odoberať členov
235
- MEMBER // Bežný člen, len používa systém
238
+ OWNER // Zakladateľ/vlastník, plný prístup k billing a settings
239
+ ADMIN // Administrátor, môže pridávať/odoberať členov
240
+ MEMBER // Bežný člen, len používa systém
236
241
  }
237
242
 
238
243
  // ZJEDNODUŠENÝ Conversation - len metadata, bez duplikátov
239
244
  model Conversation {
240
- id String @id @default(cuid())
245
+ id String @id @default(cuid())
241
246
  name String
242
247
  userId String
243
- isShareable Boolean @default(false)
244
- shareUrl String? @unique
248
+ isShareable Boolean @default(false)
249
+ shareUrl String? @unique
245
250
  sharedAt DateTime?
246
- createdAt DateTime @default(now())
247
- updatedAt DateTime @updatedAt
251
+ createdAt DateTime @default(now())
252
+ updatedAt DateTime @updatedAt
248
253
  summary String?
249
- messagesSinceLastSummary Int? @default(0)
254
+ messagesSinceLastSummary Int? @default(0)
250
255
  // Relácie
251
256
  answers Answer[]
252
- user User @relation(fields: [userId], references: [id])
257
+ user User @relation(fields: [userId], references: [id])
253
258
  workflowLogs WorkflowLog[]
254
259
  canvasDocuments CanvasDocument[]
255
260
 
@@ -259,29 +264,29 @@ model Conversation {
259
264
 
260
265
  // Hlavný model - všetky správy, bez duplikátov
261
266
  model Answer {
262
- id String @id @default(cuid())
263
- conversationId String
264
- messageId String @unique
265
- role Role
266
- content String
267
- question String?
268
- answer String?
269
- evaluation String?
270
- isWelcome Boolean @default(false)
271
- processingTime Int?
272
- model String?
273
- userId String?
274
- createdAt DateTime @default(now())
275
- updatedAt DateTime @updatedAt
267
+ id String @id @default(cuid())
268
+ conversationId String
269
+ messageId String @unique
270
+ role Role
271
+ content String
272
+ question String?
273
+ answer String?
274
+ evaluation String?
275
+ isWelcome Boolean @default(false)
276
+ processingTime Int?
277
+ model String?
278
+ userId String?
279
+ createdAt DateTime @default(now())
280
+ updatedAt DateTime @updatedAt
276
281
  // Relácie
277
- conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
278
- user User? @relation(fields: [userId], references: [id])
282
+ conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
283
+ user User? @relation(fields: [userId], references: [id])
279
284
  feedback Feedback?
280
285
  references Reference[]
281
286
  metrics AnswerMetrics?
282
287
  WorkflowLog WorkflowLog[]
283
288
  files MessageFile[]
284
- canvasDocumentId String? // No FK constraint - flexible document management
289
+ canvasDocumentId String? // No FK constraint - flexible document management
285
290
 
286
291
  @@index([conversationId])
287
292
  @@index([messageId])
@@ -291,13 +296,13 @@ model Answer {
291
296
  }
292
297
 
293
298
  model MessageFile {
294
- id String @id @default(cuid())
295
- answerId String
296
- fileName String
297
- fileType String
298
- base64Data String
299
- uploadedAt DateTime @default(now())
300
- answer Answer @relation(fields: [answerId], references: [id], onDelete: Cascade)
299
+ id String @id @default(cuid())
300
+ answerId String
301
+ fileName String
302
+ fileType String
303
+ base64Data String
304
+ uploadedAt DateTime @default(now())
305
+ answer Answer @relation(fields: [answerId], references: [id], onDelete: Cascade)
301
306
 
302
307
  @@index([answerId])
303
308
  @@index([fileType])
@@ -409,12 +414,12 @@ model PageView {
409
414
  }
410
415
 
411
416
  model Session {
412
- id String @id @default(cuid())
413
- sessionId String @unique
414
- userId String?
415
- startedAt DateTime @default(now())
416
- endedAt DateTime?
417
- duration Int?
417
+ id String @id @default(cuid())
418
+ sessionId String @unique
419
+ userId String?
420
+ startedAt DateTime @default(now())
421
+ endedAt DateTime?
422
+ duration Int?
418
423
 
419
424
  // ============================================
420
425
  // FIRST-TOUCH ATTRIBUTION
@@ -427,7 +432,7 @@ model Session {
427
432
  firstUtmCampaign String?
428
433
  firstUtmContent String?
429
434
  firstUtmTerm String?
430
- firstTouchAt DateTime? // Timestamp prvého UTM touchpoint
435
+ firstTouchAt DateTime? // Timestamp prvého UTM touchpoint
431
436
 
432
437
  // ============================================
433
438
  // LAST-TOUCH ATTRIBUTION
@@ -440,14 +445,14 @@ model Session {
440
445
  lastUtmCampaign String?
441
446
  lastUtmContent String?
442
447
  lastUtmTerm String?
443
- lastTouchAt DateTime? // Timestamp posledného UTM touchpoint
448
+ lastTouchAt DateTime? // Timestamp posledného UTM touchpoint
444
449
 
445
450
  // ============================================
446
451
  // RELATIONS
447
452
  // ============================================
448
453
 
449
- touchPoints TouchPoint[] // Všetky touchpointy v session
450
- conversions Conversion[] // Všetky konverzie v session
454
+ touchPoints TouchPoint[] // Všetky touchpointy v session
455
+ conversions Conversion[] // Všetky konverzie v session
451
456
 
452
457
  // Existujúce relations
453
458
  pageViews PageView[]
@@ -462,7 +467,6 @@ model Session {
462
467
  @@index([lastUtmCampaign])
463
468
  @@index([firstUtmSource, firstUtmMedium])
464
469
  @@index([lastUtmSource, lastUtmMedium])
465
-
466
470
  // Existujúce indexes
467
471
  @@index([userId])
468
472
  @@index([startedAt])
@@ -475,47 +479,47 @@ model Session {
475
479
  // TouchPoint - každý click s UTM parametrami
476
480
  // Umožňuje multi-touch attribution a customer journey analysis
477
481
  model TouchPoint {
478
- id String @id @default(cuid())
479
- userId String? // Pre prihlásených používateľov
480
- sessionId String // Session tracking (required)
482
+ id String @id @default(cuid())
483
+ userId String? // Pre prihlásených používateľov
484
+ sessionId String // Session tracking (required)
481
485
 
482
486
  // ============================================
483
487
  // UTM PARAMETERS (všetky lowercase!)
484
488
  // ============================================
485
489
  // Best practice: Vždy lowercase, validované pred uložením
486
490
 
487
- utmSource String? // Odkiaľ: "email", "facebook", "google", "linkedin"
488
- utmMedium String? // Typ média: "email", "cpc", "social", "organic", "paid-social"
489
- utmCampaign String? // Názov kampane: "smizany-2026-01", "spring-sale-2026"
490
- utmContent String? // Variant/link identifier: "cta-primary", "banner-top", "hero-button"
491
- utmTerm String? // Keywords (pre paid search): "pravny-asistent", "advokat-ai"
491
+ utmSource String? // Odkiaľ: "email", "facebook", "google", "linkedin"
492
+ utmMedium String? // Typ média: "email", "cpc", "social", "organic", "paid-social"
493
+ utmCampaign String? // Názov kampane: "smizany-2026-01", "spring-sale-2026"
494
+ utmContent String? // Variant/link identifier: "cta-primary", "banner-top", "hero-button"
495
+ utmTerm String? // Keywords (pre paid search): "pravny-asistent", "advokat-ai"
492
496
 
493
497
  // ============================================
494
498
  // CONTEXT & METADATA
495
499
  // ============================================
496
500
 
497
- page String // Ktorá stránka: "/", "/pricing", "/contact"
498
- path String // Celý path s params: "/?utm_source=email&utm_campaign=..."
499
- referrer String? // HTTP Referrer (odkiaľ prišiel)
501
+ page String // Ktorá stránka: "/", "/pricing", "/contact"
502
+ path String // Celý path s params: "/?utm_source=email&utm_campaign=..."
503
+ referrer String? // HTTP Referrer (odkiaľ prišiel)
500
504
 
501
505
  // Device & Browser info (denormalizované pre rýchle queries)
502
- deviceType String? // "mobile", "tablet", "desktop"
503
- browser String? // "Chrome", "Firefox", "Safari"
504
- os String? // "Windows", "macOS", "iOS", "Android"
506
+ deviceType String? // "mobile", "tablet", "desktop"
507
+ browser String? // "Chrome", "Firefox", "Safari"
508
+ os String? // "Windows", "macOS", "iOS", "Android"
505
509
 
506
510
  // Geolocation (anonymizované)
507
- country String? // "SK", "CZ", "US"
508
- city String? // "Bratislava", "Prague"
511
+ country String? // "SK", "CZ", "US"
512
+ city String? // "Bratislava", "Prague"
509
513
 
510
514
  // Timestamp
511
- timestamp DateTime @default(now())
515
+ timestamp DateTime @default(now())
512
516
 
513
517
  // ============================================
514
518
  // RELATIONS
515
519
  // ============================================
516
520
 
517
- session Session @relation(fields: [sessionId], references: [sessionId], onDelete: Cascade)
518
- user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
521
+ session Session @relation(fields: [sessionId], references: [sessionId], onDelete: Cascade)
522
+ user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
519
523
 
520
524
  // ============================================
521
525
  // INDEXES (optimalizované pre analytics queries)
@@ -531,38 +535,37 @@ model TouchPoint {
531
535
  @@index([timestamp])
532
536
  @@index([sessionId, timestamp])
533
537
  @@index([userId, timestamp])
534
-
535
538
  @@map("touch_points")
536
539
  }
537
540
 
538
541
  // Conversion - sledovanie konverzií s attribution
539
542
  // Podporuje first-touch, last-touch aj multi-touch attribution
540
543
  model Conversion {
541
- id String @id @default(cuid())
542
- userId String? // Kto konvertoval (nullable pre anonymous conversions)
543
- sessionId String // V ktorej session
544
+ id String @id @default(cuid())
545
+ userId String? // Kto konvertoval (nullable pre anonymous conversions)
546
+ sessionId String // V ktorej session
544
547
 
545
548
  // ============================================
546
549
  // CONVERSION METADATA
547
550
  // ============================================
548
551
 
549
- type ConversionType // Typ konverzie
550
- value Decimal? // Revenue (pre e-commerce/subscriptions)
551
- currency String? @default("EUR")
552
+ type ConversionType // Typ konverzie
553
+ value Decimal? // Revenue (pre e-commerce/subscriptions)
554
+ currency String? @default("EUR")
552
555
 
553
556
  // Optional metadata
554
- metadata Json? // Stripe subscription ID, product info, etc.
557
+ metadata Json? // Stripe subscription ID, product info, etc.
555
558
 
556
559
  // ============================================
557
560
  // FIRST-TOUCH ATTRIBUTION (40% credit)
558
561
  // ============================================
559
562
  // Prvý UTM touchpoint v session = awareness channel
560
563
 
561
- firstUtmSource String? // Odkiaľ prišiel prvýkrát
562
- firstUtmMedium String? // Akým médiom prvýkrát
563
- firstUtmCampaign String? // Ktorá kampaň priniesla awareness
564
- firstUtmContent String? // Ktorý konkrétny link/banner
565
- firstUtmTerm String? // Ktoré keywords (pre paid search)
564
+ firstUtmSource String? // Odkiaľ prišiel prvýkrát
565
+ firstUtmMedium String? // Akým médiom prvýkrát
566
+ firstUtmCampaign String? // Ktorá kampaň priniesla awareness
567
+ firstUtmContent String? // Ktorý konkrétny link/banner
568
+ firstUtmTerm String? // Ktoré keywords (pre paid search)
566
569
  firstTouchAt DateTime? // Kedy bol prvý touchpoint
567
570
 
568
571
  // ============================================
@@ -570,11 +573,11 @@ model Conversion {
570
573
  // ============================================
571
574
  // Posledný UTM touchpoint pred konverziou = conversion channel
572
575
 
573
- lastUtmSource String? // Odkiaľ prišiel naposledy
574
- lastUtmMedium String? // Akým médiom naposledy
575
- lastUtmCampaign String? // Ktorá kampaň priniesla konverziu
576
- lastUtmContent String? // Ktorý konkrétny link/banner
577
- lastUtmTerm String? // Ktoré keywords (pre paid search)
576
+ lastUtmSource String? // Odkiaľ prišiel naposledy
577
+ lastUtmMedium String? // Akým médiom naposledy
578
+ lastUtmCampaign String? // Ktorá kampaň priniesla konverziu
579
+ lastUtmContent String? // Ktorý konkrétny link/banner
580
+ lastUtmTerm String? // Ktoré keywords (pre paid search)
578
581
  lastTouchAt DateTime? // Kedy bol posledný touchpoint
579
582
 
580
583
  // ============================================
@@ -582,24 +585,24 @@ model Conversion {
582
585
  // ============================================
583
586
  // Všetky touchpointy medzi prvým a posledným
584
587
 
585
- touchPointIds String[] // Array of TouchPoint IDs (pre detailnú analýzu)
586
- touchPointCount Int? // Počet touchpoints v customer journey
588
+ touchPointIds String[] // Array of TouchPoint IDs (pre detailnú analýzu)
589
+ touchPointCount Int? // Počet touchpoints v customer journey
587
590
 
588
591
  // ============================================
589
592
  // CALCULATED FIELDS
590
593
  // ============================================
591
594
 
592
- journeyDuration Int? // Čas od prvého touchpoint po konverziu (sekundy)
595
+ journeyDuration Int? // Čas od prvého touchpoint po konverziu (sekundy)
593
596
 
594
597
  // Timestamp
595
- timestamp DateTime @default(now())
598
+ timestamp DateTime @default(now())
596
599
 
597
600
  // ============================================
598
601
  // RELATIONS
599
602
  // ============================================
600
603
 
601
- session Session @relation(fields: [sessionId], references: [sessionId], onDelete: Cascade)
602
- user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
604
+ session Session @relation(fields: [sessionId], references: [sessionId], onDelete: Cascade)
605
+ user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
603
606
 
604
607
  // ============================================
605
608
  // INDEXES
@@ -609,25 +612,21 @@ model Conversion {
609
612
  @@index([sessionId])
610
613
  @@index([type])
611
614
  @@index([timestamp])
612
-
613
615
  // First-touch attribution indexes
614
616
  @@index([firstUtmSource])
615
617
  @@index([firstUtmMedium])
616
618
  @@index([firstUtmCampaign])
617
619
  @@index([firstUtmCampaign, type])
618
620
  @@index([firstUtmSource, firstUtmMedium])
619
-
620
621
  // Last-touch attribution indexes
621
622
  @@index([lastUtmSource])
622
623
  @@index([lastUtmMedium])
623
624
  @@index([lastUtmCampaign])
624
625
  @@index([lastUtmCampaign, type])
625
626
  @@index([lastUtmSource, lastUtmMedium])
626
-
627
627
  // Analytics indexes
628
628
  @@index([type, timestamp])
629
629
  @@index([value])
630
-
631
630
  @@map("conversions")
632
631
  }
633
632
 
@@ -637,28 +636,28 @@ model Conversion {
637
636
 
638
637
  // Stripe Customer - polymorphic relation (User OR Organization)
639
638
  model StripeCustomer {
640
- id String @id @default(cuid())
639
+ id String @id @default(cuid())
641
640
 
642
641
  // ✅ Polymorphic relation - buď User (B2C) alebo Organization (B2B)
643
- userId String? @unique // B2C: Individuálny používateľ
644
- organizationId String? @unique // B2B: Organizácia
642
+ userId String? @unique // B2C: Individuálny používateľ
643
+ organizationId String? @unique // B2B: Organizácia
645
644
 
646
- stripeCustomerId String @unique
647
- email String
648
- name String?
645
+ stripeCustomerId String @unique
646
+ email String
647
+ name String?
649
648
 
650
649
  // Billing details (Stripe Address & Tax IDs)
651
- billingAddress Json? // Stripe Address object
652
- taxIds Json? // Stripe Tax IDs array (VAT, etc.)
650
+ billingAddress Json? // Stripe Address object
651
+ taxIds Json? // Stripe Tax IDs array (VAT, etc.)
653
652
 
654
- createdAt DateTime @default(now())
655
- updatedAt DateTime @updatedAt
653
+ createdAt DateTime @default(now())
654
+ updatedAt DateTime @updatedAt
656
655
 
657
656
  // Relations
658
- user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
659
- organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
660
- subscriptions StripeSubscription[]
661
- payments StripePayment[]
657
+ user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
658
+ organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
659
+ subscriptions StripeSubscription[]
660
+ payments StripePayment[]
662
661
 
663
662
  @@index([stripeCustomerId])
664
663
  @@index([userId])
@@ -668,37 +667,37 @@ model StripeCustomer {
668
667
 
669
668
  // Stripe Subscription - sledovanie predplatného (User alebo Organization)
670
669
  model StripeSubscription {
671
- id String @id @default(cuid())
670
+ id String @id @default(cuid())
672
671
 
673
672
  // ✅ FIX: customerId = FK na StripeCustomer.id (nie stripeCustomerId!)
674
- customerId String // FK na StripeCustomer.id
675
- stripeCustomerId String // Stripe ID (pre logging/redundancia)
676
- stripeSubscriptionId String @unique
673
+ customerId String // FK na StripeCustomer.id
674
+ stripeCustomerId String // Stripe ID (pre logging/redundancia)
675
+ stripeSubscriptionId String @unique
677
676
  stripePriceId String
678
677
  stripeProductId String
679
678
 
680
- status SubscriptionStatus
681
- tier SubscriptionTier @default(FREE)
682
- billingInterval BillingInterval @default(MONTHLY) // Monthly or Yearly billing
679
+ status SubscriptionStatus
680
+ tier SubscriptionTier @default(FREE)
681
+ billingInterval BillingInterval @default(MONTHLY) // Monthly or Yearly billing
683
682
 
684
- currentPeriodStart DateTime
685
- currentPeriodEnd DateTime
686
- cancelAtPeriodEnd Boolean @default(false)
687
- canceledAt DateTime?
683
+ currentPeriodStart DateTime
684
+ currentPeriodEnd DateTime
685
+ cancelAtPeriodEnd Boolean @default(false)
686
+ canceledAt DateTime?
688
687
 
689
- trialStart DateTime?
690
- trialEnd DateTime?
688
+ trialStart DateTime?
689
+ trialEnd DateTime?
691
690
 
692
691
  // Additional fields
693
- quantity Int @default(1) // Počet seats (pre LAW_FIRM/ENTERPRISE tier)
694
- defaultPaymentMethodId String? // Stripe payment method ID
692
+ quantity Int @default(1) // Počet seats (pre LAW_FIRM/ENTERPRISE tier)
693
+ defaultPaymentMethodId String? // Stripe payment method ID
695
694
 
696
- metadata Json? // Dodatočné Stripe metadata
697
- createdAt DateTime @default(now())
698
- updatedAt DateTime @updatedAt
695
+ metadata Json? // Dodatočné Stripe metadata
696
+ createdAt DateTime @default(now())
697
+ updatedAt DateTime @updatedAt
699
698
 
700
699
  // ✅ FIX: Relácia na customerId (interné ID), nie stripeCustomerId (Stripe ID)
701
- customer StripeCustomer @relation(fields: [customerId], references: [id], onDelete: Cascade)
700
+ customer StripeCustomer @relation(fields: [customerId], references: [id], onDelete: Cascade)
702
701
 
703
702
  @@index([stripeSubscriptionId])
704
703
  @@index([customerId])
@@ -711,14 +710,14 @@ model StripeSubscription {
711
710
 
712
711
  // Stripe Event - prevencia duplicitného spracovania webhookov (idempotencia)
713
712
  model StripeEvent {
714
- id String @id @default(cuid())
715
- eventId String @unique // Stripe event ID
716
- type String // Typ eventu (napr. 'checkout.session.completed')
717
- data Json // Úplné event data pre debugging
718
- processed Boolean @default(false)
713
+ id String @id @default(cuid())
714
+ eventId String @unique // Stripe event ID
715
+ type String // Typ eventu (napr. 'checkout.session.completed')
716
+ data Json // Úplné event data pre debugging
717
+ processed Boolean @default(false)
719
718
  processedAt DateTime?
720
- error String? // Uloženie chýb pri spracovaní
721
- createdAt DateTime @default(now())
719
+ error String? // Uloženie chýb pri spracovaní
720
+ createdAt DateTime @default(now())
722
721
 
723
722
  @@index([eventId])
724
723
  @@index([processed])
@@ -728,28 +727,28 @@ model StripeEvent {
728
727
 
729
728
  // Stripe Payment - sledovanie jednotlivých platieb (voliteľné, pre detailnú analytiku)
730
729
  model StripePayment {
731
- id String @id @default(cuid())
730
+ id String @id @default(cuid())
732
731
 
733
732
  // ✅ FIX: Pridaná relácia na StripeCustomer
734
- customerId String
735
- stripePaymentId String @unique
736
- stripeCustomerId String // Redundantné, ale OK pre logging
733
+ customerId String
734
+ stripePaymentId String @unique
735
+ stripeCustomerId String // Redundantné, ale OK pre logging
737
736
 
738
- amount Int // Suma v centoch
739
- currency String @default("eur")
740
- status String // succeeded, failed, pending
741
- paymentMethod String? // card, sepa_debit, atď.
742
- description String?
737
+ amount Int // Suma v centoch
738
+ currency String @default("eur")
739
+ status String // succeeded, failed, pending
740
+ paymentMethod String? // card, sepa_debit, atď.
741
+ description String?
743
742
 
744
743
  // Invoice info
745
- invoiceId String? // Stripe Invoice ID
746
- invoiceUrl String? // URL na faktúru
744
+ invoiceId String? // Stripe Invoice ID
745
+ invoiceUrl String? // URL na faktúru
747
746
 
748
- metadata Json?
749
- createdAt DateTime @default(now())
747
+ metadata Json?
748
+ createdAt DateTime @default(now())
750
749
 
751
750
  // ✅ Relácia na StripeCustomer
752
- customer StripeCustomer @relation(fields: [customerId], references: [id], onDelete: Cascade)
751
+ customer StripeCustomer @relation(fields: [customerId], references: [id], onDelete: Cascade)
753
752
 
754
753
  @@index([stripePaymentId])
755
754
  @@index([customerId])
@@ -790,35 +789,35 @@ enum ApprovalStatus {
790
789
 
791
790
  // Stripe: Status predplatného
792
791
  enum SubscriptionStatus {
793
- ACTIVE // Predplatné je aktívne
794
- CANCELED // Predplatné zrušené
795
- INCOMPLETE // Iniciálna platba zlyhala
792
+ ACTIVE // Predplatné je aktívne
793
+ CANCELED // Predplatné zrušené
794
+ INCOMPLETE // Iniciálna platba zlyhala
796
795
  INCOMPLETE_EXPIRED // Neúplné predplatné expirované
797
- PAST_DUE // Platba zlyhala, retry prebieha
798
- TRIALING // V skúšobnom období
799
- UNPAID // Platba zlyhala, žiadny retry
800
- PAUSED // Predplatné pozastavené (Stripe feature)
796
+ PAST_DUE // Platba zlyhala, retry prebieha
797
+ TRIALING // V skúšobnom období
798
+ UNPAID // Platba zlyhala, žiadny retry
799
+ PAUSED // Predplatné pozastavené (Stripe feature)
801
800
  }
802
801
 
803
802
  // Customer type: Individuálny vs SZČO
804
803
  enum CustomerType {
805
- INDIVIDUAL // Fyzická osoba (bez IČO)
806
- SELF_EMPLOYED // SZČO - Samostatne zárobkovo činná osoba (s IČO)
804
+ INDIVIDUAL // Fyzická osoba (bez IČO)
805
+ SELF_EMPLOYED // SZČO - Samostatne zárobkovo činná osoba (s IČO)
807
806
  }
808
807
 
809
808
  // Stripe: Tier predplatného
810
809
  enum SubscriptionTier {
811
- FREE // Free tier (10 messages/month)
812
- LAWYER // Lawyer tier (1000 messages/month, €29/month, 1 user)
813
- LAWYER_PRO // Lawyer Pro tier (3000 messages/month, €49/month, 1 user) - RECOMMENDED
814
- LAW_FIRM // Law Firm tier (10000 messages/month, €129/month, up to 5 users)
815
- ENTERPRISE // Enterprise tier (unlimited messages, unlimited users, custom pricing)
810
+ FREE // Free tier (10 messages/month)
811
+ LAWYER // Lawyer tier (1000 messages/month, €29/month, 1 user)
812
+ LAWYER_PRO // Lawyer Pro tier (3000 messages/month, €49/month, 1 user) - RECOMMENDED
813
+ LAW_FIRM // Law Firm tier (10000 messages/month, €129/month, up to 5 users)
814
+ ENTERPRISE // Enterprise tier (unlimited messages, unlimited users, custom pricing)
816
815
  }
817
816
 
818
817
  // Stripe: Billing interval
819
818
  enum BillingInterval {
820
- MONTHLY // Monthly billing
821
- YEARLY // Yearly billing (17% discount)
819
+ MONTHLY // Monthly billing
820
+ YEARLY // Yearly billing (17% discount)
822
821
  }
823
822
 
824
823
  // Canvas Document Status
@@ -830,16 +829,16 @@ enum DocumentStatus {
830
829
 
831
830
  // Conversion types for UTM attribution tracking
832
831
  enum ConversionType {
833
- REGISTRATION // Nová registrácia
834
- SUBSCRIPTION // Začiatok predplatného (FREE → PAID)
835
- UPGRADE // Upgrade tieru (LAWYER → LAWYER_PRO)
836
- RENEWAL // Obnovenie predplatného
837
- TRIAL_START // Začiatok trial periodu
838
- PURCHASE // Jednorazový nákup
839
- LEAD // Vyplnenie kontaktného formulára
840
- DEMO_REQUEST // Žiadosť o demo
841
- DOWNLOAD // Stiahnutie resourceu
842
- FORM_SUBMIT // Iné formuláre
832
+ REGISTRATION // Nová registrácia
833
+ SUBSCRIPTION // Začiatok predplatného (FREE → PAID)
834
+ UPGRADE // Upgrade tieru (LAWYER → LAWYER_PRO)
835
+ RENEWAL // Obnovenie predplatného
836
+ TRIAL_START // Začiatok trial periodu
837
+ PURCHASE // Jednorazový nákup
838
+ LEAD // Vyplnenie kontaktného formulára
839
+ DEMO_REQUEST // Žiadosť o demo
840
+ DOWNLOAD // Stiahnutie resourceu
841
+ FORM_SUBMIT // Iné formuláre
843
842
  }
844
843
 
845
844
  // ============================================
@@ -966,12 +965,12 @@ enum StepType {
966
965
 
967
966
  // Email verification tokens
968
967
  model VerificationToken {
969
- id String @id @default(cuid())
970
- userId String
971
- token String @unique
972
- expires DateTime
973
- createdAt DateTime @default(now())
974
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
968
+ id String @id @default(cuid())
969
+ userId String
970
+ token String @unique
971
+ expires DateTime
972
+ createdAt DateTime @default(now())
973
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
975
974
 
976
975
  @@index([token])
977
976
  @@index([userId])
@@ -980,12 +979,12 @@ model VerificationToken {
980
979
 
981
980
  // Password reset tokens
982
981
  model PasswordResetToken {
983
- id String @id @default(cuid())
984
- userId String
985
- token String @unique
986
- expires DateTime
987
- createdAt DateTime @default(now())
988
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
982
+ id String @id @default(cuid())
983
+ userId String
984
+ token String @unique
985
+ expires DateTime
986
+ createdAt DateTime @default(now())
987
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
989
988
 
990
989
  @@index([token])
991
990
  @@index([userId])
@@ -997,21 +996,21 @@ model PasswordResetToken {
997
996
  // ============================================
998
997
 
999
998
  model CanvasDocument {
1000
- id String @id @default(cuid())
999
+ id String @id @default(cuid())
1001
1000
  userId String
1002
1001
  title String
1003
- status DocumentStatus @default(DRAFT)
1004
- createdAt DateTime @default(now())
1005
- updatedAt DateTime @updatedAt
1002
+ status DocumentStatus @default(DRAFT)
1003
+ createdAt DateTime @default(now())
1004
+ updatedAt DateTime @updatedAt
1006
1005
  originConversationId String?
1007
- originAnswerId String? // No FK constraint - async save reference
1008
- currentVersionId String? @unique
1006
+ originAnswerId String? // No FK constraint - async save reference
1007
+ currentVersionId String? @unique
1009
1008
 
1010
1009
  // Relations
1011
- user User @relation(fields: [userId], references: [id], onDelete: Restrict)
1012
- originConversation Conversation? @relation(fields: [originConversationId], references: [id], onDelete: SetNull)
1013
- currentVersion CanvasDocumentVersion? @relation("CurrentVersion", fields: [currentVersionId], references: [id], onDelete: SetNull)
1014
- versions CanvasDocumentVersion[] @relation("DocumentVersions")
1010
+ user User @relation(fields: [userId], references: [id], onDelete: Restrict)
1011
+ originConversation Conversation? @relation(fields: [originConversationId], references: [id], onDelete: SetNull)
1012
+ currentVersion CanvasDocumentVersion? @relation("CurrentVersion", fields: [currentVersionId], references: [id], onDelete: SetNull)
1013
+ versions CanvasDocumentVersion[] @relation("DocumentVersions")
1015
1014
 
1016
1015
  @@index([userId])
1017
1016
  @@index([originConversationId])
@@ -1020,12 +1019,12 @@ model CanvasDocument {
1020
1019
  }
1021
1020
 
1022
1021
  model CanvasDocumentVersion {
1023
- id String @id @default(cuid())
1022
+ id String @id @default(cuid())
1024
1023
  documentId String
1025
1024
  versionNumber Int
1026
1025
  title String
1027
1026
  markdownContent String
1028
- createdAt DateTime @default(now())
1027
+ createdAt DateTime @default(now())
1029
1028
  createdBy String
1030
1029
  regenerationPrompt String?
1031
1030
  parentVersionId String?
@@ -1050,34 +1049,34 @@ model CanvasDocumentVersion {
1050
1049
  // Main folder entity with hierarchy support via parentId
1051
1050
  // Uses materialized path pattern for efficient hierarchy queries
1052
1051
  model Folder {
1053
- id String @id @default(cuid())
1052
+ id String @id @default(cuid())
1054
1053
  name String
1055
1054
  description String?
1056
- color String? @default("#6366f1")
1057
- icon String? @default("folder")
1055
+ color String? @default("#6366f1")
1056
+ icon String? @default("folder")
1058
1057
 
1059
1058
  // Ownership (always user-owned)
1060
- ownerId String
1059
+ ownerId String
1061
1060
 
1062
1061
  // Hierarchy
1063
1062
  parentId String?
1064
- rootFolderId String? // NULL for root folders, points to top-level ancestor
1065
- path String @default("/") // Materialized path: "/parentId/grandparentId/..."
1066
- depth Int @default(0)
1063
+ rootFolderId String? // NULL for root folders, points to top-level ancestor
1064
+ path String @default("/") // Materialized path: "/parentId/grandparentId/..."
1065
+ depth Int @default(0)
1067
1066
 
1068
1067
  // Metadata
1069
- sortOrder Int @default(0)
1070
- isArchived Boolean @default(false)
1071
- createdAt DateTime @default(now())
1072
- updatedAt DateTime @updatedAt
1068
+ sortOrder Int @default(0)
1069
+ isArchived Boolean @default(false)
1070
+ createdAt DateTime @default(now())
1071
+ updatedAt DateTime @updatedAt
1073
1072
 
1074
1073
  // Relations
1075
- owner User @relation("FolderOwner", fields: [ownerId], references: [id], onDelete: Cascade)
1076
- parent Folder? @relation("FolderHierarchy", fields: [parentId], references: [id], onDelete: Cascade)
1077
- children Folder[] @relation("FolderHierarchy")
1078
- items FolderItem[]
1079
- activities FolderActivity[]
1080
- shares FolderShare[]
1074
+ owner User @relation("FolderOwner", fields: [ownerId], references: [id], onDelete: Cascade)
1075
+ parent Folder? @relation("FolderHierarchy", fields: [parentId], references: [id], onDelete: Cascade)
1076
+ children Folder[] @relation("FolderHierarchy")
1077
+ items FolderItem[]
1078
+ activities FolderActivity[]
1079
+ shares FolderShare[]
1081
1080
 
1082
1081
  @@index([ownerId])
1083
1082
  @@index([parentId])
@@ -1090,12 +1089,12 @@ model Folder {
1090
1089
  // Links entities (conversations, documents, etc.) to folders
1091
1090
  // Polymorphic: entityType + entityId point to any supported entity
1092
1091
  model FolderItem {
1093
- id String @id @default(cuid())
1094
- folderId String
1092
+ id String @id @default(cuid())
1093
+ folderId String
1095
1094
 
1096
1095
  // Polymorphic reference
1097
- entityType FolderItemType
1098
- entityId String
1096
+ entityType FolderItemType
1097
+ entityId String
1099
1098
 
1100
1099
  // Optional metadata override
1101
1100
  displayName String?
@@ -1105,14 +1104,14 @@ model FolderItem {
1105
1104
  rootFolderId String?
1106
1105
 
1107
1106
  // Tracking
1108
- addedById String
1109
- sortOrder Int @default(0)
1110
- createdAt DateTime @default(now())
1111
- updatedAt DateTime @updatedAt
1107
+ addedById String
1108
+ sortOrder Int @default(0)
1109
+ createdAt DateTime @default(now())
1110
+ updatedAt DateTime @updatedAt
1112
1111
 
1113
1112
  // Relations
1114
- folder Folder @relation(fields: [folderId], references: [id], onDelete: Cascade)
1115
- addedBy User @relation("FolderItemAdder", fields: [addedById], references: [id], onDelete: Restrict)
1113
+ folder Folder @relation(fields: [folderId], references: [id], onDelete: Cascade)
1114
+ addedBy User @relation("FolderItemAdder", fields: [addedById], references: [id], onDelete: Restrict)
1116
1115
 
1117
1116
  @@unique([folderId, entityType, entityId])
1118
1117
  @@index([folderId])
@@ -1124,25 +1123,25 @@ model FolderItem {
1124
1123
  // Timeline entries for folders (system events + user messages)
1125
1124
  // Opening ANY folder shows ALL activities from the entire folder tree
1126
1125
  model FolderActivity {
1127
- id String @id @default(cuid())
1128
- folderId String
1126
+ id String @id @default(cuid())
1127
+ folderId String
1129
1128
 
1130
1129
  // Denormalized for cross-folder timeline queries
1131
- rootFolderId String?
1130
+ rootFolderId String?
1132
1131
 
1133
1132
  // Activity details
1134
1133
  activityType FolderActivityType
1135
1134
  userId String
1136
- content String? // For USER_MESSAGE, USER_NOTE types
1137
- metadata Json? // For system event details
1138
- relatedItemId String? // Optional reference to FolderItem
1135
+ content String? // For USER_MESSAGE, USER_NOTE types
1136
+ metadata Json? // For system event details
1137
+ relatedItemId String? // Optional reference to FolderItem
1139
1138
 
1140
1139
  // Timestamp
1141
- createdAt DateTime @default(now())
1140
+ createdAt DateTime @default(now())
1142
1141
 
1143
1142
  // Relations
1144
- folder Folder @relation(fields: [folderId], references: [id], onDelete: Cascade)
1145
- user User @relation("FolderActivityUser", fields: [userId], references: [id], onDelete: Restrict)
1143
+ folder Folder @relation(fields: [folderId], references: [id], onDelete: Cascade)
1144
+ user User @relation("FolderActivityUser", fields: [userId], references: [id], onDelete: Restrict)
1146
1145
 
1147
1146
  @@index([folderId])
1148
1147
  @@index([rootFolderId])
@@ -1155,26 +1154,26 @@ model FolderActivity {
1155
1154
  // Sharing permissions for folders
1156
1155
  // Can share with individual user OR entire organization (not both)
1157
1156
  model FolderShare {
1158
- id String @id @default(cuid())
1159
- folderId String
1157
+ id String @id @default(cuid())
1158
+ folderId String
1160
1159
 
1161
1160
  // Share target (either user OR organization, enforced by application logic)
1162
1161
  userId String?
1163
1162
  organizationId String?
1164
1163
 
1165
1164
  // Permission level
1166
- permission FolderPermission @default(VIEW)
1165
+ permission FolderPermission @default(VIEW)
1167
1166
 
1168
1167
  // Sharing metadata
1169
- sharedById String
1170
- sharedAt DateTime @default(now())
1171
- expiresAt DateTime?
1168
+ sharedById String
1169
+ sharedAt DateTime @default(now())
1170
+ expiresAt DateTime?
1172
1171
 
1173
1172
  // Relations
1174
- folder Folder @relation(fields: [folderId], references: [id], onDelete: Cascade)
1175
- user User? @relation("FolderShareUser", fields: [userId], references: [id], onDelete: Cascade)
1176
- organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1177
- sharedBy User @relation("FolderShareCreator", fields: [sharedById], references: [id], onDelete: Restrict)
1173
+ folder Folder @relation(fields: [folderId], references: [id], onDelete: Cascade)
1174
+ user User? @relation("FolderShareUser", fields: [userId], references: [id], onDelete: Cascade)
1175
+ organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
1176
+ sharedBy User @relation("FolderShareCreator", fields: [sharedById], references: [id], onDelete: Restrict)
1178
1177
 
1179
1178
  // Partial unique indexes for nullable columns
1180
1179
  @@unique([folderId, userId])
@@ -0,0 +1,23 @@
1
+ -- Multi-Brand Support: Allow same email to exist across different brands (smartlex, justi)
2
+ -- Existing data gets brand = 'smartlex' via DEFAULT value
3
+
4
+ -- DropIndex
5
+ DROP INDEX "Account_provider_providerAccountId_key";
6
+
7
+ -- DropIndex
8
+ DROP INDEX "User_email_key";
9
+
10
+ -- AlterTable: Add brand column to Account with default 'smartlex'
11
+ ALTER TABLE "Account" ADD COLUMN "brand" TEXT NOT NULL DEFAULT 'smartlex';
12
+
13
+ -- AlterTable: Add brand column to User with default 'smartlex'
14
+ ALTER TABLE "User" ADD COLUMN "brand" TEXT NOT NULL DEFAULT 'smartlex';
15
+
16
+ -- CreateIndex: Compound unique on Account (provider + providerAccountId + brand)
17
+ CREATE UNIQUE INDEX "Account_provider_providerAccountId_brand_key" ON "Account"("provider", "providerAccountId", "brand");
18
+
19
+ -- CreateIndex: Index on User.brand for fast filtering
20
+ CREATE INDEX "User_brand_idx" ON "User"("brand");
21
+
22
+ -- CreateIndex: Compound unique on User (email + brand) - allows same email in different brands
23
+ CREATE UNIQUE INDEX "User_email_brand_key" ON "User"("email", "brand");