-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschema.prisma
More file actions
419 lines (349 loc) · 9.69 KB
/
Copy pathschema.prisma
File metadata and controls
419 lines (349 loc) · 9.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
datasource db {
provider = "postgresql"
}
generator client {
provider = "prisma-client"
output = "./generated/client"
moduleFormat = "cjs"
}
// User
enum Role {
USER
SUPER_ADMIN
}
enum Plan {
FREE
DOCTOR
ORGANIZATION
}
model User {
id String @id @default(uuid())
username String @unique
email String @unique
password String?
googleId String? @unique
profile_image_url String?
plan Plan @default(FREE)
role Role @default(USER)
is_active Boolean @default(true)
total_scans Int @default(0)
total_reports Int @default(0)
twoFactorSecret String?
twoFactorEnabled Boolean @default(false)
reset_password_token String?
reset_token_expires DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
patients Patient[]
scans Scan[]
notifications Notifications[]
emailNotification EmailNotification?
inAppNotification InAppNotification?
sessions Session[]
ownedOrg Organization? @relation("OrgOwner")
orgMember OrgMember? @relation("OrgMember")
subscription Subscription?
payments Payment[]
auditLogs AuditLog[]
submittedTickets Ticket[] @relation("TicketSubmittedBy")
assignedTickets Ticket[] @relation("TicketAssignedTo")
}
// HOSPITAL
model Organization {
id String @id @default(uuid())
name String
ownerId String @unique
owner User @relation("OrgOwner", fields: [ownerId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
members OrgMember[]
apiKeys ApiKey[]
patients Patient[]
scans Scan[]
auditLogs AuditLog[]
}
model OrgMember {
id String @id @default(uuid())
orgId String
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
userId String @unique
user User @relation("OrgMember", fields: [userId], references: [id], onDelete: Cascade)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// Patient
enum Gender {
Male
Female
}
model Patient {
id String @id @default(uuid())
cin String
full_name String
date_of_birth String
gender Gender
email String
phone_number String
createdById String?
created_by User? @relation(fields: [createdById], references: [id], onDelete: Cascade)
orgId String?
organization Organization? @relation(fields: [orgId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
scans Scan[]
}
// Scan
enum Class {
meningioma
glioma
pituitary
notumor
}
enum Status {
PROCESSING
DONE
FAILED
}
model Scan {
id String @id @default(uuid())
scan_code String @unique
name String?
notes String?
class Class
confidence_score Float
all_scores Json
status Status @default(PROCESSING)
processing Float
uploadedById String
uploaded_by User @relation(fields: [uploadedById], references: [id], onDelete: Cascade)
patientId String?
patient Patient? @relation(fields: [patientId], references: [id], onDelete: Cascade)
orgId String?
organization Organization? @relation(fields: [orgId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
scanImage ScanImage?
report Report?
ticketsForScan Ticket[] @relation("TicketScan")
ticketsAsReanalysis Ticket[] @relation("TicketReanalysisScan")
}
model ScanImage {
id String @id @default(uuid())
scanId String @unique
scan Scan @relation(fields: [scanId], references: [id], onDelete: Cascade)
url String
size Int
resolution String
format String
name String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// Report
model Report {
id String @id @default(uuid())
content Json
scanId String @unique
scan Scan @relation(fields: [scanId], references: [id], onDelete: Cascade)
code String @unique
is_shared Boolean @default(false)
downloads Int @default(0)
share_token String? @unique
processing Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ticketsForReport Ticket[] @relation("TicketReport")
ticketsAsReanalysis Ticket[] @relation("TicketReanalysisReport")
}
// Notification
enum NotificationType {
scan
report
team
alert
info
}
model Notifications {
id String @id @default(uuid())
userId String
title String
message String
path String?
type NotificationType
read Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model EmailNotification {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
scanReady Boolean @default(true)
reportReady Boolean @default(true)
productUpdates Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model InAppNotification {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
scanReady Boolean @default(true)
reportReady Boolean @default(true)
productUpdates Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// Integration
model ApiKey {
id String @id @default(uuid())
organizationId String
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
name String
key String @unique
lastUsedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// Session
model Session {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
refreshToken String @unique
deviceInfo String?
ipAddress String?
lastUsedAt DateTime @default(now())
expiresAt DateTime
isRevoked Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// Stripe
enum SubscriptionStatus {
active
past_due
canceled
unpaid
}
model Subscription {
id String @id @default(uuid())
userId String @unique
stripeCustomerId String
stripeSubscriptionId String
status SubscriptionStatus
currentPeriodEnd DateTime
cancelAtPeriodEnd Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
enum PaymentStatus {
succeeded
failed
}
enum PaymentMode {
subscription
renewal
}
model Payment {
id String @id @default(uuid())
userId String
amount Int
status PaymentStatus
stripePaymentId String
plan Plan
mode PaymentMode
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
// Tickets
enum TicketType {
RE_ANALYSIS
RE_REPORT
}
enum TicketStatus {
OPEN
IN_PROGRESS
RESOLVED
DISMISSED
}
enum TicketPriority {
LOW
MEDIUM
HIGH
}
model Ticket {
id String @id @default(uuid())
code String @unique
type TicketType
status TicketStatus @default(OPEN)
priority TicketPriority @default(MEDIUM)
reason String
scanId String?
scan Scan? @relation("TicketScan", fields: [scanId], references: [id], onDelete: SetNull)
reportId String?
report Report? @relation("TicketReport", fields: [reportId], references: [id], onDelete: SetNull)
submittedById String
submittedBy User @relation("TicketSubmittedBy", fields: [submittedById], references: [id], onDelete: Cascade)
assignedToId String?
assignedTo User? @relation("TicketAssignedTo", fields: [assignedToId], references: [id], onDelete: SetNull)
resolutionNote String?
reanalysisScanId String?
reanalysisScan Scan? @relation("TicketReanalysisScan", fields: [reanalysisScanId], references: [id], onDelete: SetNull)
reanalysisReportId String?
reanalysisReport Report? @relation("TicketReanalysisReport", fields: [reanalysisReportId], references: [id], onDelete: SetNull)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
resolvedAt DateTime?
@@index([status])
@@index([type])
@@index([submittedById])
@@index([createdAt])
}
// Audit Logs
enum AuditCategory {
scans
patients
members
api
reports
}
enum AuditSeverity {
info
success
warning
danger
}
enum AuditStatus {
success
failed
}
model AuditLog {
id String @id @default(uuid())
orgId String?
organization Organization? @relation(fields: [orgId], references: [id], onDelete: Cascade)
actorId String?
actor User? @relation(fields: [actorId], references: [id], onDelete: SetNull)
actorName String
actorEmail String
action String
category AuditCategory
status AuditStatus @default(success)
severity AuditSeverity @default(info)
target String
targetId String?
ip String?
userAgent String?
createdAt DateTime @default(now())
@@index([orgId, createdAt])
@@index([orgId, category])
@@index([orgId, status])
@@index([orgId, actorEmail])
}