@actuate-media/cms-core 0.13.0 → 0.15.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 (73) hide show
  1. package/LICENSE +21 -21
  2. package/dist/__tests__/api/api-key-auth.test.d.ts +2 -0
  3. package/dist/__tests__/api/api-key-auth.test.d.ts.map +1 -0
  4. package/dist/__tests__/api/api-key-auth.test.js +254 -0
  5. package/dist/__tests__/api/api-key-auth.test.js.map +1 -0
  6. package/dist/__tests__/api/public-seo.test.d.ts +2 -0
  7. package/dist/__tests__/api/public-seo.test.d.ts.map +1 -0
  8. package/dist/__tests__/api/public-seo.test.js +341 -0
  9. package/dist/__tests__/api/public-seo.test.js.map +1 -0
  10. package/dist/__tests__/security/api-key-enhanced.test.d.ts +2 -0
  11. package/dist/__tests__/security/api-key-enhanced.test.d.ts.map +1 -0
  12. package/dist/__tests__/security/api-key-enhanced.test.js +110 -0
  13. package/dist/__tests__/security/api-key-enhanced.test.js.map +1 -0
  14. package/dist/__tests__/seo/page-meta.test.d.ts +2 -0
  15. package/dist/__tests__/seo/page-meta.test.d.ts.map +1 -0
  16. package/dist/__tests__/seo/page-meta.test.js +204 -0
  17. package/dist/__tests__/seo/page-meta.test.js.map +1 -0
  18. package/dist/api/handler-factory.d.ts.map +1 -1
  19. package/dist/api/handler-factory.js +20 -2
  20. package/dist/api/handler-factory.js.map +1 -1
  21. package/dist/api/handlers.d.ts.map +1 -1
  22. package/dist/api/handlers.js +764 -31
  23. package/dist/api/handlers.js.map +1 -1
  24. package/dist/config/types.d.ts +75 -0
  25. package/dist/config/types.d.ts.map +1 -1
  26. package/dist/security/api-key-enhanced.d.ts +48 -5
  27. package/dist/security/api-key-enhanced.d.ts.map +1 -1
  28. package/dist/security/api-key-enhanced.js +60 -9
  29. package/dist/security/api-key-enhanced.js.map +1 -1
  30. package/dist/seo/index.d.ts +2 -0
  31. package/dist/seo/index.d.ts.map +1 -1
  32. package/dist/seo/index.js +1 -0
  33. package/dist/seo/index.js.map +1 -1
  34. package/dist/seo/page-meta.d.ts +79 -0
  35. package/dist/seo/page-meta.d.ts.map +1 -0
  36. package/dist/seo/page-meta.js +209 -0
  37. package/dist/seo/page-meta.js.map +1 -0
  38. package/generated/browser.ts +109 -0
  39. package/generated/client.ts +133 -0
  40. package/generated/commonInputTypes.ts +709 -0
  41. package/generated/enums.ts +125 -0
  42. package/generated/internal/class.ts +376 -0
  43. package/generated/internal/prismaNamespace.ts +2617 -0
  44. package/generated/internal/prismaNamespaceBrowser.ts +611 -0
  45. package/generated/models/ApiKey.ts +1550 -0
  46. package/generated/models/AuditLog.ts +1206 -0
  47. package/generated/models/BackupRecord.ts +1250 -0
  48. package/generated/models/ContentLock.ts +1472 -0
  49. package/generated/models/ContentTemplate.ts +1416 -0
  50. package/generated/models/Document.ts +3005 -0
  51. package/generated/models/Folder.ts +1904 -0
  52. package/generated/models/FormSubmission.ts +1200 -0
  53. package/generated/models/InAppNotification.ts +1457 -0
  54. package/generated/models/Media.ts +2340 -0
  55. package/generated/models/MediaUsage.ts +1472 -0
  56. package/generated/models/OAuthAccount.ts +1463 -0
  57. package/generated/models/Redirect.ts +1284 -0
  58. package/generated/models/Session.ts +1492 -0
  59. package/generated/models/Site.ts +1206 -0
  60. package/generated/models/User.ts +3513 -0
  61. package/generated/models/Version.ts +1511 -0
  62. package/generated/models/WorkflowState.ts +1514 -0
  63. package/generated/models.ts +29 -0
  64. package/package.json +1 -1
  65. package/prisma/cms-schema.prisma +306 -306
  66. package/prisma/migrations/0001_init/migration.sql +384 -384
  67. package/prisma/migrations/0002_folders/migration.sql +39 -39
  68. package/prisma/migrations/0003_search_and_webhooks/migration.sql +50 -50
  69. package/prisma/migrations/0004_script_tags/migration.sql +21 -21
  70. package/prisma/migrations/0005_password_reset_tokens/migration.sql +20 -20
  71. package/prisma/migrations/0006_page_builder/migration.sql +38 -38
  72. package/prisma/migrations/migration_lock.toml +3 -3
  73. package/prisma/schema.prisma +549 -549
@@ -0,0 +1,29 @@
1
+
2
+ /* !!! This is code generated by Prisma. Do not edit directly. !!! */
3
+ /* eslint-disable */
4
+ // biome-ignore-all lint: generated file
5
+ // @ts-nocheck
6
+ /*
7
+ * This is a barrel export file for all models and their related types.
8
+ *
9
+ * 🟢 You can import this file directly.
10
+ */
11
+ export type * from './models/User'
12
+ export type * from './models/OAuthAccount'
13
+ export type * from './models/Session'
14
+ export type * from './models/ApiKey'
15
+ export type * from './models/AuditLog'
16
+ export type * from './models/Folder'
17
+ export type * from './models/Document'
18
+ export type * from './models/Version'
19
+ export type * from './models/Media'
20
+ export type * from './models/MediaUsage'
21
+ export type * from './models/ContentLock'
22
+ export type * from './models/InAppNotification'
23
+ export type * from './models/ContentTemplate'
24
+ export type * from './models/Site'
25
+ export type * from './models/WorkflowState'
26
+ export type * from './models/Redirect'
27
+ export type * from './models/FormSubmission'
28
+ export type * from './models/BackupRecord'
29
+ export type * from './commonInputTypes'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuate-media/cms-core",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/actuate-media/actuatecms.git",
@@ -1,306 +1,306 @@
1
- // ═══════════════════════════════════════════════════════════════════════════════
2
- // Actuate CMS — Prisma schema fragment
3
- // ═══════════════════════════════════════════════════════════════════════════════
4
- //
5
- // This file defines the database models expected by `@actuatecms/cms-core` API
6
- // handlers and server actions. It is a **fragment**: it does not include a
7
- // `datasource` or `generator` block.
8
- //
9
- // ── How to merge into your project ─────────────────────────────────────────────
10
- //
11
- // 1. Ensure your root `schema.prisma` uses PostgreSQL, for example:
12
- // datasource db {
13
- // provider = "postgresql"
14
- // url = env("DATABASE_URL")
15
- // }
16
- // generator client {
17
- // provider = "prisma-client-js"
18
- // output = "../node_modules/.prisma/client"
19
- // }
20
- //
21
- // 2. Copy the `enum` and `model` blocks below into your `schema.prisma` (or use
22
- // Prisma’s multi-file schema preview: put this file in `prisma/schema/` and
23
- // include it per Prisma’s multi-file docs).
24
- //
25
- // 3. Resolve naming clashes: if you already have a `User` or `Document` model,
26
- // rename these models and update your Actuate integration to use a custom
27
- // Prisma client, or map tables with `@@map("…")` and align delegate names.
28
- //
29
- // 4. Run migrations:
30
- // npx prisma migrate dev --name actuate-cms
31
- //
32
- // Models mirror `packages/cms-core/src/api/handlers.ts` and `actions.ts`
33
- // (including `contentHash`, `changeType` on versions, scheduling fields, etc.).
34
- //
35
- // ═══════════════════════════════════════════════════════════════════════════════
36
-
37
- enum DocumentStatus {
38
- DRAFT
39
- PUBLISHED
40
- ARCHIVED
41
- SCHEDULED
42
- }
43
-
44
- model User {
45
- id String @id @default(cuid())
46
- email String @unique
47
- name String @default("")
48
- role String @default("EDITOR")
49
- passwordHash String?
50
- isActive Boolean @default(true)
51
- isApproved Boolean @default(false)
52
- emailVerified Boolean @default(false)
53
- totpEnabled Boolean @default(false)
54
- totpSecret String?
55
- /// JSON array of one-time backup codes (e.g. `["abcd-1234", …]`).
56
- backupCodes Json?
57
- oauthProvider String?
58
- oauthId String?
59
- createdAt DateTime @default(now())
60
- updatedAt DateTime @updatedAt
61
-
62
- sessions Session[]
63
- documentsCreated Document[] @relation("DocumentCreatedBy")
64
- documentsUpdated Document[] @relation("DocumentUpdatedBy")
65
- documentsReviewed Document[] @relation("DocumentReviewer")
66
- versions Version[]
67
- mediaUploaded Media[] @relation("MediaUploadedBy")
68
- auditLogs AuditLog[]
69
-
70
- @@index([role])
71
- @@index([isActive])
72
- }
73
-
74
- model Session {
75
- id String @id @default(cuid())
76
- userId String
77
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
78
- /// JWT or opaque session token; optional until first persisted login (e.g. OAuth).
79
- token String? @unique
80
- expiresAt DateTime
81
- revokedAt DateTime?
82
- ipAddress String?
83
- userAgent String?
84
- createdAt DateTime @default(now())
85
-
86
- @@index([userId])
87
- @@index([expiresAt])
88
- }
89
-
90
- model Document {
91
- id String @id @default(cuid())
92
- collection String
93
- slug String?
94
- title String?
95
- data Json
96
- status DocumentStatus @default(DRAFT)
97
- plainText String? @db.Text
98
- locale String?
99
- folderId String?
100
- structuredData Json?
101
- workflowStage String?
102
- reviewerId String?
103
- reviewNote String? @db.Text
104
- publishedAt DateTime?
105
- scheduledAt DateTime?
106
- scheduledUnpublishAt DateTime?
107
- deletedAt DateTime?
108
- contentHash String?
109
- siteId String?
110
- templateId String?
111
- createdById String
112
- updatedById String
113
- createdAt DateTime @default(now())
114
- updatedAt DateTime @updatedAt
115
-
116
- createdBy User @relation("DocumentCreatedBy", fields: [createdById], references: [id], onDelete: Restrict)
117
- updatedBy User @relation("DocumentUpdatedBy", fields: [updatedById], references: [id], onDelete: Restrict)
118
- reviewer User? @relation("DocumentReviewer", fields: [reviewerId], references: [id], onDelete: SetNull)
119
- folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
120
- versions Version[]
121
- formSubmissions FormSubmission[]
122
-
123
- @@unique([collection, slug], name: "collection_slug")
124
- @@index([collection])
125
- @@index([status])
126
- @@index([deletedAt])
127
- @@index([publishedAt])
128
- @@index([folderId])
129
- @@index([locale])
130
- @@index([scheduledAt])
131
- @@index([scheduledUnpublishAt])
132
- @@index([createdById])
133
- @@index([updatedById])
134
- }
135
-
136
- model Media {
137
- id String @id @default(cuid())
138
- filename String
139
- storageKey String @unique
140
- mimeType String
141
- fileSize Int
142
- width Int?
143
- height Int?
144
- altText String?
145
- title String?
146
- blurHash String?
147
- focalPointX Float?
148
- focalPointY Float?
149
- folderId String?
150
- uploadedById String
151
- createdAt DateTime @default(now())
152
- updatedAt DateTime @updatedAt
153
-
154
- uploadedBy User @relation("MediaUploadedBy", fields: [uploadedById], references: [id], onDelete: Restrict)
155
- folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
156
-
157
- @@index([folderId])
158
- @@index([mimeType])
159
- @@index([createdAt])
160
- }
161
-
162
- model Version {
163
- id String @id @default(cuid())
164
- documentId String
165
- document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
166
- data Json
167
- changedById String
168
- changedBy User @relation(fields: [changedById], references: [id], onDelete: Restrict)
169
- /// CREATE | UPDATE | DELETE (see `actions.ts` / workflow).
170
- changeType String @default("UPDATE")
171
- createdAt DateTime @default(now())
172
-
173
- @@index([documentId])
174
- @@index([createdAt])
175
- }
176
-
177
- model Folder {
178
- id String @id @default(cuid())
179
- name String
180
- /// Discriminator for folder trees (e.g. `documents`, `media`).
181
- scope String
182
- parentId String?
183
- position Int @default(0)
184
- createdAt DateTime @default(now())
185
-
186
- parent Folder? @relation("FolderTree", fields: [parentId], references: [id], onDelete: Cascade)
187
- children Folder[] @relation("FolderTree")
188
- documents Document[]
189
- media Media[]
190
-
191
- @@index([scope])
192
- @@index([parentId])
193
- @@index([scope, parentId, position])
194
- }
195
-
196
- model Redirect {
197
- id String @id @default(cuid())
198
- source String
199
- destination String
200
- statusCode Int @default(301)
201
- isRegex Boolean @default(false)
202
- notes String?
203
- createdAt DateTime @default(now())
204
- updatedAt DateTime @updatedAt
205
-
206
- @@unique([source])
207
- @@index([createdAt])
208
- }
209
-
210
- model FormSubmission {
211
- id String @id @default(cuid())
212
- formId String
213
- form Document @relation(fields: [formId], references: [id], onDelete: Cascade)
214
- data Json
215
- attribution Json?
216
- submittedAt DateTime @default(now())
217
- createdAt DateTime @default(now())
218
-
219
- @@index([formId])
220
- @@index([submittedAt])
221
- @@index([createdAt])
222
- }
223
-
224
- model AuditLog {
225
- id String @id @default(cuid())
226
- event String
227
- userId String?
228
- user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
229
- details Json?
230
- ipAddress String?
231
- userAgent String?
232
- createdAt DateTime @default(now())
233
-
234
- @@index([event])
235
- @@index([userId])
236
- @@index([createdAt])
237
- }
238
-
239
- model PasswordResetToken {
240
- id String @id @default(cuid())
241
- userId String
242
- tokenHash String
243
- expiresAt DateTime
244
- usedAt DateTime?
245
- createdAt DateTime @default(now())
246
-
247
- @@index([tokenHash])
248
- @@index([userId])
249
- }
250
-
251
- model MediaUsage {
252
- id String @id @default(cuid())
253
- mediaId String
254
- documentId String
255
- fieldPath String?
256
- createdAt DateTime @default(now())
257
-
258
- @@unique([mediaId, documentId, fieldPath])
259
- @@index([mediaId])
260
- @@index([documentId])
261
- }
262
-
263
- model ScriptTag {
264
- id String @id @default(cuid())
265
- name String
266
- code String @db.Text
267
- placement String
268
- scope String
269
- targetPaths String[]
270
- priority Int @default(100)
271
- enabled Boolean @default(true)
272
- createdAt DateTime @default(now())
273
- updatedAt DateTime @updatedAt
274
-
275
- @@index([enabled])
276
- @@index([placement])
277
- }
278
-
279
- model PageTemplate {
280
- id String @id @default(cuid())
281
- name String
282
- description String?
283
- category String @default("content")
284
- tree Json
285
- thumbnail String?
286
- builtIn Boolean @default(false)
287
- createdAt DateTime @default(now())
288
- updatedAt DateTime @updatedAt
289
-
290
- @@index([category])
291
- @@index([builtIn])
292
- }
293
-
294
- model SavedSection {
295
- id String @id @default(cuid())
296
- name String
297
- description String?
298
- category String @default("content")
299
- tree Json
300
- thumbnail String?
301
- usageCount Int @default(0)
302
- createdAt DateTime @default(now())
303
- updatedAt DateTime @updatedAt
304
-
305
- @@index([category])
306
- }
1
+ // ═══════════════════════════════════════════════════════════════════════════════
2
+ // Actuate CMS — Prisma schema fragment
3
+ // ═══════════════════════════════════════════════════════════════════════════════
4
+ //
5
+ // This file defines the database models expected by `@actuatecms/cms-core` API
6
+ // handlers and server actions. It is a **fragment**: it does not include a
7
+ // `datasource` or `generator` block.
8
+ //
9
+ // ── How to merge into your project ─────────────────────────────────────────────
10
+ //
11
+ // 1. Ensure your root `schema.prisma` uses PostgreSQL, for example:
12
+ // datasource db {
13
+ // provider = "postgresql"
14
+ // url = env("DATABASE_URL")
15
+ // }
16
+ // generator client {
17
+ // provider = "prisma-client-js"
18
+ // output = "../node_modules/.prisma/client"
19
+ // }
20
+ //
21
+ // 2. Copy the `enum` and `model` blocks below into your `schema.prisma` (or use
22
+ // Prisma’s multi-file schema preview: put this file in `prisma/schema/` and
23
+ // include it per Prisma’s multi-file docs).
24
+ //
25
+ // 3. Resolve naming clashes: if you already have a `User` or `Document` model,
26
+ // rename these models and update your Actuate integration to use a custom
27
+ // Prisma client, or map tables with `@@map("…")` and align delegate names.
28
+ //
29
+ // 4. Run migrations:
30
+ // npx prisma migrate dev --name actuate-cms
31
+ //
32
+ // Models mirror `packages/cms-core/src/api/handlers.ts` and `actions.ts`
33
+ // (including `contentHash`, `changeType` on versions, scheduling fields, etc.).
34
+ //
35
+ // ═══════════════════════════════════════════════════════════════════════════════
36
+
37
+ enum DocumentStatus {
38
+ DRAFT
39
+ PUBLISHED
40
+ ARCHIVED
41
+ SCHEDULED
42
+ }
43
+
44
+ model User {
45
+ id String @id @default(cuid())
46
+ email String @unique
47
+ name String @default("")
48
+ role String @default("EDITOR")
49
+ passwordHash String?
50
+ isActive Boolean @default(true)
51
+ isApproved Boolean @default(false)
52
+ emailVerified Boolean @default(false)
53
+ totpEnabled Boolean @default(false)
54
+ totpSecret String?
55
+ /// JSON array of one-time backup codes (e.g. `["abcd-1234", …]`).
56
+ backupCodes Json?
57
+ oauthProvider String?
58
+ oauthId String?
59
+ createdAt DateTime @default(now())
60
+ updatedAt DateTime @updatedAt
61
+
62
+ sessions Session[]
63
+ documentsCreated Document[] @relation("DocumentCreatedBy")
64
+ documentsUpdated Document[] @relation("DocumentUpdatedBy")
65
+ documentsReviewed Document[] @relation("DocumentReviewer")
66
+ versions Version[]
67
+ mediaUploaded Media[] @relation("MediaUploadedBy")
68
+ auditLogs AuditLog[]
69
+
70
+ @@index([role])
71
+ @@index([isActive])
72
+ }
73
+
74
+ model Session {
75
+ id String @id @default(cuid())
76
+ userId String
77
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
78
+ /// JWT or opaque session token; optional until first persisted login (e.g. OAuth).
79
+ token String? @unique
80
+ expiresAt DateTime
81
+ revokedAt DateTime?
82
+ ipAddress String?
83
+ userAgent String?
84
+ createdAt DateTime @default(now())
85
+
86
+ @@index([userId])
87
+ @@index([expiresAt])
88
+ }
89
+
90
+ model Document {
91
+ id String @id @default(cuid())
92
+ collection String
93
+ slug String?
94
+ title String?
95
+ data Json
96
+ status DocumentStatus @default(DRAFT)
97
+ plainText String? @db.Text
98
+ locale String?
99
+ folderId String?
100
+ structuredData Json?
101
+ workflowStage String?
102
+ reviewerId String?
103
+ reviewNote String? @db.Text
104
+ publishedAt DateTime?
105
+ scheduledAt DateTime?
106
+ scheduledUnpublishAt DateTime?
107
+ deletedAt DateTime?
108
+ contentHash String?
109
+ siteId String?
110
+ templateId String?
111
+ createdById String
112
+ updatedById String
113
+ createdAt DateTime @default(now())
114
+ updatedAt DateTime @updatedAt
115
+
116
+ createdBy User @relation("DocumentCreatedBy", fields: [createdById], references: [id], onDelete: Restrict)
117
+ updatedBy User @relation("DocumentUpdatedBy", fields: [updatedById], references: [id], onDelete: Restrict)
118
+ reviewer User? @relation("DocumentReviewer", fields: [reviewerId], references: [id], onDelete: SetNull)
119
+ folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
120
+ versions Version[]
121
+ formSubmissions FormSubmission[]
122
+
123
+ @@unique([collection, slug], name: "collection_slug")
124
+ @@index([collection])
125
+ @@index([status])
126
+ @@index([deletedAt])
127
+ @@index([publishedAt])
128
+ @@index([folderId])
129
+ @@index([locale])
130
+ @@index([scheduledAt])
131
+ @@index([scheduledUnpublishAt])
132
+ @@index([createdById])
133
+ @@index([updatedById])
134
+ }
135
+
136
+ model Media {
137
+ id String @id @default(cuid())
138
+ filename String
139
+ storageKey String @unique
140
+ mimeType String
141
+ fileSize Int
142
+ width Int?
143
+ height Int?
144
+ altText String?
145
+ title String?
146
+ blurHash String?
147
+ focalPointX Float?
148
+ focalPointY Float?
149
+ folderId String?
150
+ uploadedById String
151
+ createdAt DateTime @default(now())
152
+ updatedAt DateTime @updatedAt
153
+
154
+ uploadedBy User @relation("MediaUploadedBy", fields: [uploadedById], references: [id], onDelete: Restrict)
155
+ folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
156
+
157
+ @@index([folderId])
158
+ @@index([mimeType])
159
+ @@index([createdAt])
160
+ }
161
+
162
+ model Version {
163
+ id String @id @default(cuid())
164
+ documentId String
165
+ document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
166
+ data Json
167
+ changedById String
168
+ changedBy User @relation(fields: [changedById], references: [id], onDelete: Restrict)
169
+ /// CREATE | UPDATE | DELETE (see `actions.ts` / workflow).
170
+ changeType String @default("UPDATE")
171
+ createdAt DateTime @default(now())
172
+
173
+ @@index([documentId])
174
+ @@index([createdAt])
175
+ }
176
+
177
+ model Folder {
178
+ id String @id @default(cuid())
179
+ name String
180
+ /// Discriminator for folder trees (e.g. `documents`, `media`).
181
+ scope String
182
+ parentId String?
183
+ position Int @default(0)
184
+ createdAt DateTime @default(now())
185
+
186
+ parent Folder? @relation("FolderTree", fields: [parentId], references: [id], onDelete: Cascade)
187
+ children Folder[] @relation("FolderTree")
188
+ documents Document[]
189
+ media Media[]
190
+
191
+ @@index([scope])
192
+ @@index([parentId])
193
+ @@index([scope, parentId, position])
194
+ }
195
+
196
+ model Redirect {
197
+ id String @id @default(cuid())
198
+ source String
199
+ destination String
200
+ statusCode Int @default(301)
201
+ isRegex Boolean @default(false)
202
+ notes String?
203
+ createdAt DateTime @default(now())
204
+ updatedAt DateTime @updatedAt
205
+
206
+ @@unique([source])
207
+ @@index([createdAt])
208
+ }
209
+
210
+ model FormSubmission {
211
+ id String @id @default(cuid())
212
+ formId String
213
+ form Document @relation(fields: [formId], references: [id], onDelete: Cascade)
214
+ data Json
215
+ attribution Json?
216
+ submittedAt DateTime @default(now())
217
+ createdAt DateTime @default(now())
218
+
219
+ @@index([formId])
220
+ @@index([submittedAt])
221
+ @@index([createdAt])
222
+ }
223
+
224
+ model AuditLog {
225
+ id String @id @default(cuid())
226
+ event String
227
+ userId String?
228
+ user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
229
+ details Json?
230
+ ipAddress String?
231
+ userAgent String?
232
+ createdAt DateTime @default(now())
233
+
234
+ @@index([event])
235
+ @@index([userId])
236
+ @@index([createdAt])
237
+ }
238
+
239
+ model PasswordResetToken {
240
+ id String @id @default(cuid())
241
+ userId String
242
+ tokenHash String
243
+ expiresAt DateTime
244
+ usedAt DateTime?
245
+ createdAt DateTime @default(now())
246
+
247
+ @@index([tokenHash])
248
+ @@index([userId])
249
+ }
250
+
251
+ model MediaUsage {
252
+ id String @id @default(cuid())
253
+ mediaId String
254
+ documentId String
255
+ fieldPath String?
256
+ createdAt DateTime @default(now())
257
+
258
+ @@unique([mediaId, documentId, fieldPath])
259
+ @@index([mediaId])
260
+ @@index([documentId])
261
+ }
262
+
263
+ model ScriptTag {
264
+ id String @id @default(cuid())
265
+ name String
266
+ code String @db.Text
267
+ placement String
268
+ scope String
269
+ targetPaths String[]
270
+ priority Int @default(100)
271
+ enabled Boolean @default(true)
272
+ createdAt DateTime @default(now())
273
+ updatedAt DateTime @updatedAt
274
+
275
+ @@index([enabled])
276
+ @@index([placement])
277
+ }
278
+
279
+ model PageTemplate {
280
+ id String @id @default(cuid())
281
+ name String
282
+ description String?
283
+ category String @default("content")
284
+ tree Json
285
+ thumbnail String?
286
+ builtIn Boolean @default(false)
287
+ createdAt DateTime @default(now())
288
+ updatedAt DateTime @updatedAt
289
+
290
+ @@index([category])
291
+ @@index([builtIn])
292
+ }
293
+
294
+ model SavedSection {
295
+ id String @id @default(cuid())
296
+ name String
297
+ description String?
298
+ category String @default("content")
299
+ tree Json
300
+ thumbnail String?
301
+ usageCount Int @default(0)
302
+ createdAt DateTime @default(now())
303
+ updatedAt DateTime @updatedAt
304
+
305
+ @@index([category])
306
+ }