@actuate-media/cms-core 0.20.0 → 0.22.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.
Files changed (150) hide show
  1. package/LICENSE +21 -21
  2. package/dist/__tests__/actions/document-crud.test.js +74 -2
  3. package/dist/__tests__/actions/document-crud.test.js.map +1 -1
  4. package/dist/__tests__/api/cache-headers.test.d.ts +2 -0
  5. package/dist/__tests__/api/cache-headers.test.d.ts.map +1 -0
  6. package/dist/__tests__/api/cache-headers.test.js +135 -0
  7. package/dist/__tests__/api/cache-headers.test.js.map +1 -0
  8. package/dist/__tests__/api/comments-routes.test.d.ts +2 -0
  9. package/dist/__tests__/api/comments-routes.test.d.ts.map +1 -0
  10. package/dist/__tests__/api/comments-routes.test.js +266 -0
  11. package/dist/__tests__/api/comments-routes.test.js.map +1 -0
  12. package/dist/__tests__/api/notifications-routes.test.d.ts +2 -0
  13. package/dist/__tests__/api/notifications-routes.test.d.ts.map +1 -0
  14. package/dist/__tests__/api/notifications-routes.test.js +225 -0
  15. package/dist/__tests__/api/notifications-routes.test.js.map +1 -0
  16. package/dist/__tests__/api/preview-and-scheduling.test.js +53 -0
  17. package/dist/__tests__/api/preview-and-scheduling.test.js.map +1 -1
  18. package/dist/__tests__/fields/component-block.test.d.ts +2 -0
  19. package/dist/__tests__/fields/component-block.test.d.ts.map +1 -0
  20. package/dist/__tests__/fields/component-block.test.js +129 -0
  21. package/dist/__tests__/fields/component-block.test.js.map +1 -0
  22. package/dist/__tests__/fields/relations.test.js +62 -8
  23. package/dist/__tests__/fields/relations.test.js.map +1 -1
  24. package/dist/__tests__/preview-event-bus.test.d.ts +2 -0
  25. package/dist/__tests__/preview-event-bus.test.d.ts.map +1 -0
  26. package/dist/__tests__/preview-event-bus.test.js +89 -0
  27. package/dist/__tests__/preview-event-bus.test.js.map +1 -0
  28. package/dist/__tests__/preview-sse-stream.test.d.ts +2 -0
  29. package/dist/__tests__/preview-sse-stream.test.d.ts.map +1 -0
  30. package/dist/__tests__/preview-sse-stream.test.js +117 -0
  31. package/dist/__tests__/preview-sse-stream.test.js.map +1 -0
  32. package/dist/__tests__/realtime/comments.test.d.ts +2 -0
  33. package/dist/__tests__/realtime/comments.test.d.ts.map +1 -0
  34. package/dist/__tests__/realtime/comments.test.js +508 -0
  35. package/dist/__tests__/realtime/comments.test.js.map +1 -0
  36. package/dist/__tests__/realtime/gateway-ws-integration.test.d.ts +2 -0
  37. package/dist/__tests__/realtime/gateway-ws-integration.test.d.ts.map +1 -0
  38. package/dist/__tests__/realtime/gateway-ws-integration.test.js +170 -0
  39. package/dist/__tests__/realtime/gateway-ws-integration.test.js.map +1 -0
  40. package/dist/__tests__/realtime/gateway.test.d.ts +2 -0
  41. package/dist/__tests__/realtime/gateway.test.d.ts.map +1 -0
  42. package/dist/__tests__/realtime/gateway.test.js +402 -0
  43. package/dist/__tests__/realtime/gateway.test.js.map +1 -0
  44. package/dist/__tests__/realtime/notifications.test.d.ts +2 -0
  45. package/dist/__tests__/realtime/notifications.test.d.ts.map +1 -0
  46. package/dist/__tests__/realtime/notifications.test.js +317 -0
  47. package/dist/__tests__/realtime/notifications.test.js.map +1 -0
  48. package/dist/__tests__/realtime/persistence.test.d.ts +2 -0
  49. package/dist/__tests__/realtime/persistence.test.d.ts.map +1 -0
  50. package/dist/__tests__/realtime/persistence.test.js +124 -0
  51. package/dist/__tests__/realtime/persistence.test.js.map +1 -0
  52. package/dist/__tests__/schema-preview-features.test.d.ts +2 -0
  53. package/dist/__tests__/schema-preview-features.test.d.ts.map +1 -0
  54. package/dist/__tests__/schema-preview-features.test.js +42 -0
  55. package/dist/__tests__/schema-preview-features.test.js.map +1 -0
  56. package/dist/actions.d.ts.map +1 -1
  57. package/dist/actions.js +71 -26
  58. package/dist/actions.js.map +1 -1
  59. package/dist/api/handlers.d.ts.map +1 -1
  60. package/dist/api/handlers.js +734 -188
  61. package/dist/api/handlers.js.map +1 -1
  62. package/dist/cache/__tests__/http.test.d.ts +2 -0
  63. package/dist/cache/__tests__/http.test.d.ts.map +1 -0
  64. package/dist/cache/__tests__/http.test.js +285 -0
  65. package/dist/cache/__tests__/http.test.js.map +1 -0
  66. package/dist/cache/http.d.ts +119 -0
  67. package/dist/cache/http.d.ts.map +1 -0
  68. package/dist/cache/http.js +188 -0
  69. package/dist/cache/http.js.map +1 -0
  70. package/dist/config/types.d.ts +153 -1
  71. package/dist/config/types.d.ts.map +1 -1
  72. package/dist/fields/component-block.d.ts +23 -0
  73. package/dist/fields/component-block.d.ts.map +1 -0
  74. package/dist/fields/component-block.js +137 -0
  75. package/dist/fields/component-block.js.map +1 -0
  76. package/dist/fields/index.d.ts.map +1 -1
  77. package/dist/fields/index.js +2 -0
  78. package/dist/fields/index.js.map +1 -1
  79. package/dist/fields/relations.d.ts.map +1 -1
  80. package/dist/fields/relations.js +43 -11
  81. package/dist/fields/relations.js.map +1 -1
  82. package/dist/index.d.ts +5 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +2 -0
  85. package/dist/index.js.map +1 -1
  86. package/dist/page-builder/schema.d.ts +2 -2
  87. package/dist/preview/event-bus.d.ts +39 -0
  88. package/dist/preview/event-bus.d.ts.map +1 -0
  89. package/dist/preview/event-bus.js +73 -0
  90. package/dist/preview/event-bus.js.map +1 -0
  91. package/dist/preview/sse-stream.d.ts +50 -0
  92. package/dist/preview/sse-stream.d.ts.map +1 -0
  93. package/dist/preview/sse-stream.js +120 -0
  94. package/dist/preview/sse-stream.js.map +1 -0
  95. package/dist/realtime/comments.d.ts +217 -0
  96. package/dist/realtime/comments.d.ts.map +1 -0
  97. package/dist/realtime/comments.js +282 -0
  98. package/dist/realtime/comments.js.map +1 -0
  99. package/dist/realtime/gateway.d.ts +107 -0
  100. package/dist/realtime/gateway.d.ts.map +1 -0
  101. package/dist/realtime/gateway.js +215 -0
  102. package/dist/realtime/gateway.js.map +1 -0
  103. package/dist/realtime/index.d.ts +18 -0
  104. package/dist/realtime/index.d.ts.map +1 -0
  105. package/dist/realtime/index.js +18 -0
  106. package/dist/realtime/index.js.map +1 -0
  107. package/dist/realtime/notifications.d.ts +209 -0
  108. package/dist/realtime/notifications.d.ts.map +1 -0
  109. package/dist/realtime/notifications.js +209 -0
  110. package/dist/realtime/notifications.js.map +1 -0
  111. package/dist/realtime/persistence.d.ts +72 -0
  112. package/dist/realtime/persistence.d.ts.map +1 -0
  113. package/dist/realtime/persistence.js +53 -0
  114. package/dist/realtime/persistence.js.map +1 -0
  115. package/package.json +13 -4
  116. package/prisma/cms-schema.prisma +437 -306
  117. package/prisma/migrations/0001_init/migration.sql +384 -384
  118. package/prisma/migrations/0002_folders/migration.sql +39 -39
  119. package/prisma/migrations/0003_search_and_webhooks/migration.sql +50 -50
  120. package/prisma/migrations/0004_script_tags/migration.sql +21 -21
  121. package/prisma/migrations/0005_password_reset_tokens/migration.sql +20 -20
  122. package/prisma/migrations/0006_page_builder/migration.sql +38 -38
  123. package/prisma/migrations/migration_lock.toml +3 -3
  124. package/prisma/schema.prisma +563 -549
  125. package/generated/browser.ts +0 -109
  126. package/generated/client.ts +0 -133
  127. package/generated/commonInputTypes.ts +0 -709
  128. package/generated/enums.ts +0 -125
  129. package/generated/internal/class.ts +0 -376
  130. package/generated/internal/prismaNamespace.ts +0 -2617
  131. package/generated/internal/prismaNamespaceBrowser.ts +0 -611
  132. package/generated/models/ApiKey.ts +0 -1550
  133. package/generated/models/AuditLog.ts +0 -1206
  134. package/generated/models/BackupRecord.ts +0 -1250
  135. package/generated/models/ContentLock.ts +0 -1472
  136. package/generated/models/ContentTemplate.ts +0 -1416
  137. package/generated/models/Document.ts +0 -3005
  138. package/generated/models/Folder.ts +0 -1904
  139. package/generated/models/FormSubmission.ts +0 -1200
  140. package/generated/models/InAppNotification.ts +0 -1457
  141. package/generated/models/Media.ts +0 -2340
  142. package/generated/models/MediaUsage.ts +0 -1472
  143. package/generated/models/OAuthAccount.ts +0 -1463
  144. package/generated/models/Redirect.ts +0 -1284
  145. package/generated/models/Session.ts +0 -1492
  146. package/generated/models/Site.ts +0 -1206
  147. package/generated/models/User.ts +0 -3513
  148. package/generated/models/Version.ts +0 -1511
  149. package/generated/models/WorkflowState.ts +0 -1514
  150. package/generated/models.ts +0 -29
@@ -1,549 +1,563 @@
1
- generator client {
2
- provider = "prisma-client"
3
- output = "../generated"
4
- previewFeatures = ["fullTextSearchPostgres"]
5
- }
6
-
7
- datasource db {
8
- provider = "postgresql"
9
- }
10
-
11
- // ─── Enums ──────────────────────────────────────────────────────────
12
-
13
- enum DocumentStatus {
14
- DRAFT
15
- PUBLISHED
16
- ARCHIVED
17
- SCHEDULED
18
- SCHEDULED_UNPUBLISH
19
- }
20
-
21
- enum UserRole {
22
- ADMIN
23
- EDITOR
24
- AUTHOR
25
- CLIENT
26
- }
27
-
28
- enum ChangeType {
29
- CREATE
30
- UPDATE
31
- PUBLISH
32
- RESTORE
33
- DELETE
34
- }
35
-
36
- enum AuditEvent {
37
- login_success
38
- login_failed
39
- logout
40
- password_change
41
- password_reset_request
42
- password_reset_complete
43
- totp_enabled
44
- totp_disabled
45
- api_key_created
46
- api_key_revoked
47
- document_created
48
- document_updated
49
- document_published
50
- document_deleted
51
- media_uploaded
52
- media_deleted
53
- user_created
54
- user_updated
55
- user_deactivated
56
- settings_changed
57
- version_restored
58
- export_requested
59
- import_completed
60
- }
61
-
62
- enum NotificationType {
63
- DOCUMENT_PUBLISHED
64
- DOCUMENT_ASSIGNED
65
- REVIEW_REQUESTED
66
- REVIEW_APPROVED
67
- COMMENT_ADDED
68
- SYSTEM_ALERT
69
- WORKFLOW_STEP
70
- }
71
-
72
- enum OrderStatus {
73
- PENDING
74
- CONFIRMED
75
- PROCESSING
76
- SHIPPED
77
- DELIVERED
78
- CANCELLED
79
- REFUNDED
80
- }
81
-
82
- enum PaymentStatus {
83
- PENDING
84
- AUTHORIZED
85
- CAPTURED
86
- FAILED
87
- REFUNDED
88
- PARTIALLY_REFUNDED
89
- }
90
-
91
- enum WorkflowStage {
92
- DRAFT
93
- IN_REVIEW
94
- APPROVED
95
- PUBLISHED
96
- ARCHIVED
97
- }
98
-
99
- enum DiscountType {
100
- PERCENTAGE
101
- FIXED_AMOUNT
102
- FREE_SHIPPING
103
- }
104
-
105
- enum ProductType {
106
- PHYSICAL
107
- DIGITAL
108
- SUBSCRIPTION
109
- BUNDLE
110
- }
111
-
112
- // ─── Models ─────────────────────────────────────────────────────────
113
-
114
- model User {
115
- id String @id @default(cuid())
116
- email String @unique
117
- name String
118
- avatarUrl String?
119
- role UserRole @default(AUTHOR)
120
- passwordHash String?
121
- totpSecret String?
122
- totpEnabled Boolean @default(false)
123
- backupCodes Json?
124
- authProvider String?
125
- isActive Boolean @default(true)
126
- isApproved Boolean @default(false)
127
- emailVerified Boolean @default(false)
128
- lastLoginAt DateTime?
129
- createdAt DateTime @default(now())
130
- updatedAt DateTime @updatedAt
131
-
132
- sessions Session[]
133
- oauthAccounts OAuthAccount[]
134
- apiKeys ApiKey[]
135
- documents Document[] @relation("CreatedDocuments")
136
- updatedDocuments Document[] @relation("UpdatedDocuments")
137
- versions Version[]
138
- media Media[]
139
- contentLocks ContentLock[]
140
- notifications InAppNotification[]
141
- contentTemplates ContentTemplate[]
142
- workflowAssigned WorkflowState[]
143
- passwordResetTokens PasswordResetToken[]
144
-
145
- @@map("actuate_users")
146
- }
147
-
148
- model OAuthAccount {
149
- id String @id @default(cuid())
150
- userId String
151
- provider String
152
- providerAccountId String
153
- accessToken String?
154
- refreshToken String?
155
- expiresAt DateTime?
156
- createdAt DateTime @default(now())
157
-
158
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
159
-
160
- @@unique([provider, providerAccountId])
161
- @@map("actuate_oauth_accounts")
162
- }
163
-
164
- model Session {
165
- id String @id @default(cuid())
166
- userId String
167
- token String @unique
168
- expiresAt DateTime
169
- revokedAt DateTime?
170
- ipAddress String?
171
- userAgent String?
172
- fingerprintHash String?
173
- createdAt DateTime @default(now())
174
-
175
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
176
-
177
- @@index([userId])
178
- @@index([expiresAt])
179
- @@map("actuate_sessions")
180
- }
181
-
182
- model ApiKey {
183
- id String @id @default(cuid())
184
- name String
185
- keyHash String @unique
186
- keyPrefix String
187
- userId String
188
- scopes Json
189
- ipRestrictions Json?
190
- expiresAt DateTime?
191
- lastUsedAt DateTime?
192
- revokedAt DateTime?
193
- createdAt DateTime @default(now())
194
-
195
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
196
-
197
- @@map("actuate_api_keys")
198
- }
199
-
200
- model AuditLog {
201
- id String @id @default(cuid())
202
- event String
203
- userId String?
204
- ipAddress String?
205
- userAgent String?
206
- details Json?
207
- timestamp DateTime @default(now())
208
-
209
- @@index([event])
210
- @@index([userId])
211
- @@index([timestamp])
212
- @@map("actuate_audit_logs")
213
- }
214
-
215
- model Folder {
216
- id String @id @default(cuid())
217
- name String
218
- scope String
219
- parentId String?
220
- position Int @default(0)
221
- createdAt DateTime @default(now())
222
- updatedAt DateTime @updatedAt
223
-
224
- parent Folder? @relation("FolderTree", fields: [parentId], references: [id], onDelete: Cascade)
225
- children Folder[] @relation("FolderTree")
226
-
227
- documents Document[]
228
- media Media[]
229
-
230
- @@index([scope])
231
- @@index([parentId])
232
- @@map("actuate_folders")
233
- }
234
-
235
- model Document {
236
- id String @id @default(cuid())
237
- collection String
238
- title String?
239
- slug String?
240
- data Json
241
- status DocumentStatus @default(DRAFT)
242
- locale String?
243
- localeGroupId String?
244
- createdById String
245
- updatedById String
246
- publishedAt DateTime?
247
- scheduledAt DateTime?
248
- scheduledUnpublishAt DateTime?
249
- deletedAt DateTime?
250
- searchVector String?
251
- plainText String?
252
- contentHash String?
253
- structuredData Json?
254
- contentGraph Json?
255
- siteId String?
256
- templateId String?
257
- workflowStage WorkflowStage @default(DRAFT)
258
- reviewerId String?
259
- reviewNote String?
260
- folderId String?
261
- createdAt DateTime @default(now())
262
- updatedAt DateTime @updatedAt
263
-
264
- createdBy User @relation("CreatedDocuments", fields: [createdById], references: [id])
265
- updatedBy User @relation("UpdatedDocuments", fields: [updatedById], references: [id])
266
- folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
267
- versions Version[]
268
- mediaUsages MediaUsage[]
269
- contentLocks ContentLock[]
270
-
271
- @@unique([collection, slug])
272
- @@index([collection])
273
- @@index([status])
274
- @@index([deletedAt])
275
- @@index([publishedAt])
276
- @@index([folderId])
277
- @@index([scheduledAt])
278
- @@index([localeGroupId])
279
- @@index([createdById])
280
- @@map("actuate_documents")
281
- }
282
-
283
- model Version {
284
- id String @id @default(cuid())
285
- documentId String
286
- data Json
287
- changedById String
288
- changeType ChangeType
289
- createdAt DateTime @default(now())
290
-
291
- document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
292
- changedBy User @relation(fields: [changedById], references: [id])
293
-
294
- @@index([documentId])
295
- @@map("actuate_versions")
296
- }
297
-
298
- model Media {
299
- id String @id @default(cuid())
300
- filename String
301
- storageKey String @unique
302
- mimeType String
303
- fileSize Int
304
- width Int?
305
- height Int?
306
- altText String?
307
- title String?
308
- uploadedById String
309
- focalPointX Float?
310
- focalPointY Float?
311
- blurHash String?
312
- aiAltText String?
313
- aiTags Json?
314
- aiDescription String?
315
- folderId String?
316
- createdAt DateTime @default(now())
317
- updatedAt DateTime @updatedAt
318
-
319
- uploadedBy User @relation(fields: [uploadedById], references: [id])
320
- folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
321
- mediaUsages MediaUsage[]
322
-
323
- @@index([folderId])
324
- @@map("actuate_media")
325
- }
326
-
327
- model MediaUsage {
328
- id String @id @default(cuid())
329
- mediaId String
330
- documentId String
331
- fieldName String
332
- createdAt DateTime @default(now())
333
-
334
- media Media @relation(fields: [mediaId], references: [id], onDelete: Cascade)
335
- document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
336
-
337
- @@unique([mediaId, documentId, fieldName])
338
- @@index([documentId])
339
- @@map("actuate_media_usages")
340
- }
341
-
342
- model ContentLock {
343
- id String @id @default(cuid())
344
- documentId String
345
- userId String
346
- lockedAt DateTime @default(now())
347
- expiresAt DateTime
348
-
349
- document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
350
- user User @relation(fields: [userId], references: [id])
351
-
352
- @@map("actuate_content_locks")
353
- }
354
-
355
- model InAppNotification {
356
- id String @id @default(cuid())
357
- userId String
358
- type String
359
- title String
360
- message String?
361
- link String?
362
- read Boolean @default(false)
363
- createdAt DateTime @default(now())
364
-
365
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
366
-
367
- @@map("actuate_notifications")
368
- }
369
-
370
- model ContentTemplate {
371
- id String @id @default(cuid())
372
- name String
373
- collection String
374
- templateData Json
375
- createdById String
376
- createdAt DateTime @default(now())
377
- updatedAt DateTime @updatedAt
378
-
379
- createdBy User @relation(fields: [createdById], references: [id])
380
-
381
- @@map("actuate_content_templates")
382
- }
383
-
384
- model Site {
385
- id String @id @default(cuid())
386
- domain String @unique
387
- name String
388
- configOverrides Json?
389
- isDefault Boolean @default(false)
390
- createdAt DateTime @default(now())
391
- updatedAt DateTime @updatedAt
392
-
393
- @@map("actuate_sites")
394
- }
395
-
396
- model WorkflowState {
397
- id String @id @default(cuid())
398
- documentId String @unique
399
- currentStep Int @default(0)
400
- assignedToId String?
401
- status String @default("pending")
402
- definition Json
403
- createdAt DateTime @default(now())
404
- updatedAt DateTime @updatedAt
405
-
406
- assignedTo User? @relation(fields: [assignedToId], references: [id])
407
-
408
- @@map("actuate_workflow_states")
409
- }
410
-
411
- model Redirect {
412
- id String @id @default(cuid())
413
- source String
414
- destination String
415
- statusCode Int @default(301)
416
- isRegex Boolean @default(false)
417
- notes String?
418
- createdAt DateTime @default(now())
419
- updatedAt DateTime @updatedAt
420
-
421
- @@unique([source])
422
- @@map("actuate_redirects")
423
- }
424
-
425
- model FormSubmission {
426
- id String @id @default(cuid())
427
- formId String
428
- data Json
429
- attribution Json?
430
- status String @default("new")
431
- submittedAt DateTime @default(now())
432
- createdAt DateTime @default(now())
433
-
434
- @@index([formId])
435
- @@index([status])
436
- @@map("actuate_form_submissions")
437
- }
438
-
439
- model BackupRecord {
440
- id String @id @default(cuid())
441
- filename String
442
- storageKey String
443
- sizeBytes Int
444
- type String
445
- metadata Json?
446
- createdAt DateTime @default(now())
447
-
448
- @@map("actuate_backup_records")
449
- }
450
-
451
- model WebhookEndpoint {
452
- id String @id @default(cuid())
453
- url String
454
- events Json
455
- secret String
456
- active Boolean @default(true)
457
- name String?
458
- createdAt DateTime @default(now())
459
- updatedAt DateTime @updatedAt
460
-
461
- deliveries WebhookDeliveryLog[]
462
-
463
- @@map("actuate_webhook_endpoints")
464
- }
465
-
466
- model WebhookDeliveryLog {
467
- id String @id @default(cuid())
468
- endpointId String
469
- event String
470
- payload Json
471
- status String @default("pending")
472
- attempts Int @default(0)
473
- maxAttempts Int @default(3)
474
- lastAttemptAt DateTime?
475
- nextRetryAt DateTime?
476
- responseStatus Int?
477
- responseBody String?
478
- createdAt DateTime @default(now())
479
-
480
- endpoint WebhookEndpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade)
481
-
482
- @@index([endpointId])
483
- @@index([status])
484
- @@index([nextRetryAt])
485
- @@map("actuate_webhook_deliveries")
486
- }
487
-
488
- model PasswordResetToken {
489
- id String @id @default(cuid())
490
- userId String
491
- tokenHash String
492
- expiresAt DateTime
493
- usedAt DateTime?
494
- createdAt DateTime @default(now())
495
-
496
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
497
-
498
- @@index([tokenHash])
499
- @@index([userId])
500
- @@map("actuate_password_reset_tokens")
501
- }
502
-
503
- model ScriptTag {
504
- id String @id @default(cuid())
505
- name String
506
- code String @db.Text
507
- placement String
508
- scope String
509
- targetPaths String[]
510
- priority Int @default(100)
511
- enabled Boolean @default(true)
512
- createdAt DateTime @default(now())
513
- updatedAt DateTime @updatedAt
514
-
515
- @@index([enabled])
516
- @@index([placement])
517
- @@map("actuate_script_tags")
518
- }
519
-
520
- model PageTemplate {
521
- id String @id @default(cuid())
522
- name String
523
- description String?
524
- category String @default("content")
525
- tree Json
526
- thumbnail String?
527
- builtIn Boolean @default(false)
528
- createdAt DateTime @default(now())
529
- updatedAt DateTime @updatedAt
530
-
531
- @@index([category])
532
- @@index([builtIn])
533
- @@map("actuate_page_templates")
534
- }
535
-
536
- model SavedSection {
537
- id String @id @default(cuid())
538
- name String
539
- description String?
540
- category String @default("content")
541
- tree Json
542
- thumbnail String?
543
- usageCount Int @default(0)
544
- createdAt DateTime @default(now())
545
- updatedAt DateTime @updatedAt
546
-
547
- @@index([category])
548
- @@map("actuate_saved_sections")
549
- }
1
+ generator client {
2
+ provider = "prisma-client"
3
+ output = "../generated"
4
+ // `relationJoins` is the Preview-feature flag that makes
5
+ // `relationLoadStrategy: 'join'` a recognised argument on
6
+ // findUnique / findMany / findFirst. Without it the option is
7
+ // silently rejected as an "Unknown argument" by Prisma — which
8
+ // is how the optimisation in PR #132 (dashboard recent-docs +
9
+ // versions list + bench `doc_get`) went unnoticed in production:
10
+ // `safeFindMany` swallowed the rejection and returned `[]`, the
11
+ // versions endpoint returned 500, and the bench reported "100/100
12
+ // errors" with no attached cause. Phase 5.5 #5 surfaced the
13
+ // failure once the bench harness started recording the first
14
+ // error message.
15
+ //
16
+ // The feature has been Preview since Prisma 5.7 and is documented
17
+ // at https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries#relation-load-strategies
18
+ previewFeatures = ["fullTextSearchPostgres", "relationJoins"]
19
+ }
20
+
21
+ datasource db {
22
+ provider = "postgresql"
23
+ }
24
+
25
+ // ─── Enums ──────────────────────────────────────────────────────────
26
+
27
+ enum DocumentStatus {
28
+ DRAFT
29
+ PUBLISHED
30
+ ARCHIVED
31
+ SCHEDULED
32
+ SCHEDULED_UNPUBLISH
33
+ }
34
+
35
+ enum UserRole {
36
+ ADMIN
37
+ EDITOR
38
+ AUTHOR
39
+ CLIENT
40
+ }
41
+
42
+ enum ChangeType {
43
+ CREATE
44
+ UPDATE
45
+ PUBLISH
46
+ RESTORE
47
+ DELETE
48
+ }
49
+
50
+ enum AuditEvent {
51
+ login_success
52
+ login_failed
53
+ logout
54
+ password_change
55
+ password_reset_request
56
+ password_reset_complete
57
+ totp_enabled
58
+ totp_disabled
59
+ api_key_created
60
+ api_key_revoked
61
+ document_created
62
+ document_updated
63
+ document_published
64
+ document_deleted
65
+ media_uploaded
66
+ media_deleted
67
+ user_created
68
+ user_updated
69
+ user_deactivated
70
+ settings_changed
71
+ version_restored
72
+ export_requested
73
+ import_completed
74
+ }
75
+
76
+ enum NotificationType {
77
+ DOCUMENT_PUBLISHED
78
+ DOCUMENT_ASSIGNED
79
+ REVIEW_REQUESTED
80
+ REVIEW_APPROVED
81
+ COMMENT_ADDED
82
+ SYSTEM_ALERT
83
+ WORKFLOW_STEP
84
+ }
85
+
86
+ enum OrderStatus {
87
+ PENDING
88
+ CONFIRMED
89
+ PROCESSING
90
+ SHIPPED
91
+ DELIVERED
92
+ CANCELLED
93
+ REFUNDED
94
+ }
95
+
96
+ enum PaymentStatus {
97
+ PENDING
98
+ AUTHORIZED
99
+ CAPTURED
100
+ FAILED
101
+ REFUNDED
102
+ PARTIALLY_REFUNDED
103
+ }
104
+
105
+ enum WorkflowStage {
106
+ DRAFT
107
+ IN_REVIEW
108
+ APPROVED
109
+ PUBLISHED
110
+ ARCHIVED
111
+ }
112
+
113
+ enum DiscountType {
114
+ PERCENTAGE
115
+ FIXED_AMOUNT
116
+ FREE_SHIPPING
117
+ }
118
+
119
+ enum ProductType {
120
+ PHYSICAL
121
+ DIGITAL
122
+ SUBSCRIPTION
123
+ BUNDLE
124
+ }
125
+
126
+ // ─── Models ─────────────────────────────────────────────────────────
127
+
128
+ model User {
129
+ id String @id @default(cuid())
130
+ email String @unique
131
+ name String
132
+ avatarUrl String?
133
+ role UserRole @default(AUTHOR)
134
+ passwordHash String?
135
+ totpSecret String?
136
+ totpEnabled Boolean @default(false)
137
+ backupCodes Json?
138
+ authProvider String?
139
+ isActive Boolean @default(true)
140
+ isApproved Boolean @default(false)
141
+ emailVerified Boolean @default(false)
142
+ lastLoginAt DateTime?
143
+ createdAt DateTime @default(now())
144
+ updatedAt DateTime @updatedAt
145
+
146
+ sessions Session[]
147
+ oauthAccounts OAuthAccount[]
148
+ apiKeys ApiKey[]
149
+ documents Document[] @relation("CreatedDocuments")
150
+ updatedDocuments Document[] @relation("UpdatedDocuments")
151
+ versions Version[]
152
+ media Media[]
153
+ contentLocks ContentLock[]
154
+ notifications InAppNotification[]
155
+ contentTemplates ContentTemplate[]
156
+ workflowAssigned WorkflowState[]
157
+ passwordResetTokens PasswordResetToken[]
158
+
159
+ @@map("actuate_users")
160
+ }
161
+
162
+ model OAuthAccount {
163
+ id String @id @default(cuid())
164
+ userId String
165
+ provider String
166
+ providerAccountId String
167
+ accessToken String?
168
+ refreshToken String?
169
+ expiresAt DateTime?
170
+ createdAt DateTime @default(now())
171
+
172
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
173
+
174
+ @@unique([provider, providerAccountId])
175
+ @@map("actuate_oauth_accounts")
176
+ }
177
+
178
+ model Session {
179
+ id String @id @default(cuid())
180
+ userId String
181
+ token String @unique
182
+ expiresAt DateTime
183
+ revokedAt DateTime?
184
+ ipAddress String?
185
+ userAgent String?
186
+ fingerprintHash String?
187
+ createdAt DateTime @default(now())
188
+
189
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
190
+
191
+ @@index([userId])
192
+ @@index([expiresAt])
193
+ @@map("actuate_sessions")
194
+ }
195
+
196
+ model ApiKey {
197
+ id String @id @default(cuid())
198
+ name String
199
+ keyHash String @unique
200
+ keyPrefix String
201
+ userId String
202
+ scopes Json
203
+ ipRestrictions Json?
204
+ expiresAt DateTime?
205
+ lastUsedAt DateTime?
206
+ revokedAt DateTime?
207
+ createdAt DateTime @default(now())
208
+
209
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
210
+
211
+ @@map("actuate_api_keys")
212
+ }
213
+
214
+ model AuditLog {
215
+ id String @id @default(cuid())
216
+ event String
217
+ userId String?
218
+ ipAddress String?
219
+ userAgent String?
220
+ details Json?
221
+ timestamp DateTime @default(now())
222
+
223
+ @@index([event])
224
+ @@index([userId])
225
+ @@index([timestamp])
226
+ @@map("actuate_audit_logs")
227
+ }
228
+
229
+ model Folder {
230
+ id String @id @default(cuid())
231
+ name String
232
+ scope String
233
+ parentId String?
234
+ position Int @default(0)
235
+ createdAt DateTime @default(now())
236
+ updatedAt DateTime @updatedAt
237
+
238
+ parent Folder? @relation("FolderTree", fields: [parentId], references: [id], onDelete: Cascade)
239
+ children Folder[] @relation("FolderTree")
240
+
241
+ documents Document[]
242
+ media Media[]
243
+
244
+ @@index([scope])
245
+ @@index([parentId])
246
+ @@map("actuate_folders")
247
+ }
248
+
249
+ model Document {
250
+ id String @id @default(cuid())
251
+ collection String
252
+ title String?
253
+ slug String?
254
+ data Json
255
+ status DocumentStatus @default(DRAFT)
256
+ locale String?
257
+ localeGroupId String?
258
+ createdById String
259
+ updatedById String
260
+ publishedAt DateTime?
261
+ scheduledAt DateTime?
262
+ scheduledUnpublishAt DateTime?
263
+ deletedAt DateTime?
264
+ searchVector String?
265
+ plainText String?
266
+ contentHash String?
267
+ structuredData Json?
268
+ contentGraph Json?
269
+ siteId String?
270
+ templateId String?
271
+ workflowStage WorkflowStage @default(DRAFT)
272
+ reviewerId String?
273
+ reviewNote String?
274
+ folderId String?
275
+ createdAt DateTime @default(now())
276
+ updatedAt DateTime @updatedAt
277
+
278
+ createdBy User @relation("CreatedDocuments", fields: [createdById], references: [id])
279
+ updatedBy User @relation("UpdatedDocuments", fields: [updatedById], references: [id])
280
+ folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
281
+ versions Version[]
282
+ mediaUsages MediaUsage[]
283
+ contentLocks ContentLock[]
284
+
285
+ @@unique([collection, slug])
286
+ @@index([collection])
287
+ @@index([status])
288
+ @@index([deletedAt])
289
+ @@index([publishedAt])
290
+ @@index([folderId])
291
+ @@index([scheduledAt])
292
+ @@index([localeGroupId])
293
+ @@index([createdById])
294
+ @@map("actuate_documents")
295
+ }
296
+
297
+ model Version {
298
+ id String @id @default(cuid())
299
+ documentId String
300
+ data Json
301
+ changedById String
302
+ changeType ChangeType
303
+ createdAt DateTime @default(now())
304
+
305
+ document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
306
+ changedBy User @relation(fields: [changedById], references: [id])
307
+
308
+ @@index([documentId])
309
+ @@map("actuate_versions")
310
+ }
311
+
312
+ model Media {
313
+ id String @id @default(cuid())
314
+ filename String
315
+ storageKey String @unique
316
+ mimeType String
317
+ fileSize Int
318
+ width Int?
319
+ height Int?
320
+ altText String?
321
+ title String?
322
+ uploadedById String
323
+ focalPointX Float?
324
+ focalPointY Float?
325
+ blurHash String?
326
+ aiAltText String?
327
+ aiTags Json?
328
+ aiDescription String?
329
+ folderId String?
330
+ createdAt DateTime @default(now())
331
+ updatedAt DateTime @updatedAt
332
+
333
+ uploadedBy User @relation(fields: [uploadedById], references: [id])
334
+ folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
335
+ mediaUsages MediaUsage[]
336
+
337
+ @@index([folderId])
338
+ @@map("actuate_media")
339
+ }
340
+
341
+ model MediaUsage {
342
+ id String @id @default(cuid())
343
+ mediaId String
344
+ documentId String
345
+ fieldName String
346
+ createdAt DateTime @default(now())
347
+
348
+ media Media @relation(fields: [mediaId], references: [id], onDelete: Cascade)
349
+ document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
350
+
351
+ @@unique([mediaId, documentId, fieldName])
352
+ @@index([documentId])
353
+ @@map("actuate_media_usages")
354
+ }
355
+
356
+ model ContentLock {
357
+ id String @id @default(cuid())
358
+ documentId String
359
+ userId String
360
+ lockedAt DateTime @default(now())
361
+ expiresAt DateTime
362
+
363
+ document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
364
+ user User @relation(fields: [userId], references: [id])
365
+
366
+ @@map("actuate_content_locks")
367
+ }
368
+
369
+ model InAppNotification {
370
+ id String @id @default(cuid())
371
+ userId String
372
+ type String
373
+ title String
374
+ message String?
375
+ link String?
376
+ read Boolean @default(false)
377
+ createdAt DateTime @default(now())
378
+
379
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
380
+
381
+ @@map("actuate_notifications")
382
+ }
383
+
384
+ model ContentTemplate {
385
+ id String @id @default(cuid())
386
+ name String
387
+ collection String
388
+ templateData Json
389
+ createdById String
390
+ createdAt DateTime @default(now())
391
+ updatedAt DateTime @updatedAt
392
+
393
+ createdBy User @relation(fields: [createdById], references: [id])
394
+
395
+ @@map("actuate_content_templates")
396
+ }
397
+
398
+ model Site {
399
+ id String @id @default(cuid())
400
+ domain String @unique
401
+ name String
402
+ configOverrides Json?
403
+ isDefault Boolean @default(false)
404
+ createdAt DateTime @default(now())
405
+ updatedAt DateTime @updatedAt
406
+
407
+ @@map("actuate_sites")
408
+ }
409
+
410
+ model WorkflowState {
411
+ id String @id @default(cuid())
412
+ documentId String @unique
413
+ currentStep Int @default(0)
414
+ assignedToId String?
415
+ status String @default("pending")
416
+ definition Json
417
+ createdAt DateTime @default(now())
418
+ updatedAt DateTime @updatedAt
419
+
420
+ assignedTo User? @relation(fields: [assignedToId], references: [id])
421
+
422
+ @@map("actuate_workflow_states")
423
+ }
424
+
425
+ model Redirect {
426
+ id String @id @default(cuid())
427
+ source String
428
+ destination String
429
+ statusCode Int @default(301)
430
+ isRegex Boolean @default(false)
431
+ notes String?
432
+ createdAt DateTime @default(now())
433
+ updatedAt DateTime @updatedAt
434
+
435
+ @@unique([source])
436
+ @@map("actuate_redirects")
437
+ }
438
+
439
+ model FormSubmission {
440
+ id String @id @default(cuid())
441
+ formId String
442
+ data Json
443
+ attribution Json?
444
+ status String @default("new")
445
+ submittedAt DateTime @default(now())
446
+ createdAt DateTime @default(now())
447
+
448
+ @@index([formId])
449
+ @@index([status])
450
+ @@map("actuate_form_submissions")
451
+ }
452
+
453
+ model BackupRecord {
454
+ id String @id @default(cuid())
455
+ filename String
456
+ storageKey String
457
+ sizeBytes Int
458
+ type String
459
+ metadata Json?
460
+ createdAt DateTime @default(now())
461
+
462
+ @@map("actuate_backup_records")
463
+ }
464
+
465
+ model WebhookEndpoint {
466
+ id String @id @default(cuid())
467
+ url String
468
+ events Json
469
+ secret String
470
+ active Boolean @default(true)
471
+ name String?
472
+ createdAt DateTime @default(now())
473
+ updatedAt DateTime @updatedAt
474
+
475
+ deliveries WebhookDeliveryLog[]
476
+
477
+ @@map("actuate_webhook_endpoints")
478
+ }
479
+
480
+ model WebhookDeliveryLog {
481
+ id String @id @default(cuid())
482
+ endpointId String
483
+ event String
484
+ payload Json
485
+ status String @default("pending")
486
+ attempts Int @default(0)
487
+ maxAttempts Int @default(3)
488
+ lastAttemptAt DateTime?
489
+ nextRetryAt DateTime?
490
+ responseStatus Int?
491
+ responseBody String?
492
+ createdAt DateTime @default(now())
493
+
494
+ endpoint WebhookEndpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade)
495
+
496
+ @@index([endpointId])
497
+ @@index([status])
498
+ @@index([nextRetryAt])
499
+ @@map("actuate_webhook_deliveries")
500
+ }
501
+
502
+ model PasswordResetToken {
503
+ id String @id @default(cuid())
504
+ userId String
505
+ tokenHash String
506
+ expiresAt DateTime
507
+ usedAt DateTime?
508
+ createdAt DateTime @default(now())
509
+
510
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
511
+
512
+ @@index([tokenHash])
513
+ @@index([userId])
514
+ @@map("actuate_password_reset_tokens")
515
+ }
516
+
517
+ model ScriptTag {
518
+ id String @id @default(cuid())
519
+ name String
520
+ code String @db.Text
521
+ placement String
522
+ scope String
523
+ targetPaths String[]
524
+ priority Int @default(100)
525
+ enabled Boolean @default(true)
526
+ createdAt DateTime @default(now())
527
+ updatedAt DateTime @updatedAt
528
+
529
+ @@index([enabled])
530
+ @@index([placement])
531
+ @@map("actuate_script_tags")
532
+ }
533
+
534
+ model PageTemplate {
535
+ id String @id @default(cuid())
536
+ name String
537
+ description String?
538
+ category String @default("content")
539
+ tree Json
540
+ thumbnail String?
541
+ builtIn Boolean @default(false)
542
+ createdAt DateTime @default(now())
543
+ updatedAt DateTime @updatedAt
544
+
545
+ @@index([category])
546
+ @@index([builtIn])
547
+ @@map("actuate_page_templates")
548
+ }
549
+
550
+ model SavedSection {
551
+ id String @id @default(cuid())
552
+ name String
553
+ description String?
554
+ category String @default("content")
555
+ tree Json
556
+ thumbnail String?
557
+ usageCount Int @default(0)
558
+ createdAt DateTime @default(now())
559
+ updatedAt DateTime @updatedAt
560
+
561
+ @@index([category])
562
+ @@map("actuate_saved_sections")
563
+ }