@studious-lms/server 1.4.9 → 1.5.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/dist/lib/config/cors.d.ts.map +1 -1
- package/dist/lib/config/cors.js +2 -4
- package/dist/lib/config/cors.js.map +1 -1
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +4 -5
- package/dist/lib/fileUpload.js.map +1 -1
- package/dist/models/auth.d.ts +1 -0
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +3 -2
- package/dist/models/auth.js.map +1 -1
- package/dist/models/comment.d.ts +0 -5
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/conversation.d.ts +2 -1
- package/dist/models/conversation.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +2 -1
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/message.d.ts +6 -3
- package/dist/models/message.d.ts.map +1 -1
- package/dist/models/school.d.ts +0 -22
- package/dist/models/school.d.ts.map +1 -1
- package/dist/models/school.js +2 -14
- package/dist/models/school.js.map +1 -1
- package/dist/models/worksheet.d.ts +76 -19
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/models/worksheet.js +2 -2
- package/dist/models/worksheet.js.map +1 -1
- package/dist/pipelines/aiLabChat.js +6 -6
- package/dist/pipelines/aiLabChat.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts +5 -3
- package/dist/pipelines/gradeWorksheet.d.ts.map +1 -1
- package/dist/pipelines/gradeWorksheet.js +60 -24
- package/dist/pipelines/gradeWorksheet.js.map +1 -1
- package/dist/pipelines/pdfToWorksheet.d.ts +3 -0
- package/dist/pipelines/pdfToWorksheet.d.ts.map +1 -1
- package/dist/pipelines/pdfToWorksheet.js +65 -24
- package/dist/pipelines/pdfToWorksheet.js.map +1 -1
- package/dist/routers/_app.d.ts +92 -48
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/announcement.d.ts +0 -4
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/assignment.d.ts +0 -8
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/auth.d.ts +1 -0
- package/dist/routers/auth.d.ts.map +1 -1
- package/dist/routers/comment.d.ts +0 -3
- package/dist/routers/comment.d.ts.map +1 -1
- package/dist/routers/conversation.d.ts +2 -1
- package/dist/routers/conversation.d.ts.map +1 -1
- package/dist/routers/labChat.d.ts +2 -1
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/school.d.ts +6 -0
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/school.js +7 -2
- package/dist/routers/school.js.map +1 -1
- package/dist/routers/worksheet.d.ts +35 -7
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/services/auth.d.ts +1 -0
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/comment.d.ts +0 -3
- package/dist/services/comment.d.ts.map +1 -1
- package/dist/services/conversation.d.ts +2 -1
- package/dist/services/conversation.d.ts.map +1 -1
- package/dist/services/labChat.d.ts +2 -1
- package/dist/services/labChat.d.ts.map +1 -1
- package/dist/services/labChat.js +6 -6
- package/dist/services/labChat.js.map +1 -1
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +14 -2
- package/dist/services/message.js.map +1 -1
- package/dist/services/school.d.ts +6 -0
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/school.js +71 -6
- package/dist/services/school.js.map +1 -1
- package/dist/services/worksheet.d.ts +35 -7
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/services/worksheet.js +17 -19
- package/dist/services/worksheet.js.map +1 -1
- package/dist/utils/generateUsername.d.ts +8 -0
- package/dist/utils/generateUsername.d.ts.map +1 -0
- package/dist/utils/generateUsername.js +103 -0
- package/dist/utils/generateUsername.js.map +1 -0
- package/dist/workers/connection.d.ts +3 -0
- package/dist/workers/connection.d.ts.map +1 -0
- package/dist/workers/connection.js +33 -0
- package/dist/workers/connection.js.map +1 -0
- package/dist/workers/index.d.ts +10 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +53 -0
- package/dist/workers/index.js.map +1 -0
- package/dist/workers/processors/pdfToWorksheet.d.ts +9 -0
- package/dist/workers/processors/pdfToWorksheet.d.ts.map +1 -0
- package/dist/workers/processors/pdfToWorksheet.js +100 -0
- package/dist/workers/processors/pdfToWorksheet.js.map +1 -0
- package/dist/workers/queues.d.ts +69 -0
- package/dist/workers/queues.d.ts.map +1 -0
- package/dist/workers/queues.js +119 -0
- package/dist/workers/queues.js.map +1 -0
- package/package.json +4 -1
- package/prisma/migrations/20260506162500_consolidate_run_job_and_unify_job_status/migration.sql +166 -0
- package/prisma/schema.prisma +465 -387
- package/src/lib/config/cors.ts +0 -2
- package/src/lib/fileUpload.ts +2 -4
- package/src/models/auth.ts +1 -0
- package/src/models/school.ts +0 -14
- package/src/models/worksheet.ts +2 -2
- package/src/pipelines/aiLabChat.ts +4 -4
- package/src/pipelines/gradeWorksheet.ts +63 -25
- package/src/pipelines/pdfToWorksheet.ts +68 -22
- package/src/routers/school.ts +5 -0
- package/src/services/labChat.ts +4 -4
- package/src/services/message.ts +13 -0
- package/src/services/school.ts +89 -6
- package/src/services/worksheet.ts +16 -18
- package/src/utils/generateUsername.ts +108 -0
- package/src/workers/connection.ts +37 -0
- package/src/workers/index.ts +61 -0
- package/src/workers/processors/pdfToWorksheet.ts +119 -0
- package/src/workers/queues.ts +159 -0
- package/tests/{globalSetup.ts → integration/globalSetup.ts} +4 -4
- package/tests/{helpers.ts → integration/helpers.ts} +2 -2
- package/tests/{pipelines → integration/pipelines}/pdfToWorksheet.test.ts +55 -43
- package/tests/{routers → integration/routers}/attendance.test.ts +1 -1
- package/tests/{routers → integration/routers}/auth.test.ts +3 -3
- package/tests/{routers → integration/routers}/class.test.ts +3 -17
- package/tests/{routers → integration/routers}/conversation.test.ts +1 -1
- package/tests/{routers → integration/routers}/event.test.ts +1 -1
- package/tests/{routers → integration/routers}/message.test.ts +1 -1
- package/tests/{routers → integration/routers}/newtonChat.test.ts +1 -1
- package/tests/{routers → integration/routers}/studentProgress.test.ts +1 -1
- package/tests/{user.test.ts → integration/routers/user.test.ts} +2 -2
- package/tests/integration/routers/worksheet.test.ts +448 -0
- package/tests/{setup.ts → integration/setup.ts} +4 -4
- package/tests/{lib → unit/lib}/cors.test.ts +1 -1
- package/tests/{middleware → unit/middleware}/security.test.ts +1 -1
- package/tests/{pipelines → unit/pipelines}/aiLabChat.test.ts +1 -1
- package/tests/{lib → unit/pipelines}/aiLabChatContract.test.ts +1 -1
- package/tests/{utils/aiLabChatPrompt.test.ts → unit/pipelines/labChatPrompt.test.ts} +2 -2
- package/tests/{utils → unit/services}/studentProgress.test.ts +5 -5
- package/tests/{utils → unit/utils}/aiUser.test.ts +1 -1
- package/tests/{utils → unit/utils}/generateInviteCode.test.ts +1 -1
- package/tests/{utils → unit/utils}/inference.test.ts +6 -6
- package/tests/{utils → unit/utils}/logger.test.ts +1 -1
- package/tests/{utils → unit/utils}/prismaErrorHandler.test.ts +1 -1
- package/tests/{utils → unit/utils}/prismaWrapper.test.ts +1 -1
- package/vitest.config.ts +11 -3
- package/vitest.unit.config.ts +10 -10
- package/tests/routers/worksheet.test.ts +0 -194
- package/tests/startup.test.ts +0 -5
- package/tests/worksheet.test.ts +0 -181
- /package/tests/{routers → integration/routers}/agenda.test.ts +0 -0
- /package/tests/{routers → integration/routers}/announcement.test.ts +0 -0
- /package/tests/{routers → integration/routers}/assignment.test.ts +0 -0
- /package/tests/{routers → integration/routers}/comment.test.ts +0 -0
- /package/tests/{routers → integration/routers}/folder.test.ts +0 -0
- /package/tests/{routers → integration/routers}/labChat.test.ts +0 -0
- /package/tests/{routers → integration/routers}/marketing.test.ts +0 -0
- /package/tests/{routers → integration/routers}/notification.test.ts +0 -0
- /package/tests/{routers → integration/routers}/search.test.ts +0 -0
- /package/tests/{routers → integration/routers}/section.test.ts +0 -0
- /package/tests/{server → unit/middleware}/rateLimit.test.ts +0 -0
package/prisma/schema.prisma
CHANGED
|
@@ -15,8 +15,8 @@ generator client {
|
|
|
15
15
|
// }
|
|
16
16
|
|
|
17
17
|
datasource db {
|
|
18
|
-
provider
|
|
19
|
-
url
|
|
18
|
+
provider = "postgresql"
|
|
19
|
+
url = env("DATABASE_URL")
|
|
20
20
|
directUrl = env("DIRECT_URL")
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -47,10 +47,20 @@ enum UploadStatus {
|
|
|
47
47
|
CANCELLED
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
/// UI-shaped status shared by every domain row that has an async/AI lifecycle
|
|
51
|
+
/// the user can observe (chat messages, AI grading, etc.).
|
|
52
|
+
///
|
|
53
|
+
/// Not every row uses every value — e.g. a Message never goes to NOT_STARTED
|
|
54
|
+
/// (the row doesn't exist until the message is sent) or CANCELLED (the app
|
|
55
|
+
/// doesn't cancel chat replies mid-flight). The full set lives here so a
|
|
56
|
+
/// single enum can serve every UI surface.
|
|
57
|
+
///
|
|
58
|
+
/// For the queue-internal lifecycle (PENDING / RUNNING / SUCCEEDED) see
|
|
59
|
+
/// RunJobStatus — those names matter operationally and shouldn't be mixed
|
|
60
|
+
/// in here.
|
|
61
|
+
enum JobStatus {
|
|
51
62
|
NOT_STARTED
|
|
52
63
|
PENDING
|
|
53
|
-
GENERATING
|
|
54
64
|
COMPLETED
|
|
55
65
|
FAILED
|
|
56
66
|
CANCELLED
|
|
@@ -101,15 +111,14 @@ enum SchoolInviteStatus {
|
|
|
101
111
|
}
|
|
102
112
|
|
|
103
113
|
model School {
|
|
104
|
-
id
|
|
105
|
-
name
|
|
106
|
-
logo
|
|
107
|
-
logoId
|
|
108
|
-
subdomain
|
|
109
|
-
createdAt
|
|
110
|
-
updatedAt
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
id String @id @default(uuid())
|
|
115
|
+
name String
|
|
116
|
+
logo File? @relation(references: [id], fields: [logoId])
|
|
117
|
+
logoId String?
|
|
118
|
+
subdomain String? @unique
|
|
119
|
+
createdAt DateTime @default(now())
|
|
120
|
+
updatedAt DateTime @updatedAt
|
|
121
|
+
|
|
113
122
|
users User[]
|
|
114
123
|
memberships SchoolMembership[]
|
|
115
124
|
invites SchoolInvite[]
|
|
@@ -117,46 +126,45 @@ model School {
|
|
|
117
126
|
}
|
|
118
127
|
|
|
119
128
|
model User {
|
|
120
|
-
id
|
|
121
|
-
username
|
|
122
|
-
email
|
|
123
|
-
password
|
|
124
|
-
profile
|
|
125
|
-
verified
|
|
126
|
-
role
|
|
127
|
-
|
|
128
|
-
teacherIn
|
|
129
|
-
studentIn
|
|
130
|
-
|
|
131
|
-
submissions
|
|
132
|
-
sessions
|
|
133
|
-
files
|
|
134
|
-
assignments
|
|
135
|
-
specificAssignments
|
|
136
|
-
events
|
|
137
|
-
announcements
|
|
138
|
-
notificationsSent
|
|
139
|
-
notificationsReceived
|
|
140
|
-
studentQuestionProgress
|
|
129
|
+
id String @id @default(uuid())
|
|
130
|
+
username String
|
|
131
|
+
email String
|
|
132
|
+
password String
|
|
133
|
+
profile UserProfile?
|
|
134
|
+
verified Boolean @default(false)
|
|
135
|
+
role UserRole @default(NONE)
|
|
136
|
+
|
|
137
|
+
teacherIn Class[] @relation("UserTeacherToClass")
|
|
138
|
+
studentIn Class[] @relation("UserStudentToClass")
|
|
139
|
+
|
|
140
|
+
submissions Submission[]
|
|
141
|
+
sessions Session[]
|
|
142
|
+
files File[]
|
|
143
|
+
assignments Assignment[]
|
|
144
|
+
specificAssignments Assignment[] @relation("SpecificAssignmentAssignedTo")
|
|
145
|
+
events Event[]
|
|
146
|
+
announcements Announcement[]
|
|
147
|
+
notificationsSent Notification[] @relation("SentNotifications")
|
|
148
|
+
notificationsReceived Notification[] @relation("ReceivedNotifications")
|
|
149
|
+
studentQuestionProgress StudentQuestionProgress[]
|
|
141
150
|
studentWorksheetResponses StudentWorksheetResponse[]
|
|
142
151
|
|
|
143
|
-
presentAttendance
|
|
152
|
+
presentAttendance Attendance[] @relation("PresentAttendance")
|
|
144
153
|
lateAttendance Attendance[] @relation("LateAttendance")
|
|
145
154
|
absentAttendance Attendance[] @relation("AbsentAttendance")
|
|
146
155
|
|
|
147
|
-
school
|
|
148
|
-
schoolId
|
|
156
|
+
school School? @relation(fields: [schoolId], references: [id])
|
|
157
|
+
schoolId String?
|
|
149
158
|
schoolMemberships SchoolMembership[]
|
|
150
|
-
sentSchoolInvites SchoolInvite[]
|
|
159
|
+
sentSchoolInvites SchoolInvite[] @relation("SchoolInviteInvitedBy")
|
|
151
160
|
|
|
152
161
|
// Chat relations
|
|
153
162
|
conversationMemberships ConversationMember[]
|
|
154
|
-
sentMessages
|
|
155
|
-
mentions
|
|
156
|
-
createdLabChats
|
|
157
|
-
comments
|
|
158
|
-
reactions
|
|
159
|
-
|
|
163
|
+
sentMessages Message[] @relation("SentMessages")
|
|
164
|
+
mentions Mention[] @relation("UserMentions")
|
|
165
|
+
createdLabChats LabChat[] @relation("CreatedLabChats")
|
|
166
|
+
comments Comment[]
|
|
167
|
+
reactions Reaction[]
|
|
160
168
|
}
|
|
161
169
|
|
|
162
170
|
model SchoolMembership {
|
|
@@ -178,230 +186,227 @@ model SchoolMembership {
|
|
|
178
186
|
}
|
|
179
187
|
|
|
180
188
|
model SchoolInvite {
|
|
181
|
-
id
|
|
182
|
-
token
|
|
183
|
-
email
|
|
184
|
-
role
|
|
185
|
-
status
|
|
186
|
-
expiresAt
|
|
187
|
-
acceptedAt
|
|
188
|
-
revokedAt
|
|
189
|
-
createdAt
|
|
190
|
-
updatedAt
|
|
189
|
+
id String @id @default(uuid())
|
|
190
|
+
token String @unique
|
|
191
|
+
email String
|
|
192
|
+
role SchoolMembershipRole
|
|
193
|
+
status SchoolInviteStatus @default(PENDING)
|
|
194
|
+
expiresAt DateTime
|
|
195
|
+
acceptedAt DateTime?
|
|
196
|
+
revokedAt DateTime?
|
|
197
|
+
createdAt DateTime @default(now())
|
|
198
|
+
updatedAt DateTime @updatedAt
|
|
191
199
|
|
|
192
200
|
schoolId String
|
|
193
|
-
school School
|
|
201
|
+
school School @relation(fields: [schoolId], references: [id], onDelete: Cascade)
|
|
194
202
|
invitedById String
|
|
195
|
-
invitedBy User
|
|
203
|
+
invitedBy User @relation("SchoolInviteInvitedBy", fields: [invitedById], references: [id], onDelete: Cascade)
|
|
196
204
|
|
|
197
205
|
@@index([schoolId, status])
|
|
198
206
|
@@index([email])
|
|
199
207
|
}
|
|
200
208
|
|
|
201
209
|
model UserProfile {
|
|
202
|
-
id
|
|
210
|
+
id String @id @default(uuid())
|
|
203
211
|
userId String @unique
|
|
204
|
-
user
|
|
205
|
-
|
|
206
|
-
displayName
|
|
207
|
-
bio
|
|
208
|
-
location
|
|
209
|
-
website
|
|
210
|
-
profilePicture
|
|
212
|
+
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
213
|
+
|
|
214
|
+
displayName String?
|
|
215
|
+
bio String?
|
|
216
|
+
location String?
|
|
217
|
+
website String?
|
|
218
|
+
profilePicture String?
|
|
211
219
|
profilePictureThumbnail String?
|
|
212
|
-
|
|
220
|
+
|
|
213
221
|
createdAt DateTime @default(now())
|
|
214
222
|
updatedAt DateTime @updatedAt
|
|
215
|
-
}
|
|
223
|
+
}
|
|
216
224
|
|
|
217
225
|
model Class {
|
|
218
|
-
id
|
|
219
|
-
name
|
|
220
|
-
subject
|
|
221
|
-
color
|
|
222
|
-
section
|
|
223
|
-
syllabus
|
|
224
|
-
announcements
|
|
225
|
-
assignments
|
|
226
|
-
attendance
|
|
227
|
-
events
|
|
228
|
-
sections
|
|
229
|
-
sessions
|
|
230
|
-
worksheets
|
|
231
|
-
students
|
|
232
|
-
teachers
|
|
226
|
+
id String @id @default(uuid())
|
|
227
|
+
name String
|
|
228
|
+
subject String
|
|
229
|
+
color String? @default("#3B82F6")
|
|
230
|
+
section String
|
|
231
|
+
syllabus String?
|
|
232
|
+
announcements Announcement[]
|
|
233
|
+
assignments Assignment[]
|
|
234
|
+
attendance Attendance[]
|
|
235
|
+
events Event[]
|
|
236
|
+
sections Section[]
|
|
237
|
+
sessions Session[]
|
|
238
|
+
worksheets Worksheet[]
|
|
239
|
+
students User[] @relation("UserStudentToClass")
|
|
240
|
+
teachers User[] @relation("UserTeacherToClass")
|
|
233
241
|
// markSchemes MarkScheme[] @relation("ClassToMarkScheme")
|
|
234
242
|
// gradingBoundaries GradingBoundary[] @relation("ClassToGradingBoundary")
|
|
235
|
-
draftFiles
|
|
236
|
-
classFiles
|
|
237
|
-
labChats
|
|
238
|
-
markSchemes
|
|
243
|
+
draftFiles File[] @relation("ClassDraftFiles")
|
|
244
|
+
classFiles Folder? @relation("ClassFiles")
|
|
245
|
+
labChats LabChat[] @relation("ClassLabChats")
|
|
246
|
+
markSchemes MarkScheme[]
|
|
239
247
|
gradingBoundaries GradingBoundary[]
|
|
240
|
-
school
|
|
241
|
-
schoolId
|
|
248
|
+
school School? @relation(fields: [schoolId], references: [id])
|
|
249
|
+
schoolId String?
|
|
242
250
|
}
|
|
243
251
|
|
|
244
252
|
model MarkScheme {
|
|
245
|
-
id
|
|
246
|
-
classId
|
|
253
|
+
id String @id @default(uuid())
|
|
254
|
+
classId String
|
|
247
255
|
// class Class[] @relation("ClassToMarkScheme")
|
|
248
|
-
class
|
|
249
|
-
structured
|
|
256
|
+
class Class? @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
257
|
+
structured String
|
|
250
258
|
assignments Assignment[]
|
|
251
259
|
}
|
|
252
260
|
|
|
253
261
|
model GradingBoundary {
|
|
254
|
-
id
|
|
255
|
-
classId
|
|
262
|
+
id String @id @default(uuid())
|
|
263
|
+
classId String
|
|
256
264
|
// class Class[] @relation("ClassToGradingBoundary")
|
|
257
|
-
class
|
|
258
|
-
structured
|
|
265
|
+
class Class? @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
266
|
+
structured String
|
|
259
267
|
assignments Assignment[]
|
|
260
268
|
}
|
|
261
269
|
|
|
262
270
|
model Folder {
|
|
263
|
-
id
|
|
264
|
-
name
|
|
265
|
-
files
|
|
266
|
-
childFolders
|
|
267
|
-
parentFolder
|
|
271
|
+
id String @id @default(uuid())
|
|
272
|
+
name String
|
|
273
|
+
files File[] @relation("FolderFiles")
|
|
274
|
+
childFolders Folder[] @relation("ParentChildFolders")
|
|
275
|
+
parentFolder Folder? @relation("ParentChildFolders", fields: [parentFolderId], references: [id])
|
|
268
276
|
parentFolderId String?
|
|
269
|
-
color
|
|
270
|
-
class
|
|
271
|
-
classId
|
|
277
|
+
color String? @default("#3B82F6")
|
|
278
|
+
class Class? @relation("ClassFiles", fields: [classId], references: [id])
|
|
279
|
+
classId String? @unique
|
|
272
280
|
}
|
|
273
281
|
|
|
274
282
|
model File {
|
|
275
|
-
id String
|
|
283
|
+
id String @id @default(uuid())
|
|
276
284
|
name String
|
|
277
285
|
path String
|
|
278
286
|
size Int?
|
|
279
287
|
type String
|
|
280
|
-
user User?
|
|
288
|
+
user User? @relation(fields: [userId], references: [id])
|
|
281
289
|
userId String?
|
|
282
290
|
uploadedAt DateTime? @default(now())
|
|
283
291
|
|
|
284
292
|
// Upload tracking fields
|
|
285
|
-
uploadStatus
|
|
286
|
-
uploadUrl
|
|
287
|
-
uploadExpiresAt
|
|
288
|
-
uploadSessionId
|
|
289
|
-
uploadProgress
|
|
290
|
-
uploadError
|
|
291
|
-
uploadRetryCount Int
|
|
292
|
-
isOrphaned
|
|
293
|
-
cleanupAt
|
|
293
|
+
uploadStatus UploadStatus @default(PENDING)
|
|
294
|
+
uploadUrl String?
|
|
295
|
+
uploadExpiresAt DateTime?
|
|
296
|
+
uploadSessionId String?
|
|
297
|
+
uploadProgress Int?
|
|
298
|
+
uploadError String?
|
|
299
|
+
uploadRetryCount Int @default(0)
|
|
300
|
+
isOrphaned Boolean @default(false)
|
|
301
|
+
cleanupAt DateTime?
|
|
294
302
|
|
|
295
303
|
// Thumbnail relationship
|
|
296
|
-
thumbnail
|
|
297
|
-
thumbnailId
|
|
298
|
-
originalFile File?
|
|
304
|
+
thumbnail File? @relation("Thumbnail", fields: [thumbnailId], references: [id])
|
|
305
|
+
thumbnailId String? @unique
|
|
306
|
+
originalFile File? @relation("Thumbnail")
|
|
299
307
|
|
|
300
|
-
assignment
|
|
308
|
+
assignment Assignment? @relation(fields: [assignmentId], references: [id], onDelete: Cascade)
|
|
301
309
|
assignmentId String?
|
|
302
310
|
|
|
303
|
-
submission
|
|
311
|
+
submission Submission? @relation("SubmissionFile", fields: [submissionId], references: [id], onDelete: Cascade)
|
|
304
312
|
submissionId String?
|
|
305
313
|
|
|
306
|
-
annotations
|
|
314
|
+
annotations Submission? @relation("SubmissionAnnotations", fields: [annotationId], references: [id], onDelete: Cascade)
|
|
307
315
|
annotationId String?
|
|
308
316
|
|
|
309
|
-
classDraft
|
|
317
|
+
classDraft Class? @relation("ClassDraftFiles", fields: [classDraftId], references: [id], onDelete: Cascade)
|
|
310
318
|
classDraftId String?
|
|
311
319
|
|
|
312
|
-
folder
|
|
320
|
+
folder Folder? @relation("FolderFiles", fields: [folderId], references: [id], onDelete: Cascade)
|
|
313
321
|
folderId String?
|
|
314
322
|
|
|
315
323
|
conversationId String?
|
|
316
324
|
|
|
317
325
|
messageId String?
|
|
318
|
-
message
|
|
326
|
+
message Message? @relation("MessageAttachments", fields: [messageId], references: [id], onDelete: Cascade)
|
|
319
327
|
|
|
320
|
-
announcement
|
|
328
|
+
announcement Announcement? @relation("AnnouncementAttachments", fields: [announcementId], references: [id], onDelete: Cascade)
|
|
321
329
|
announcementId String?
|
|
322
330
|
|
|
323
|
-
schools
|
|
331
|
+
schools School[]
|
|
324
332
|
|
|
325
|
-
schoolDevelopementProgram
|
|
333
|
+
schoolDevelopementProgram SchoolDevelopementProgram? @relation("SchoolDevelopementProgramSupportingDocumentation", fields: [schoolDevelopementProgramId], references: [id], onDelete: Cascade)
|
|
326
334
|
schoolDevelopementProgramId String?
|
|
327
335
|
}
|
|
328
336
|
|
|
329
337
|
model Assignment {
|
|
330
|
-
id
|
|
331
|
-
title
|
|
332
|
-
instructions
|
|
333
|
-
dueDate
|
|
334
|
-
createdAt
|
|
335
|
-
modifiedAt
|
|
336
|
-
teacher
|
|
337
|
-
teacherId
|
|
338
|
-
class
|
|
339
|
-
classId
|
|
340
|
-
attachments
|
|
341
|
-
acceptFiles
|
|
342
|
-
acceptExtendedResponse Boolean
|
|
343
|
-
acceptWorksheet
|
|
344
|
-
gradeWithAI
|
|
338
|
+
id String @id @default(uuid())
|
|
339
|
+
title String
|
|
340
|
+
instructions String
|
|
341
|
+
dueDate DateTime
|
|
342
|
+
createdAt DateTime? @default(now())
|
|
343
|
+
modifiedAt DateTime? @updatedAt
|
|
344
|
+
teacher User @relation(fields: [teacherId], references: [id], onDelete: NoAction)
|
|
345
|
+
teacherId String
|
|
346
|
+
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
347
|
+
classId String
|
|
348
|
+
attachments File[]
|
|
349
|
+
acceptFiles Boolean @default(false)
|
|
350
|
+
acceptExtendedResponse Boolean @default(false)
|
|
351
|
+
acceptWorksheet Boolean @default(false)
|
|
352
|
+
gradeWithAI Boolean @default(false)
|
|
345
353
|
|
|
346
354
|
aiPolicyLevel Int @default(0)
|
|
347
355
|
|
|
348
|
-
submissions
|
|
349
|
-
comments
|
|
350
|
-
assignedTo
|
|
351
|
-
section
|
|
352
|
-
sectionId
|
|
353
|
-
graded
|
|
354
|
-
maxGrade
|
|
355
|
-
weight
|
|
356
|
-
type
|
|
357
|
-
inProgress
|
|
358
|
-
template
|
|
359
|
-
eventAttached
|
|
360
|
-
eventId
|
|
361
|
-
markScheme
|
|
362
|
-
markSchemeId
|
|
363
|
-
order
|
|
364
|
-
gradingBoundary
|
|
365
|
-
gradingBoundaryId
|
|
366
|
-
worksheets
|
|
367
|
-
targetedBySubmissions Submission[]
|
|
356
|
+
submissions Submission[]
|
|
357
|
+
comments Comment[] @relation("AssignmentComments")
|
|
358
|
+
assignedTo User[] @relation("SpecificAssignmentAssignedTo")
|
|
359
|
+
section Section? @relation(fields: [sectionId], references: [id], onDelete: Cascade)
|
|
360
|
+
sectionId String?
|
|
361
|
+
graded Boolean @default(false)
|
|
362
|
+
maxGrade Int? @default(0)
|
|
363
|
+
weight Float @default(1)
|
|
364
|
+
type AssignmentType @default(HOMEWORK)
|
|
365
|
+
inProgress Boolean @default(false)
|
|
366
|
+
template Boolean @default(false)
|
|
367
|
+
eventAttached Event? @relation(fields: [eventId], references: [id], onDelete: NoAction)
|
|
368
|
+
eventId String?
|
|
369
|
+
markScheme MarkScheme? @relation(fields: [markSchemeId], references: [id], onDelete: Cascade)
|
|
370
|
+
markSchemeId String?
|
|
371
|
+
order Int?
|
|
372
|
+
gradingBoundary GradingBoundary? @relation(fields: [gradingBoundaryId], references: [id], onDelete: Cascade)
|
|
373
|
+
gradingBoundaryId String?
|
|
374
|
+
worksheets Worksheet[] @relation("AssignmentWorksheets")
|
|
375
|
+
targetedBySubmissions Submission[] @relation("SubmissionTargetedAssignment")
|
|
368
376
|
}
|
|
369
377
|
|
|
370
|
-
|
|
371
|
-
|
|
372
378
|
model Announcement {
|
|
373
|
-
id
|
|
374
|
-
remarks
|
|
375
|
-
teacher
|
|
376
|
-
teacherId
|
|
377
|
-
createdAt
|
|
378
|
-
modifiedAt
|
|
379
|
-
class
|
|
380
|
-
classId
|
|
381
|
-
attachments File[]
|
|
382
|
-
comments
|
|
383
|
-
reactions
|
|
379
|
+
id String @id @default(uuid())
|
|
380
|
+
remarks String
|
|
381
|
+
teacher User @relation(fields: [teacherId], references: [id])
|
|
382
|
+
teacherId String
|
|
383
|
+
createdAt DateTime @default(now())
|
|
384
|
+
modifiedAt DateTime? @updatedAt
|
|
385
|
+
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
386
|
+
classId String
|
|
387
|
+
attachments File[] @relation("AnnouncementAttachments")
|
|
388
|
+
comments Comment[]
|
|
389
|
+
reactions Reaction[]
|
|
384
390
|
}
|
|
385
391
|
|
|
386
392
|
model Comment {
|
|
387
|
-
id
|
|
388
|
-
content
|
|
389
|
-
author
|
|
390
|
-
authorId
|
|
391
|
-
announcement
|
|
392
|
-
announcementId
|
|
393
|
-
assignment
|
|
394
|
-
assignmentId
|
|
395
|
-
submission
|
|
396
|
-
submissionId
|
|
397
|
-
parentComment
|
|
398
|
-
parentCommentId
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
studentQuestionProgress StudentQuestionProgress? @relation("StudentQuestionProgressComments", fields: [studentQuestionProgressId], references: [id], onDelete: Cascade)
|
|
393
|
+
id String @id @default(uuid())
|
|
394
|
+
content String
|
|
395
|
+
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
|
396
|
+
authorId String
|
|
397
|
+
announcement Announcement? @relation(fields: [announcementId], references: [id], onDelete: Cascade)
|
|
398
|
+
announcementId String?
|
|
399
|
+
assignment Assignment? @relation("AssignmentComments", fields: [assignmentId], references: [id], onDelete: Cascade)
|
|
400
|
+
assignmentId String?
|
|
401
|
+
submission Submission? @relation("SubmissionComments", fields: [submissionId], references: [id], onDelete: Cascade)
|
|
402
|
+
submissionId String?
|
|
403
|
+
parentComment Comment? @relation("CommentReplies", fields: [parentCommentId], references: [id], onDelete: Cascade)
|
|
404
|
+
parentCommentId String?
|
|
405
|
+
replies Comment[] @relation("CommentReplies")
|
|
406
|
+
reactions Reaction[]
|
|
407
|
+
createdAt DateTime @default(now())
|
|
408
|
+
modifiedAt DateTime? @updatedAt
|
|
409
|
+
studentQuestionProgress StudentQuestionProgress? @relation("StudentQuestionProgressComments", fields: [studentQuestionProgressId], references: [id], onDelete: Cascade)
|
|
405
410
|
studentQuestionProgressId String?
|
|
406
411
|
|
|
407
412
|
@@index([assignmentId])
|
|
@@ -409,16 +414,16 @@ model Comment {
|
|
|
409
414
|
}
|
|
410
415
|
|
|
411
416
|
model Reaction {
|
|
412
|
-
id
|
|
413
|
-
type
|
|
414
|
-
user
|
|
415
|
-
userId
|
|
416
|
-
announcement
|
|
417
|
+
id String @id @default(uuid())
|
|
418
|
+
type ReactionType
|
|
419
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
420
|
+
userId String
|
|
421
|
+
announcement Announcement? @relation(fields: [announcementId], references: [id], onDelete: Cascade)
|
|
417
422
|
announcementId String?
|
|
418
|
-
comment
|
|
419
|
-
commentId
|
|
420
|
-
createdAt
|
|
421
|
-
|
|
423
|
+
comment Comment? @relation(fields: [commentId], references: [id], onDelete: Cascade)
|
|
424
|
+
commentId String?
|
|
425
|
+
createdAt DateTime @default(now())
|
|
426
|
+
|
|
422
427
|
@@unique([userId, announcementId])
|
|
423
428
|
@@unique([userId, commentId])
|
|
424
429
|
@@index([announcementId])
|
|
@@ -426,57 +431,57 @@ model Reaction {
|
|
|
426
431
|
}
|
|
427
432
|
|
|
428
433
|
model Submission {
|
|
429
|
-
id
|
|
430
|
-
createdAt
|
|
434
|
+
id String @id @default(uuid())
|
|
435
|
+
createdAt DateTime @default(now())
|
|
431
436
|
modifiedAt DateTime @default(now())
|
|
432
437
|
|
|
433
|
-
assignment
|
|
438
|
+
assignment Assignment @relation(fields: [assignmentId], references: [id], onDelete: Cascade)
|
|
434
439
|
assignmentId String
|
|
435
440
|
|
|
436
|
-
student
|
|
441
|
+
student User @relation(fields: [studentId], references: [id])
|
|
437
442
|
studentId String
|
|
438
443
|
|
|
439
|
-
attachments
|
|
440
|
-
annotations
|
|
441
|
-
comments
|
|
442
|
-
worksheetResponses
|
|
443
|
-
extendedResponse
|
|
444
|
-
gradeReceived
|
|
445
|
-
recommendationState
|
|
444
|
+
attachments File[] @relation("SubmissionFile")
|
|
445
|
+
annotations File[] @relation("SubmissionAnnotations")
|
|
446
|
+
comments Comment[] @relation("SubmissionComments")
|
|
447
|
+
worksheetResponses StudentWorksheetResponse[]
|
|
448
|
+
extendedResponse String?
|
|
449
|
+
gradeReceived Int?
|
|
450
|
+
recommendationState SubmissionRecommendationState @default(NONE)
|
|
446
451
|
recommendationUpdatedAt DateTime?
|
|
447
|
-
targetedAssignmentId
|
|
448
|
-
targetedAssignment
|
|
452
|
+
targetedAssignmentId String?
|
|
453
|
+
targetedAssignment Assignment? @relation("SubmissionTargetedAssignment", fields: [targetedAssignmentId], references: [id], onDelete: SetNull)
|
|
449
454
|
|
|
450
|
-
rubricState
|
|
455
|
+
rubricState String?
|
|
451
456
|
teacherComments String?
|
|
452
457
|
|
|
453
|
-
submittedAt
|
|
454
|
-
submitted
|
|
455
|
-
returned
|
|
458
|
+
submittedAt DateTime?
|
|
459
|
+
submitted Boolean? @default(false)
|
|
460
|
+
returned Boolean? @default(false)
|
|
456
461
|
newtonTutors NewtonChat[]
|
|
457
462
|
|
|
458
463
|
@@index([studentId, recommendationState])
|
|
459
464
|
}
|
|
460
465
|
|
|
461
466
|
model NewtonChat {
|
|
462
|
-
id
|
|
463
|
-
submissionId
|
|
464
|
-
submission
|
|
465
|
-
conversationId String
|
|
466
|
-
conversation
|
|
467
|
-
createdAt
|
|
468
|
-
updatedAt
|
|
469
|
-
title
|
|
467
|
+
id String @id @default(uuid())
|
|
468
|
+
submissionId String
|
|
469
|
+
submission Submission @relation(fields: [submissionId], references: [id], onDelete: Cascade)
|
|
470
|
+
conversationId String @unique
|
|
471
|
+
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
472
|
+
createdAt DateTime @default(now())
|
|
473
|
+
updatedAt DateTime @updatedAt
|
|
474
|
+
title String @default("Session with Newton Tutor")
|
|
470
475
|
}
|
|
471
476
|
|
|
472
477
|
model Section {
|
|
473
|
-
id
|
|
474
|
-
name
|
|
475
|
-
classId
|
|
476
|
-
class
|
|
478
|
+
id String @id @default(uuid())
|
|
479
|
+
name String
|
|
480
|
+
classId String
|
|
481
|
+
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
477
482
|
assignments Assignment[]
|
|
478
|
-
color
|
|
479
|
-
order
|
|
483
|
+
color String? @default("#3B82F6")
|
|
484
|
+
order Int?
|
|
480
485
|
}
|
|
481
486
|
|
|
482
487
|
enum SessionType {
|
|
@@ -487,57 +492,57 @@ enum SessionType {
|
|
|
487
492
|
}
|
|
488
493
|
|
|
489
494
|
model Session {
|
|
490
|
-
id String
|
|
491
|
-
createdAt DateTime?
|
|
495
|
+
id String @id @default(uuid())
|
|
496
|
+
createdAt DateTime? @default(now())
|
|
492
497
|
expiresAt DateTime?
|
|
493
498
|
type SessionType @default(AUTH)
|
|
494
499
|
userId String?
|
|
495
|
-
user User?
|
|
500
|
+
user User? @relation(fields: [userId], references: [id], onDelete: NoAction)
|
|
496
501
|
classId String?
|
|
497
|
-
class Class?
|
|
502
|
+
class Class? @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
498
503
|
}
|
|
499
504
|
|
|
500
505
|
model Event {
|
|
501
|
-
id
|
|
502
|
-
name
|
|
503
|
-
startTime
|
|
504
|
-
endTime
|
|
505
|
-
location
|
|
506
|
-
remarks
|
|
507
|
-
userId
|
|
508
|
-
user
|
|
509
|
-
classId
|
|
510
|
-
class
|
|
511
|
-
color
|
|
506
|
+
id String @id @default(uuid())
|
|
507
|
+
name String?
|
|
508
|
+
startTime DateTime
|
|
509
|
+
endTime DateTime
|
|
510
|
+
location String?
|
|
511
|
+
remarks String?
|
|
512
|
+
userId String?
|
|
513
|
+
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
514
|
+
classId String?
|
|
515
|
+
class Class? @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
516
|
+
color String? @default("#3B82F6")
|
|
512
517
|
assignmentsAttached Assignment[]
|
|
513
|
-
attendance
|
|
518
|
+
attendance Attendance[]
|
|
514
519
|
}
|
|
515
520
|
|
|
516
521
|
model Attendance {
|
|
517
|
-
id
|
|
518
|
-
date
|
|
519
|
-
|
|
520
|
-
class
|
|
521
|
-
classId
|
|
522
|
+
id String @id @default(uuid())
|
|
523
|
+
date DateTime @default(now())
|
|
524
|
+
|
|
525
|
+
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
526
|
+
classId String
|
|
522
527
|
|
|
523
|
-
event
|
|
524
|
-
eventId
|
|
528
|
+
event Event? @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
|
529
|
+
eventId String?
|
|
525
530
|
|
|
526
|
-
present
|
|
527
|
-
late
|
|
528
|
-
absent
|
|
531
|
+
present User[] @relation("PresentAttendance")
|
|
532
|
+
late User[] @relation("LateAttendance")
|
|
533
|
+
absent User[] @relation("AbsentAttendance")
|
|
529
534
|
}
|
|
530
535
|
|
|
531
536
|
model Notification {
|
|
532
|
-
id
|
|
533
|
-
title
|
|
534
|
-
content
|
|
535
|
-
createdAt
|
|
536
|
-
senderId
|
|
537
|
+
id String @id @default(uuid())
|
|
538
|
+
title String
|
|
539
|
+
content String
|
|
540
|
+
createdAt DateTime @default(now())
|
|
541
|
+
senderId String? // no ID means sys
|
|
537
542
|
receiverId String
|
|
538
|
-
read
|
|
539
|
-
sender
|
|
540
|
-
receiver
|
|
543
|
+
read Boolean @default(false)
|
|
544
|
+
sender User? @relation("SentNotifications", fields: [senderId], references: [id])
|
|
545
|
+
receiver User @relation("ReceivedNotifications", fields: [receiverId], references: [id], onDelete: Cascade)
|
|
541
546
|
}
|
|
542
547
|
|
|
543
548
|
enum ConversationType {
|
|
@@ -551,179 +556,201 @@ enum ConversationRole {
|
|
|
551
556
|
}
|
|
552
557
|
|
|
553
558
|
model Conversation {
|
|
554
|
-
id
|
|
555
|
-
type
|
|
556
|
-
name
|
|
557
|
-
createdAt DateTime
|
|
558
|
-
updatedAt DateTime
|
|
559
|
+
id String @id @default(uuid())
|
|
560
|
+
type ConversationType
|
|
561
|
+
name String?
|
|
562
|
+
createdAt DateTime @default(now())
|
|
563
|
+
updatedAt DateTime @updatedAt
|
|
559
564
|
|
|
560
565
|
displayInChat Boolean @default(true)
|
|
561
|
-
|
|
562
|
-
members
|
|
563
|
-
messages
|
|
564
|
-
labChat
|
|
566
|
+
|
|
567
|
+
members ConversationMember[]
|
|
568
|
+
messages Message[]
|
|
569
|
+
labChat LabChat?
|
|
565
570
|
newtonChat NewtonChat?
|
|
566
571
|
}
|
|
567
572
|
|
|
568
573
|
model LabChat {
|
|
569
|
-
id
|
|
570
|
-
title
|
|
571
|
-
context
|
|
572
|
-
classId
|
|
573
|
-
conversationId String
|
|
574
|
-
createdById
|
|
575
|
-
createdAt
|
|
576
|
-
updatedAt
|
|
577
|
-
class
|
|
578
|
-
conversation
|
|
579
|
-
createdBy
|
|
574
|
+
id String @id @default(uuid())
|
|
575
|
+
title String
|
|
576
|
+
context String // JSON string for LLM context
|
|
577
|
+
classId String
|
|
578
|
+
conversationId String @unique
|
|
579
|
+
createdById String // Teacher who created the lab
|
|
580
|
+
createdAt DateTime @default(now())
|
|
581
|
+
updatedAt DateTime @updatedAt
|
|
582
|
+
class Class @relation("ClassLabChats", fields: [classId], references: [id], onDelete: Cascade)
|
|
583
|
+
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
584
|
+
createdBy User @relation("CreatedLabChats", fields: [createdById], references: [id], onDelete: NoAction)
|
|
580
585
|
}
|
|
581
586
|
|
|
582
587
|
model ConversationMember {
|
|
583
|
-
id
|
|
584
|
-
userId
|
|
585
|
-
conversationId
|
|
586
|
-
role
|
|
587
|
-
joinedAt
|
|
588
|
-
hiddenAt
|
|
589
|
-
lastViewedAt
|
|
588
|
+
id String @id @default(uuid())
|
|
589
|
+
userId String
|
|
590
|
+
conversationId String
|
|
591
|
+
role ConversationRole @default(MEMBER)
|
|
592
|
+
joinedAt DateTime @default(now())
|
|
593
|
+
hiddenAt DateTime? // When user last hid this conversation from their list
|
|
594
|
+
lastViewedAt DateTime? // When user last viewed this conversation
|
|
590
595
|
lastViewedMentionAt DateTime? // When user last viewed mentions in this conversation
|
|
591
|
-
|
|
592
|
-
user
|
|
596
|
+
|
|
597
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
593
598
|
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
594
|
-
|
|
599
|
+
|
|
595
600
|
@@unique([userId, conversationId])
|
|
596
601
|
}
|
|
597
602
|
|
|
598
603
|
model Message {
|
|
599
|
-
id
|
|
600
|
-
content
|
|
601
|
-
senderId
|
|
604
|
+
id String @id @default(uuid())
|
|
605
|
+
content String
|
|
606
|
+
senderId String
|
|
602
607
|
conversationId String
|
|
603
|
-
createdAt
|
|
604
|
-
status
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
608
|
+
createdAt DateTime @default(now())
|
|
609
|
+
/// UI-shaped status. NULL for messages with no AI lifecycle (normal user DMs).
|
|
610
|
+
/// Operational/queue state (retries, errors, attempts) lives on `runJob`.
|
|
611
|
+
status JobStatus?
|
|
612
|
+
/// Link to the background job that's generating / generated the AI response
|
|
613
|
+
/// for this message. NULL for non-AI messages.
|
|
614
|
+
runJobId String?
|
|
615
|
+
runJob RunJob? @relation("MessageRunJob", fields: [runJobId], references: [id], onDelete: SetNull)
|
|
616
|
+
sender User @relation("SentMessages", fields: [senderId], references: [id], onDelete: Cascade)
|
|
617
|
+
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
618
|
+
mentions Mention[]
|
|
619
|
+
attachments File[] @relation("MessageAttachments")
|
|
609
620
|
|
|
610
621
|
meta Json? @default("{}")
|
|
622
|
+
|
|
623
|
+
@@index([runJobId])
|
|
611
624
|
}
|
|
612
625
|
|
|
613
626
|
model AiUsageLog {
|
|
614
|
-
id
|
|
615
|
-
reason
|
|
616
|
-
provider
|
|
617
|
-
model
|
|
618
|
-
operation
|
|
619
|
-
success
|
|
620
|
-
promptTokens
|
|
621
|
-
completionTokens
|
|
622
|
-
totalTokens
|
|
627
|
+
id String @id @default(uuid())
|
|
628
|
+
reason String
|
|
629
|
+
provider String @default("openai")
|
|
630
|
+
model String
|
|
631
|
+
operation String
|
|
632
|
+
success Boolean @default(true)
|
|
633
|
+
promptTokens Int?
|
|
634
|
+
completionTokens Int?
|
|
635
|
+
totalTokens Int?
|
|
623
636
|
estimatedInputTokens Int?
|
|
624
|
-
metadata
|
|
625
|
-
error
|
|
626
|
-
createdAt
|
|
637
|
+
metadata Json? @default("{}")
|
|
638
|
+
error String?
|
|
639
|
+
createdAt DateTime @default(now())
|
|
627
640
|
|
|
628
641
|
@@index([reason, createdAt])
|
|
629
642
|
}
|
|
630
643
|
|
|
631
644
|
model Mention {
|
|
632
|
-
id
|
|
645
|
+
id String @id @default(uuid())
|
|
633
646
|
messageId String
|
|
634
|
-
userId
|
|
647
|
+
userId String
|
|
635
648
|
createdAt DateTime @default(now())
|
|
636
|
-
|
|
649
|
+
|
|
637
650
|
message Message @relation(fields: [messageId], references: [id], onDelete: Cascade)
|
|
638
|
-
user
|
|
639
|
-
|
|
651
|
+
user User @relation("UserMentions", fields: [userId], references: [id], onDelete: Cascade)
|
|
652
|
+
|
|
640
653
|
@@unique([messageId, userId])
|
|
641
654
|
}
|
|
642
655
|
|
|
643
656
|
model Worksheet {
|
|
644
|
-
id
|
|
645
|
-
name
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
657
|
+
id String @id @default(uuid())
|
|
658
|
+
name String
|
|
659
|
+
sourceUrl String?
|
|
660
|
+
createdAt DateTime @default(now())
|
|
661
|
+
updatedAt DateTime @updatedAt
|
|
662
|
+
classId String
|
|
663
|
+
class Class? @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
664
|
+
assignments Assignment[] @relation("AssignmentWorksheets")
|
|
665
|
+
questions WorksheetQuestion[]
|
|
652
666
|
studentWorksheetResponses StudentWorksheetResponse[]
|
|
667
|
+
|
|
668
|
+
runJobId String?
|
|
669
|
+
runJob RunJob? @relation("WorksheetRunJob", fields: [runJobId], references: [id], onDelete: SetNull)
|
|
670
|
+
|
|
671
|
+
status JobStatus? @default(NOT_STARTED)
|
|
672
|
+
|
|
673
|
+
@@unique([classId, sourceUrl])
|
|
653
674
|
}
|
|
654
675
|
|
|
655
676
|
model WorksheetQuestion {
|
|
656
|
-
id
|
|
657
|
-
worksheetId
|
|
658
|
-
worksheet
|
|
659
|
-
type
|
|
660
|
-
question
|
|
661
|
-
answer
|
|
662
|
-
options
|
|
663
|
-
markScheme
|
|
664
|
-
points
|
|
665
|
-
order
|
|
666
|
-
createdAt
|
|
667
|
-
updatedAt
|
|
677
|
+
id String @id @default(uuid())
|
|
678
|
+
worksheetId String
|
|
679
|
+
worksheet Worksheet @relation(fields: [worksheetId], references: [id], onDelete: Cascade)
|
|
680
|
+
type WorksheetQuestionType
|
|
681
|
+
question String
|
|
682
|
+
answer String
|
|
683
|
+
options Json? @default("{}")
|
|
684
|
+
markScheme Json? @default("{}")
|
|
685
|
+
points Int @default(0)
|
|
686
|
+
order Int? @default(0)
|
|
687
|
+
createdAt DateTime @default(now())
|
|
688
|
+
updatedAt DateTime @updatedAt
|
|
668
689
|
studentResponses StudentQuestionProgress[]
|
|
669
690
|
}
|
|
670
691
|
|
|
671
692
|
model StudentWorksheetResponse {
|
|
672
|
-
id
|
|
673
|
-
studentId
|
|
674
|
-
student
|
|
675
|
-
worksheetId
|
|
676
|
-
worksheet
|
|
677
|
-
responses
|
|
678
|
-
submission
|
|
693
|
+
id String @id @default(uuid())
|
|
694
|
+
studentId String
|
|
695
|
+
student User @relation(fields: [studentId], references: [id], onDelete: Cascade)
|
|
696
|
+
worksheetId String
|
|
697
|
+
worksheet Worksheet @relation(fields: [worksheetId], references: [id], onDelete: Cascade)
|
|
698
|
+
responses StudentQuestionProgress[]
|
|
699
|
+
submission Submission? @relation(fields: [submissionId], references: [id], onDelete: Cascade)
|
|
679
700
|
submissionId String?
|
|
680
|
-
createdAt
|
|
681
|
-
updatedAt
|
|
682
|
-
submittedAt
|
|
683
|
-
submitted
|
|
701
|
+
createdAt DateTime @default(now())
|
|
702
|
+
updatedAt DateTime @updatedAt
|
|
703
|
+
submittedAt DateTime?
|
|
704
|
+
submitted Boolean @default(false)
|
|
684
705
|
}
|
|
685
706
|
|
|
686
707
|
model StudentQuestionProgress {
|
|
687
|
-
id
|
|
688
|
-
studentId
|
|
689
|
-
student
|
|
690
|
-
questionId
|
|
691
|
-
question
|
|
692
|
-
response
|
|
693
|
-
isCorrect
|
|
694
|
-
markschemeState
|
|
695
|
-
points
|
|
696
|
-
comments
|
|
697
|
-
feedback
|
|
698
|
-
createdAt
|
|
699
|
-
updatedAt
|
|
708
|
+
id String @id @default(uuid())
|
|
709
|
+
studentId String
|
|
710
|
+
student User @relation(fields: [studentId], references: [id], onDelete: Cascade)
|
|
711
|
+
questionId String
|
|
712
|
+
question WorksheetQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
|
|
713
|
+
response String
|
|
714
|
+
isCorrect Boolean @default(false)
|
|
715
|
+
markschemeState Json? @default("{}")
|
|
716
|
+
points Int @default(0)
|
|
717
|
+
comments Comment[] @relation("StudentQuestionProgressComments")
|
|
718
|
+
feedback String?
|
|
719
|
+
createdAt DateTime @default(now())
|
|
720
|
+
updatedAt DateTime? @updatedAt
|
|
700
721
|
studentWorksheetResponseId String?
|
|
701
|
-
studentWorksheetResponse
|
|
702
|
-
|
|
703
|
-
|
|
722
|
+
studentWorksheetResponse StudentWorksheetResponse? @relation(fields: [studentWorksheetResponseId], references: [id], onDelete: Cascade)
|
|
723
|
+
/// UI-shaped grading lifecycle. Operational/queue state lives on `runJob`.
|
|
724
|
+
status JobStatus? @default(NOT_STARTED)
|
|
725
|
+
/// Link to the auto-grading background job. NULL when no auto-grading
|
|
726
|
+
/// has ever been attempted for this question.
|
|
727
|
+
runJobId String?
|
|
728
|
+
runJob RunJob? @relation("StudentQuestionProgressRunJob", fields: [runJobId], references: [id], onDelete: SetNull)
|
|
729
|
+
|
|
704
730
|
@@index([studentId, questionId])
|
|
731
|
+
@@index([runJobId])
|
|
705
732
|
}
|
|
706
733
|
|
|
707
734
|
model SchoolDevelopementProgram {
|
|
708
|
-
id
|
|
709
|
-
name
|
|
710
|
-
type
|
|
711
|
-
address
|
|
712
|
-
city
|
|
713
|
-
country
|
|
735
|
+
id String @id
|
|
736
|
+
name String
|
|
737
|
+
type String
|
|
738
|
+
address String
|
|
739
|
+
city String
|
|
740
|
+
country String
|
|
714
741
|
numberOfStudents Int
|
|
715
742
|
numberOfTeachers Int
|
|
716
|
-
website
|
|
743
|
+
website String?
|
|
717
744
|
|
|
718
|
-
contactName
|
|
719
|
-
contactRole
|
|
720
|
-
contactEmail
|
|
721
|
-
contactPhone
|
|
745
|
+
contactName String?
|
|
746
|
+
contactRole String?
|
|
747
|
+
contactEmail String?
|
|
748
|
+
contactPhone String? @default("")
|
|
722
749
|
eligibilityInformation String?
|
|
723
|
-
whyHelp
|
|
724
|
-
additionalInformation
|
|
725
|
-
submittedAt
|
|
726
|
-
reviewedAt
|
|
750
|
+
whyHelp String?
|
|
751
|
+
additionalInformation String?
|
|
752
|
+
submittedAt DateTime? @default(now())
|
|
753
|
+
reviewedAt DateTime?
|
|
727
754
|
|
|
728
755
|
status String @default("NOT_STARTED") // NOT_STARTED, PENDING, APPROVED, REJECTED, REFERRED
|
|
729
756
|
|
|
@@ -731,8 +758,59 @@ model SchoolDevelopementProgram {
|
|
|
731
758
|
}
|
|
732
759
|
|
|
733
760
|
model EarlyAccessRequest {
|
|
734
|
-
id
|
|
735
|
-
email
|
|
736
|
-
createdAt
|
|
761
|
+
id String @id @default(uuid())
|
|
762
|
+
email String
|
|
763
|
+
createdAt DateTime @default(now())
|
|
737
764
|
institutionSize String
|
|
738
765
|
}
|
|
766
|
+
|
|
767
|
+
enum RunJobType {
|
|
768
|
+
PDF_TO_WORKSHEET
|
|
769
|
+
GRADE_WORKSHEET
|
|
770
|
+
AI_LAB_CHAT
|
|
771
|
+
AI_NEWTON_CHAT
|
|
772
|
+
STUDENT_PROGRESS_CHAT
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
enum RunJobStatus {
|
|
776
|
+
PENDING
|
|
777
|
+
RUNNING
|
|
778
|
+
SUCCEEDED
|
|
779
|
+
FAILED
|
|
780
|
+
CANCELLED
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/// App-level audit/status record for background jobs.
|
|
784
|
+
/// BullMQ owns queue state in Redis (retries, scheduling, in-flight execution);
|
|
785
|
+
/// this table is the durable, queryable record of who started what and how it ended.
|
|
786
|
+
model RunJob {
|
|
787
|
+
id String @id @default(uuid())
|
|
788
|
+
type RunJobType
|
|
789
|
+
status RunJobStatus @default(PENDING)
|
|
790
|
+
|
|
791
|
+
classId String?
|
|
792
|
+
userId String?
|
|
793
|
+
|
|
794
|
+
/// BullMQ job id, set after enqueue. Null if enqueue failed before the queue accepted it.
|
|
795
|
+
bullJobId String?
|
|
796
|
+
|
|
797
|
+
input Json
|
|
798
|
+
result Json?
|
|
799
|
+
error String?
|
|
800
|
+
attempts Int @default(0)
|
|
801
|
+
|
|
802
|
+
startedAt DateTime?
|
|
803
|
+
finishedAt DateTime?
|
|
804
|
+
createdAt DateTime @default(now())
|
|
805
|
+
updatedAt DateTime @updatedAt
|
|
806
|
+
|
|
807
|
+
/// Domain rows produced or driven by this job. Each relation is optional —
|
|
808
|
+
/// most jobs touch zero or one of these.
|
|
809
|
+
messages Message[] @relation("MessageRunJob")
|
|
810
|
+
studentQuestionProgresses StudentQuestionProgress[] @relation("StudentQuestionProgressRunJob")
|
|
811
|
+
worksheet Worksheet[] @relation("WorksheetRunJob")
|
|
812
|
+
|
|
813
|
+
@@index([userId, type, status])
|
|
814
|
+
@@index([classId, status])
|
|
815
|
+
@@index([status, createdAt])
|
|
816
|
+
}
|