@studious-lms/server 1.7.0 → 1.8.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 (196) hide show
  1. package/dist/models/access.d.ts +21 -66
  2. package/dist/models/access.d.ts.map +1 -1
  3. package/dist/models/access.js +10 -26
  4. package/dist/models/access.js.map +1 -1
  5. package/dist/models/agenda.d.ts +2 -0
  6. package/dist/models/agenda.d.ts.map +1 -1
  7. package/dist/models/announcement.d.ts +2 -1
  8. package/dist/models/announcement.d.ts.map +1 -1
  9. package/dist/models/announcement.js +2 -3
  10. package/dist/models/announcement.js.map +1 -1
  11. package/dist/models/assignment.d.ts +7 -0
  12. package/dist/models/assignment.d.ts.map +1 -1
  13. package/dist/models/auth.d.ts +2 -4
  14. package/dist/models/auth.d.ts.map +1 -1
  15. package/dist/models/auth.js +2 -3
  16. package/dist/models/auth.js.map +1 -1
  17. package/dist/models/class.d.ts +32 -4
  18. package/dist/models/class.d.ts.map +1 -1
  19. package/dist/models/class.js +15 -2
  20. package/dist/models/class.js.map +1 -1
  21. package/dist/models/cloudStorage.d.ts +140 -0
  22. package/dist/models/cloudStorage.d.ts.map +1 -0
  23. package/dist/models/cloudStorage.js +175 -0
  24. package/dist/models/cloudStorage.js.map +1 -0
  25. package/dist/models/comment.d.ts +0 -24
  26. package/dist/models/comment.d.ts.map +1 -1
  27. package/dist/models/comment.js +2 -6
  28. package/dist/models/comment.js.map +1 -1
  29. package/dist/models/conversation.d.ts +22 -22
  30. package/dist/models/department.d.ts +154 -0
  31. package/dist/models/department.d.ts.map +1 -0
  32. package/dist/models/department.js +135 -0
  33. package/dist/models/department.js.map +1 -0
  34. package/dist/models/event.d.ts +7 -1
  35. package/dist/models/event.d.ts.map +1 -1
  36. package/dist/models/event.js +2 -5
  37. package/dist/models/event.js.map +1 -1
  38. package/dist/models/file.d.ts +25 -10
  39. package/dist/models/file.d.ts.map +1 -1
  40. package/dist/models/file.js +2 -5
  41. package/dist/models/file.js.map +1 -1
  42. package/dist/models/folder.d.ts +47 -0
  43. package/dist/models/folder.d.ts.map +1 -1
  44. package/dist/models/labChat.d.ts +5 -3
  45. package/dist/models/labChat.d.ts.map +1 -1
  46. package/dist/models/message.d.ts +46 -12
  47. package/dist/models/message.d.ts.map +1 -1
  48. package/dist/models/message.js +19 -10
  49. package/dist/models/message.js.map +1 -1
  50. package/dist/models/newtonChat.d.ts +2 -1
  51. package/dist/models/newtonChat.d.ts.map +1 -1
  52. package/dist/models/school.d.ts +45 -12
  53. package/dist/models/school.d.ts.map +1 -1
  54. package/dist/models/school.js +19 -2
  55. package/dist/models/school.js.map +1 -1
  56. package/dist/models/section.d.ts +1 -0
  57. package/dist/models/section.d.ts.map +1 -1
  58. package/dist/models/tag.d.ts +117 -0
  59. package/dist/models/tag.d.ts.map +1 -0
  60. package/dist/models/tag.js +113 -0
  61. package/dist/models/tag.js.map +1 -0
  62. package/dist/models/worksheet.d.ts +3 -0
  63. package/dist/models/worksheet.d.ts.map +1 -1
  64. package/dist/pipelines/aiLabChatContract.d.ts +8 -8
  65. package/dist/routers/_app.d.ts +3200 -1972
  66. package/dist/routers/_app.d.ts.map +1 -1
  67. package/dist/routers/_app.js +6 -2
  68. package/dist/routers/_app.js.map +1 -1
  69. package/dist/routers/agenda.d.ts +2 -0
  70. package/dist/routers/agenda.d.ts.map +1 -1
  71. package/dist/routers/announcement.d.ts.map +1 -1
  72. package/dist/routers/announcement.js +3 -5
  73. package/dist/routers/announcement.js.map +1 -1
  74. package/dist/routers/assignment.d.ts +18 -9
  75. package/dist/routers/assignment.d.ts.map +1 -1
  76. package/dist/routers/assignment.js +2 -3
  77. package/dist/routers/assignment.js.map +1 -1
  78. package/dist/routers/class.d.ts +87 -14
  79. package/dist/routers/class.d.ts.map +1 -1
  80. package/dist/routers/class.js +5 -2
  81. package/dist/routers/class.js.map +1 -1
  82. package/dist/routers/conversation.d.ts +5 -5
  83. package/dist/routers/department.d.ts +293 -0
  84. package/dist/routers/department.d.ts.map +1 -0
  85. package/dist/routers/department.js +93 -0
  86. package/dist/routers/department.js.map +1 -0
  87. package/dist/routers/event.d.ts +2 -1
  88. package/dist/routers/event.d.ts.map +1 -1
  89. package/dist/routers/file.d.ts +8 -6
  90. package/dist/routers/file.d.ts.map +1 -1
  91. package/dist/routers/file.js +26 -17
  92. package/dist/routers/file.js.map +1 -1
  93. package/dist/routers/folder.d.ts +139 -186
  94. package/dist/routers/folder.d.ts.map +1 -1
  95. package/dist/routers/folder.js +82 -90
  96. package/dist/routers/folder.js.map +1 -1
  97. package/dist/routers/labChat.d.ts +11 -2
  98. package/dist/routers/labChat.d.ts.map +1 -1
  99. package/dist/routers/message.d.ts +20 -2
  100. package/dist/routers/message.d.ts.map +1 -1
  101. package/dist/routers/newtonChat.d.ts +9 -0
  102. package/dist/routers/newtonChat.d.ts.map +1 -1
  103. package/dist/routers/school.d.ts +160 -17
  104. package/dist/routers/school.d.ts.map +1 -1
  105. package/dist/routers/school.js +46 -3
  106. package/dist/routers/school.js.map +1 -1
  107. package/dist/routers/tag.d.ts +119 -0
  108. package/dist/routers/tag.d.ts.map +1 -0
  109. package/dist/routers/tag.js +52 -0
  110. package/dist/routers/tag.js.map +1 -0
  111. package/dist/routers/worksheet.d.ts +1 -0
  112. package/dist/routers/worksheet.d.ts.map +1 -1
  113. package/dist/seedDatabase.d.ts +0 -1
  114. package/dist/seedDatabase.d.ts.map +1 -1
  115. package/dist/services/agenda.d.ts +2 -0
  116. package/dist/services/agenda.d.ts.map +1 -1
  117. package/dist/services/assignment.d.ts +18 -9
  118. package/dist/services/assignment.d.ts.map +1 -1
  119. package/dist/services/class.d.ts +87 -14
  120. package/dist/services/class.d.ts.map +1 -1
  121. package/dist/services/class.js +91 -4
  122. package/dist/services/class.js.map +1 -1
  123. package/dist/services/conversation.d.ts +5 -5
  124. package/dist/services/department.d.ts +200 -0
  125. package/dist/services/department.d.ts.map +1 -0
  126. package/dist/services/department.js +368 -0
  127. package/dist/services/department.js.map +1 -0
  128. package/dist/services/event.d.ts +2 -1
  129. package/dist/services/event.d.ts.map +1 -1
  130. package/dist/services/file.d.ts +85 -0
  131. package/dist/services/file.d.ts.map +1 -1
  132. package/dist/services/file.js +92 -2
  133. package/dist/services/file.js.map +1 -1
  134. package/dist/services/folder.d.ts +125 -149
  135. package/dist/services/folder.d.ts.map +1 -1
  136. package/dist/services/folder.js +258 -199
  137. package/dist/services/folder.js.map +1 -1
  138. package/dist/services/labChat.d.ts +11 -2
  139. package/dist/services/labChat.d.ts.map +1 -1
  140. package/dist/services/labChat.js +4 -3
  141. package/dist/services/labChat.js.map +1 -1
  142. package/dist/services/message.d.ts +20 -2
  143. package/dist/services/message.d.ts.map +1 -1
  144. package/dist/services/message.js +7 -23
  145. package/dist/services/message.js.map +1 -1
  146. package/dist/services/newtonChat.d.ts +9 -0
  147. package/dist/services/newtonChat.d.ts.map +1 -1
  148. package/dist/services/newtonChat.js +4 -3
  149. package/dist/services/newtonChat.js.map +1 -1
  150. package/dist/services/school.d.ts +142 -15
  151. package/dist/services/school.d.ts.map +1 -1
  152. package/dist/services/school.js +308 -54
  153. package/dist/services/school.js.map +1 -1
  154. package/dist/services/tag.d.ts +71 -0
  155. package/dist/services/tag.d.ts.map +1 -0
  156. package/dist/services/tag.js +178 -0
  157. package/dist/services/tag.js.map +1 -0
  158. package/dist/services/worksheet.d.ts +1 -0
  159. package/dist/services/worksheet.d.ts.map +1 -1
  160. package/dist/utils/aiUser.d.ts.map +1 -1
  161. package/dist/utils/aiUser.js +2 -3
  162. package/dist/utils/aiUser.js.map +1 -1
  163. package/package.json +1 -1
  164. package/prisma/migrations/20260509220000_institution_overhaul/migration.sql +184 -0
  165. package/prisma/schema.prisma +119 -35
  166. package/src/models/access.ts +8 -24
  167. package/src/models/announcement.ts +0 -1
  168. package/src/models/auth.ts +0 -1
  169. package/src/models/class.ts +13 -0
  170. package/src/models/cloudStorage.ts +194 -0
  171. package/src/models/comment.ts +0 -4
  172. package/src/models/department.ts +159 -0
  173. package/src/models/event.ts +0 -3
  174. package/src/models/file.ts +0 -3
  175. package/src/models/message.ts +19 -5
  176. package/src/models/school.ts +26 -0
  177. package/src/models/tag.ts +140 -0
  178. package/src/routers/_app.ts +4 -0
  179. package/src/routers/announcement.ts +1 -3
  180. package/src/routers/assignment.ts +0 -1
  181. package/src/routers/class.ts +3 -0
  182. package/src/routers/department.ts +174 -0
  183. package/src/routers/file.ts +29 -26
  184. package/src/routers/folder.ts +100 -121
  185. package/src/routers/school.ts +83 -0
  186. package/src/routers/tag.ts +78 -0
  187. package/src/services/class.ts +108 -3
  188. package/src/services/department.ts +478 -0
  189. package/src/services/file.ts +100 -0
  190. package/src/services/folder.ts +313 -240
  191. package/src/services/labChat.ts +2 -1
  192. package/src/services/message.ts +5 -21
  193. package/src/services/newtonChat.ts +2 -1
  194. package/src/services/school.ts +369 -57
  195. package/src/services/tag.ts +229 -0
  196. package/src/utils/aiUser.ts +0 -1
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Tag service — institution-scoped tag CRUD and assignment to taggable
3
+ * targets (users, classes, rubrics, boundaries).
4
+ */
5
+
6
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6ab21e9e-024c-5347-9864-92a8edf76dbe")}catch(e){}}();
7
+ import { TRPCError } from "@trpc/server";
8
+ import { prisma } from "../lib/prisma.js";
9
+ import { attachTagToTarget, createTag, deleteTag, detachTagFromTarget, getTag, listTagsAttachedTo, listTagsForSchool, updateTag, } from "../models/tag.js";
10
+ import { findActiveSchoolAdminMembership, findSchoolMembership, } from "../models/school.js";
11
+ async function requireAdmin(schoolId, userId) {
12
+ const membership = await findActiveSchoolAdminMembership(schoolId, userId);
13
+ if (!membership) {
14
+ throw new TRPCError({
15
+ code: "FORBIDDEN",
16
+ message: "Only school admins can manage tags",
17
+ });
18
+ }
19
+ }
20
+ async function requireMember(schoolId, userId) {
21
+ const membership = await findSchoolMembership(schoolId, userId);
22
+ if (!membership || membership.status !== "ACTIVE") {
23
+ throw new TRPCError({
24
+ code: "FORBIDDEN",
25
+ message: "You aren't a member of this institution",
26
+ });
27
+ }
28
+ return membership;
29
+ }
30
+ export async function listTags(userId, input) {
31
+ await requireMember(input.schoolId, userId);
32
+ return listTagsForSchool(input.schoolId, {
33
+ departmentId: input.departmentId,
34
+ });
35
+ }
36
+ export async function createTagRecord(userId, input) {
37
+ await requireAdmin(input.schoolId, userId);
38
+ if (input.departmentId) {
39
+ const dept = await prisma.department.findUnique({
40
+ where: { id: input.departmentId },
41
+ select: { schoolId: true },
42
+ });
43
+ if (!dept || dept.schoolId !== input.schoolId) {
44
+ throw new TRPCError({
45
+ code: "BAD_REQUEST",
46
+ message: "Department does not belong to this institution",
47
+ });
48
+ }
49
+ }
50
+ return createTag(input);
51
+ }
52
+ export async function updateTagRecord(userId, input) {
53
+ const tag = await getTag(input.tagId);
54
+ if (!tag) {
55
+ throw new TRPCError({ code: "NOT_FOUND", message: "Tag not found" });
56
+ }
57
+ await requireAdmin(tag.schoolId, userId);
58
+ if (input.departmentId) {
59
+ const dept = await prisma.department.findUnique({
60
+ where: { id: input.departmentId },
61
+ select: { schoolId: true },
62
+ });
63
+ if (!dept || dept.schoolId !== tag.schoolId) {
64
+ throw new TRPCError({
65
+ code: "BAD_REQUEST",
66
+ message: "Department does not belong to this institution",
67
+ });
68
+ }
69
+ }
70
+ return updateTag(input.tagId, {
71
+ name: input.name,
72
+ color: input.color,
73
+ departmentId: input.departmentId,
74
+ });
75
+ }
76
+ export async function deleteTagRecord(userId, tagId) {
77
+ const tag = await getTag(tagId);
78
+ if (!tag) {
79
+ throw new TRPCError({ code: "NOT_FOUND", message: "Tag not found" });
80
+ }
81
+ await requireAdmin(tag.schoolId, userId);
82
+ await deleteTag(tagId);
83
+ return { success: true };
84
+ }
85
+ async function ensureTargetInScope(schoolId, target, targetId) {
86
+ switch (target) {
87
+ case "USER": {
88
+ const inSchool = await prisma.schoolMembership.findFirst({
89
+ where: { schoolId, userId: targetId, status: "ACTIVE" },
90
+ select: { id: true },
91
+ });
92
+ if (!inSchool) {
93
+ throw new TRPCError({
94
+ code: "BAD_REQUEST",
95
+ message: "User is not in this institution",
96
+ });
97
+ }
98
+ return;
99
+ }
100
+ case "CLASS": {
101
+ const inSchool = await prisma.class.findFirst({
102
+ where: { id: targetId, schoolId },
103
+ select: { id: true },
104
+ });
105
+ if (!inSchool) {
106
+ throw new TRPCError({
107
+ code: "BAD_REQUEST",
108
+ message: "Class is not in this institution",
109
+ });
110
+ }
111
+ return;
112
+ }
113
+ case "RUBRIC": {
114
+ const inSchool = await prisma.markScheme.findFirst({
115
+ where: {
116
+ id: targetId,
117
+ OR: [
118
+ { class: { schoolId } },
119
+ { department: { schoolId } },
120
+ ],
121
+ },
122
+ select: { id: true },
123
+ });
124
+ if (!inSchool) {
125
+ throw new TRPCError({
126
+ code: "BAD_REQUEST",
127
+ message: "Rubric is not in this institution",
128
+ });
129
+ }
130
+ return;
131
+ }
132
+ case "BOUNDARY": {
133
+ const inSchool = await prisma.gradingBoundary.findFirst({
134
+ where: {
135
+ id: targetId,
136
+ OR: [
137
+ { class: { schoolId } },
138
+ { department: { schoolId } },
139
+ ],
140
+ },
141
+ select: { id: true },
142
+ });
143
+ if (!inSchool) {
144
+ throw new TRPCError({
145
+ code: "BAD_REQUEST",
146
+ message: "Boundary is not in this institution",
147
+ });
148
+ }
149
+ return;
150
+ }
151
+ }
152
+ }
153
+ export async function attachTag(userId, input) {
154
+ const tag = await getTag(input.tagId);
155
+ if (!tag) {
156
+ throw new TRPCError({ code: "NOT_FOUND", message: "Tag not found" });
157
+ }
158
+ await requireMember(tag.schoolId, userId);
159
+ await ensureTargetInScope(tag.schoolId, input.target, input.targetId);
160
+ return attachTagToTarget(input);
161
+ }
162
+ export async function detachTag(userId, input) {
163
+ const tag = await getTag(input.tagId);
164
+ if (!tag) {
165
+ throw new TRPCError({ code: "NOT_FOUND", message: "Tag not found" });
166
+ }
167
+ await requireMember(tag.schoolId, userId);
168
+ return detachTagFromTarget(input);
169
+ }
170
+ export async function getAttachedTags(userId, input) {
171
+ const tags = await listTagsAttachedTo(input.target, input.targetId);
172
+ if (tags[0]) {
173
+ await requireMember(tags[0].schoolId, userId);
174
+ }
175
+ return tags;
176
+ }
177
+ //# sourceMappingURL=tag.js.map
178
+ //# debugId=6ab21e9e-024c-5347-9864-92a8edf76dbe
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag.js","sources":["services/tag.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Tag service — institution-scoped tag CRUD and assignment to taggable\n * targets (users, classes, rubrics, boundaries).\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n attachTagToTarget,\n createTag,\n deleteTag,\n detachTagFromTarget,\n getTag,\n listTagsAttachedTo,\n listTagsForSchool,\n type TagTarget,\n updateTag,\n} from \"../models/tag.js\";\nimport {\n findActiveSchoolAdminMembership,\n findSchoolMembership,\n} from \"../models/school.js\";\n\nasync function requireAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can manage tags\",\n });\n }\n}\n\nasync function requireMember(schoolId: string, userId: string) {\n const membership = await findSchoolMembership(schoolId, userId);\n if (!membership || membership.status !== \"ACTIVE\") {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You aren't a member of this institution\",\n });\n }\n return membership;\n}\n\nexport async function listTags(\n userId: string,\n input: { schoolId: string; departmentId?: string | null }\n) {\n await requireMember(input.schoolId, userId);\n return listTagsForSchool(input.schoolId, {\n departmentId: input.departmentId,\n });\n}\n\nexport async function createTagRecord(\n userId: string,\n input: {\n schoolId: string;\n departmentId?: string | null;\n name: string;\n color?: string;\n }\n) {\n await requireAdmin(input.schoolId, userId);\n if (input.departmentId) {\n const dept = await prisma.department.findUnique({\n where: { id: input.departmentId },\n select: { schoolId: true },\n });\n if (!dept || dept.schoolId !== input.schoolId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Department does not belong to this institution\",\n });\n }\n }\n return createTag(input);\n}\n\nexport async function updateTagRecord(\n userId: string,\n input: {\n tagId: string;\n name?: string;\n color?: string;\n departmentId?: string | null;\n }\n) {\n const tag = await getTag(input.tagId);\n if (!tag) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Tag not found\" });\n }\n await requireAdmin(tag.schoolId, userId);\n if (input.departmentId) {\n const dept = await prisma.department.findUnique({\n where: { id: input.departmentId },\n select: { schoolId: true },\n });\n if (!dept || dept.schoolId !== tag.schoolId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Department does not belong to this institution\",\n });\n }\n }\n return updateTag(input.tagId, {\n name: input.name,\n color: input.color,\n departmentId: input.departmentId,\n });\n}\n\nexport async function deleteTagRecord(userId: string, tagId: string) {\n const tag = await getTag(tagId);\n if (!tag) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Tag not found\" });\n }\n await requireAdmin(tag.schoolId, userId);\n await deleteTag(tagId);\n return { success: true };\n}\n\nasync function ensureTargetInScope(\n schoolId: string,\n target: TagTarget,\n targetId: string\n) {\n switch (target) {\n case \"USER\": {\n const inSchool = await prisma.schoolMembership.findFirst({\n where: { schoolId, userId: targetId, status: \"ACTIVE\" },\n select: { id: true },\n });\n if (!inSchool) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"User is not in this institution\",\n });\n }\n return;\n }\n case \"CLASS\": {\n const inSchool = await prisma.class.findFirst({\n where: { id: targetId, schoolId },\n select: { id: true },\n });\n if (!inSchool) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Class is not in this institution\",\n });\n }\n return;\n }\n case \"RUBRIC\": {\n const inSchool = await prisma.markScheme.findFirst({\n where: {\n id: targetId,\n OR: [\n { class: { schoolId } },\n { department: { schoolId } },\n ],\n },\n select: { id: true },\n });\n if (!inSchool) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Rubric is not in this institution\",\n });\n }\n return;\n }\n case \"BOUNDARY\": {\n const inSchool = await prisma.gradingBoundary.findFirst({\n where: {\n id: targetId,\n OR: [\n { class: { schoolId } },\n { department: { schoolId } },\n ],\n },\n select: { id: true },\n });\n if (!inSchool) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Boundary is not in this institution\",\n });\n }\n return;\n }\n }\n}\n\nexport async function attachTag(\n userId: string,\n input: { tagId: string; target: TagTarget; targetId: string }\n) {\n const tag = await getTag(input.tagId);\n if (!tag) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Tag not found\" });\n }\n await requireMember(tag.schoolId, userId);\n await ensureTargetInScope(tag.schoolId, input.target, input.targetId);\n return attachTagToTarget(input);\n}\n\nexport async function detachTag(\n userId: string,\n input: { tagId: string; target: TagTarget; targetId: string }\n) {\n const tag = await getTag(input.tagId);\n if (!tag) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Tag not found\" });\n }\n await requireMember(tag.schoolId, userId);\n return detachTagFromTarget(input);\n}\n\nexport async function getAttachedTags(\n userId: string,\n input: { target: TagTarget; targetId: string }\n) {\n const tags = await listTagsAttachedTo(input.target, input.targetId);\n if (tags[0]) {\n await requireMember(tags[0].schoolId, userId);\n }\n return tags;\n}\n"],"names":[],"mappings":"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","debug_id":"6ab21e9e-024c-5347-9864-92a8edf76dbe"}
@@ -9,6 +9,7 @@ export declare function getWorksheet(worksheetId: string, userId: string): Promi
9
9
  color: string | null;
10
10
  section: string;
11
11
  syllabus: string | null;
12
+ departmentId: string | null;
12
13
  } | null;
13
14
  questions: {
14
15
  type: import(".prisma/client").$Enums.WorksheetQuestionType;
@@ -1 +1 @@
1
- {"version":3,"file":"worksheet.d.ts","sourceRoot":"/","sources":["services/worksheet.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worksheet.d.ts","sourceRoot":"/","sources":["services/worksheet.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"aiUser.d.ts","sourceRoot":"/","sources":["utils/aiUser.ts"],"names":[],"mappings":"AAQA,uDAAuD;AACvD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CA0CxD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhD"}
1
+ {"version":3,"file":"aiUser.d.ts","sourceRoot":"/","sources":["utils/aiUser.ts"],"names":[],"mappings":"AAQA,uDAAuD;AACvD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyCxD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEhD"}
@@ -2,7 +2,7 @@
2
2
  * AI user util – ensures AI assistant user exists, provides ID and isAIUser check.
3
3
  */
4
4
 
5
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="0ed01933-9d5a-548d-b86b-94f607dd41ed")}catch(e){}}();
5
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3221c7f8-7f11-5e45-9148-3a8ddd53a1f0")}catch(e){}}();
6
6
  import { prisma } from '../lib/prisma.js';
7
7
  import { logger } from './logger.js';
8
8
  const AI_USER_ID = 'AI_ASSISTANT';
@@ -24,7 +24,6 @@ export async function ensureAIUserExists() {
24
24
  email: 'ai@studious-lms.com',
25
25
  password: 'ai-system-user', // Not used for login
26
26
  verified: true,
27
- role: 'NONE', // Special role for AI
28
27
  profile: {
29
28
  create: {
30
29
  displayName: 'AI Assistant',
@@ -59,4 +58,4 @@ export function isAIUser(userId) {
59
58
  return userId === AI_USER_ID;
60
59
  }
61
60
  //# sourceMappingURL=aiUser.js.map
62
- //# debugId=0ed01933-9d5a-548d-b86b-94f607dd41ed
61
+ //# debugId=3221c7f8-7f11-5e45-9148-3a8ddd53a1f0
@@ -1 +1 @@
1
- {"version":3,"file":"aiUser.js","sources":["utils/aiUser.ts"],"sourceRoot":"/","sourcesContent":["/**\n * AI user util – ensures AI assistant user exists, provides ID and isAIUser check.\n */\nimport { prisma } from '../lib/prisma.js';\nimport { logger } from './logger.js';\n\nconst AI_USER_ID = 'AI_ASSISTANT';\n\n/** Ensure AI assistant user exists in the database. */\nexport async function ensureAIUserExists(): Promise<void> {\n try {\n // Check if AI user already exists\n const existingAIUser = await prisma.user.findUnique({\n where: { id: AI_USER_ID },\n });\n\n if (existingAIUser) {\n return; // AI user already exists\n }\n\n // Create AI user\n await prisma.user.create({\n data: {\n id: AI_USER_ID,\n username: 'ai-assistant',\n email: 'ai@studious-lms.com',\n password: 'ai-system-user', // Not used for login\n verified: true,\n role: 'NONE', // Special role for AI\n profile: {\n create: {\n displayName: 'AI Assistant',\n bio: 'Intelligent assistant for lab chats and educational support',\n profilePicture: null,\n },\n },\n },\n });\n\n logger.info('AI user created successfully', { userId: AI_USER_ID });\n\n } catch (error) {\n // If user already exists (race condition), that's okay\n if (error instanceof Error && error.message.includes('unique constraint')) {\n logger.info('AI user already exists (race condition handled)');\n return;\n }\n\n logger.error('Failed to create AI user', { error });\n throw error;\n }\n}\n\n/**\n * Get the AI user ID\n */\nexport function getAIUserId(): string {\n return AI_USER_ID;\n}\n\n/**\n * Check if a user ID belongs to the AI assistant\n */\nexport function isAIUser(userId: string): boolean {\n return userId === AI_USER_ID;\n}\n"],"names":[],"mappings":"AAAA;;GAEG;;;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC,uDAAuD;AACvD,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,IAAI,CAAC;QACH,kCAAkC;QAClC,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE;SAC1B,CAAC,CAAC;QAEH,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,CAAC,yBAAyB;QACnC,CAAC;QAED,iBAAiB;QACjB,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACvB,IAAI,EAAE;gBACJ,EAAE,EAAE,UAAU;gBACd,QAAQ,EAAE,cAAc;gBACxB,KAAK,EAAE,qBAAqB;gBAC5B,QAAQ,EAAE,gBAAgB,EAAE,qBAAqB;gBACjD,QAAQ,EAAE,IAAI;gBACd,IAAI,EAAE,MAAM,EAAE,sBAAsB;gBACpC,OAAO,EAAE;oBACP,MAAM,EAAE;wBACN,WAAW,EAAE,cAAc;wBAC3B,GAAG,EAAE,6DAA6D;wBAClE,cAAc,EAAE,IAAI;qBACrB;iBACF;aACF;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IAEtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,uDAAuD;QACvD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YAC1E,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACpD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,OAAO,MAAM,KAAK,UAAU,CAAC;AAC/B,CAAC","debug_id":"0ed01933-9d5a-548d-b86b-94f607dd41ed"}
1
+ {"version":3,"file":"aiUser.js","sources":["utils/aiUser.ts"],"sourceRoot":"/","sourcesContent":["/**\n * AI user util – ensures AI assistant user exists, provides ID and isAIUser check.\n */\nimport { prisma } from '../lib/prisma.js';\nimport { logger } from './logger.js';\n\nconst AI_USER_ID = 'AI_ASSISTANT';\n\n/** Ensure AI assistant user exists in the database. */\nexport async function ensureAIUserExists(): Promise<void> {\n try {\n // Check if AI user already exists\n const existingAIUser = await prisma.user.findUnique({\n where: { id: AI_USER_ID },\n });\n\n if (existingAIUser) {\n return; // AI user already exists\n }\n\n // Create AI user\n await prisma.user.create({\n data: {\n id: AI_USER_ID,\n username: 'ai-assistant',\n email: 'ai@studious-lms.com',\n password: 'ai-system-user', // Not used for login\n verified: true,\n profile: {\n create: {\n displayName: 'AI Assistant',\n bio: 'Intelligent assistant for lab chats and educational support',\n profilePicture: null,\n },\n },\n },\n });\n\n logger.info('AI user created successfully', { userId: AI_USER_ID });\n\n } catch (error) {\n // If user already exists (race condition), that's okay\n if (error instanceof Error && error.message.includes('unique constraint')) {\n logger.info('AI user already exists (race condition handled)');\n return;\n }\n\n logger.error('Failed to create AI user', { error });\n throw error;\n }\n}\n\n/**\n * Get the AI user ID\n */\nexport function getAIUserId(): string {\n return AI_USER_ID;\n}\n\n/**\n * Check if a user ID belongs to the AI assistant\n */\nexport function isAIUser(userId: string): boolean {\n return userId === AI_USER_ID;\n}\n"],"names":[],"mappings":"AAAA;;GAEG;;;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC,uDAAuD;AACvD,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,IAAI,CAAC;QACH,kCAAkC;QAClC,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;YAClD,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE;SAC1B,CAAC,CAAC;QAEH,IAAI,cAAc,EAAE,CAAC;YACnB,OAAO,CAAC,yBAAyB;QACnC,CAAC;QAED,iBAAiB;QACjB,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACvB,IAAI,EAAE;gBACJ,EAAE,EAAE,UAAU;gBACd,QAAQ,EAAE,cAAc;gBACxB,KAAK,EAAE,qBAAqB;gBAC5B,QAAQ,EAAE,gBAAgB,EAAE,qBAAqB;gBACjD,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE;oBACP,MAAM,EAAE;wBACN,WAAW,EAAE,cAAc;wBAC3B,GAAG,EAAE,6DAA6D;wBAClE,cAAc,EAAE,IAAI;qBACrB;iBACF;aACF;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IAEtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,uDAAuD;QACvD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YAC1E,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACpD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,OAAO,MAAM,KAAK,UAAU,CAAC;AAC/B,CAAC","debug_id":"3221c7f8-7f11-5e45-9148-3a8ddd53a1f0"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studious-lms/server",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Backend server for Studious application",
5
5
  "main": "dist/exportType.js",
6
6
  "types": "dist/exportType.d.ts",
@@ -0,0 +1,184 @@
1
+ -- Institution overhaul: departments, tags, cloud storage, class affiliation,
2
+ -- and template grading artefacts.
3
+
4
+ CREATE TYPE "TagTarget" AS ENUM ('USER', 'CLASS', 'RUBRIC', 'BOUNDARY');
5
+ CREATE TYPE "FolderScope" AS ENUM ('CLASS', 'SCHOOL_STORAGE', 'PERSONAL', 'GENERIC');
6
+
7
+ -- School: optional description.
8
+ ALTER TABLE "School"
9
+ ADD COLUMN "description" TEXT;
10
+
11
+ -- Folder: extend with scope + alternate root owners (school, personal user).
12
+ ALTER TABLE "Folder"
13
+ ADD COLUMN "scope" "FolderScope" NOT NULL DEFAULT 'GENERIC',
14
+ ADD COLUMN "schoolStorageId" TEXT,
15
+ ADD COLUMN "personalOwnerId" TEXT;
16
+
17
+ -- Backfill existing class root folders to CLASS scope so the data layer can
18
+ -- distinguish roots from generic subfolders.
19
+ UPDATE "Folder"
20
+ SET "scope" = 'CLASS'
21
+ WHERE "classId" IS NOT NULL AND "parentFolderId" IS NULL;
22
+
23
+ CREATE UNIQUE INDEX "Folder_schoolStorageId_key" ON "Folder"("schoolStorageId");
24
+ CREATE UNIQUE INDEX "Folder_personalOwnerId_key" ON "Folder"("personalOwnerId");
25
+
26
+ ALTER TABLE "Folder"
27
+ ADD CONSTRAINT "Folder_schoolStorageId_fkey"
28
+ FOREIGN KEY ("schoolStorageId") REFERENCES "School"("id")
29
+ ON DELETE SET NULL ON UPDATE CASCADE,
30
+ ADD CONSTRAINT "Folder_personalOwnerId_fkey"
31
+ FOREIGN KEY ("personalOwnerId") REFERENCES "User"("id")
32
+ ON DELETE CASCADE ON UPDATE CASCADE;
33
+
34
+ -- Department.
35
+ CREATE TABLE "Department" (
36
+ "id" TEXT NOT NULL,
37
+ "schoolId" TEXT NOT NULL,
38
+ "name" TEXT NOT NULL,
39
+ "description" TEXT,
40
+ "color" TEXT DEFAULT '#3B82F6',
41
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
42
+ "updatedAt" TIMESTAMP(3) NOT NULL,
43
+
44
+ CONSTRAINT "Department_pkey" PRIMARY KEY ("id")
45
+ );
46
+
47
+ CREATE UNIQUE INDEX "Department_schoolId_name_key" ON "Department"("schoolId", "name");
48
+ CREATE INDEX "Department_schoolId_idx" ON "Department"("schoolId");
49
+
50
+ ALTER TABLE "Department"
51
+ ADD CONSTRAINT "Department_schoolId_fkey"
52
+ FOREIGN KEY ("schoolId") REFERENCES "School"("id")
53
+ ON DELETE CASCADE ON UPDATE CASCADE;
54
+
55
+ -- User <-> Department (M:N).
56
+ CREATE TABLE "_UserDepartments" (
57
+ "A" TEXT NOT NULL,
58
+ "B" TEXT NOT NULL
59
+ );
60
+ CREATE UNIQUE INDEX "_UserDepartments_AB_unique" ON "_UserDepartments"("A", "B");
61
+ CREATE INDEX "_UserDepartments_B_index" ON "_UserDepartments"("B");
62
+ ALTER TABLE "_UserDepartments"
63
+ ADD CONSTRAINT "_UserDepartments_A_fkey"
64
+ FOREIGN KEY ("A") REFERENCES "Department"("id") ON DELETE CASCADE ON UPDATE CASCADE,
65
+ ADD CONSTRAINT "_UserDepartments_B_fkey"
66
+ FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
67
+
68
+ -- Tag.
69
+ CREATE TABLE "Tag" (
70
+ "id" TEXT NOT NULL,
71
+ "schoolId" TEXT NOT NULL,
72
+ "departmentId" TEXT,
73
+ "name" TEXT NOT NULL,
74
+ "color" TEXT NOT NULL DEFAULT '#3B82F6',
75
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
76
+ "updatedAt" TIMESTAMP(3) NOT NULL,
77
+
78
+ CONSTRAINT "Tag_pkey" PRIMARY KEY ("id")
79
+ );
80
+
81
+ CREATE UNIQUE INDEX "Tag_schoolId_name_key" ON "Tag"("schoolId", "name");
82
+ CREATE INDEX "Tag_schoolId_idx" ON "Tag"("schoolId");
83
+ CREATE INDEX "Tag_departmentId_idx" ON "Tag"("departmentId");
84
+
85
+ ALTER TABLE "Tag"
86
+ ADD CONSTRAINT "Tag_schoolId_fkey"
87
+ FOREIGN KEY ("schoolId") REFERENCES "School"("id")
88
+ ON DELETE CASCADE ON UPDATE CASCADE,
89
+ ADD CONSTRAINT "Tag_departmentId_fkey"
90
+ FOREIGN KEY ("departmentId") REFERENCES "Department"("id")
91
+ ON DELETE SET NULL ON UPDATE CASCADE;
92
+
93
+ -- Tag join tables.
94
+ CREATE TABLE "_UserTags" (
95
+ "A" TEXT NOT NULL,
96
+ "B" TEXT NOT NULL
97
+ );
98
+ CREATE UNIQUE INDEX "_UserTags_AB_unique" ON "_UserTags"("A", "B");
99
+ CREATE INDEX "_UserTags_B_index" ON "_UserTags"("B");
100
+ ALTER TABLE "_UserTags"
101
+ ADD CONSTRAINT "_UserTags_A_fkey" FOREIGN KEY ("A") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE,
102
+ ADD CONSTRAINT "_UserTags_B_fkey" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
103
+
104
+ CREATE TABLE "_ClassTags" (
105
+ "A" TEXT NOT NULL,
106
+ "B" TEXT NOT NULL
107
+ );
108
+ CREATE UNIQUE INDEX "_ClassTags_AB_unique" ON "_ClassTags"("A", "B");
109
+ CREATE INDEX "_ClassTags_B_index" ON "_ClassTags"("B");
110
+ ALTER TABLE "_ClassTags"
111
+ ADD CONSTRAINT "_ClassTags_A_fkey" FOREIGN KEY ("A") REFERENCES "Class"("id") ON DELETE CASCADE ON UPDATE CASCADE,
112
+ ADD CONSTRAINT "_ClassTags_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
113
+
114
+ CREATE TABLE "_MarkSchemeTags" (
115
+ "A" TEXT NOT NULL,
116
+ "B" TEXT NOT NULL
117
+ );
118
+ CREATE UNIQUE INDEX "_MarkSchemeTags_AB_unique" ON "_MarkSchemeTags"("A", "B");
119
+ CREATE INDEX "_MarkSchemeTags_B_index" ON "_MarkSchemeTags"("B");
120
+ ALTER TABLE "_MarkSchemeTags"
121
+ ADD CONSTRAINT "_MarkSchemeTags_A_fkey" FOREIGN KEY ("A") REFERENCES "MarkScheme"("id") ON DELETE CASCADE ON UPDATE CASCADE,
122
+ ADD CONSTRAINT "_MarkSchemeTags_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
123
+
124
+ CREATE TABLE "_GradingBoundaryTags" (
125
+ "A" TEXT NOT NULL,
126
+ "B" TEXT NOT NULL
127
+ );
128
+ CREATE UNIQUE INDEX "_GradingBoundaryTags_AB_unique" ON "_GradingBoundaryTags"("A", "B");
129
+ CREATE INDEX "_GradingBoundaryTags_B_index" ON "_GradingBoundaryTags"("B");
130
+ ALTER TABLE "_GradingBoundaryTags"
131
+ ADD CONSTRAINT "_GradingBoundaryTags_A_fkey" FOREIGN KEY ("A") REFERENCES "GradingBoundary"("id") ON DELETE CASCADE ON UPDATE CASCADE,
132
+ ADD CONSTRAINT "_GradingBoundaryTags_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
133
+
134
+ -- Class: department + tags relations (tags are via _ClassTags above).
135
+ ALTER TABLE "Class"
136
+ ADD COLUMN "departmentId" TEXT;
137
+
138
+ CREATE INDEX "Class_schoolId_idx" ON "Class"("schoolId");
139
+ CREATE INDEX "Class_departmentId_idx" ON "Class"("departmentId");
140
+
141
+ ALTER TABLE "Class"
142
+ ADD CONSTRAINT "Class_departmentId_fkey"
143
+ FOREIGN KEY ("departmentId") REFERENCES "Department"("id")
144
+ ON DELETE SET NULL ON UPDATE CASCADE;
145
+
146
+ -- MarkScheme: optional class, departmentId, name.
147
+ ALTER TABLE "MarkScheme"
148
+ DROP CONSTRAINT IF EXISTS "MarkScheme_classId_fkey";
149
+
150
+ ALTER TABLE "MarkScheme"
151
+ ALTER COLUMN "classId" DROP NOT NULL,
152
+ ADD COLUMN "departmentId" TEXT,
153
+ ADD COLUMN "name" TEXT;
154
+
155
+ ALTER TABLE "MarkScheme"
156
+ ADD CONSTRAINT "MarkScheme_classId_fkey"
157
+ FOREIGN KEY ("classId") REFERENCES "Class"("id")
158
+ ON DELETE CASCADE ON UPDATE CASCADE,
159
+ ADD CONSTRAINT "MarkScheme_departmentId_fkey"
160
+ FOREIGN KEY ("departmentId") REFERENCES "Department"("id")
161
+ ON DELETE CASCADE ON UPDATE CASCADE;
162
+
163
+ CREATE INDEX "MarkScheme_classId_idx" ON "MarkScheme"("classId");
164
+ CREATE INDEX "MarkScheme_departmentId_idx" ON "MarkScheme"("departmentId");
165
+
166
+ -- GradingBoundary: optional class, departmentId, name.
167
+ ALTER TABLE "GradingBoundary"
168
+ DROP CONSTRAINT IF EXISTS "GradingBoundary_classId_fkey";
169
+
170
+ ALTER TABLE "GradingBoundary"
171
+ ALTER COLUMN "classId" DROP NOT NULL,
172
+ ADD COLUMN "departmentId" TEXT,
173
+ ADD COLUMN "name" TEXT;
174
+
175
+ ALTER TABLE "GradingBoundary"
176
+ ADD CONSTRAINT "GradingBoundary_classId_fkey"
177
+ FOREIGN KEY ("classId") REFERENCES "Class"("id")
178
+ ON DELETE CASCADE ON UPDATE CASCADE,
179
+ ADD CONSTRAINT "GradingBoundary_departmentId_fkey"
180
+ FOREIGN KEY ("departmentId") REFERENCES "Department"("id")
181
+ ON DELETE CASCADE ON UPDATE CASCADE;
182
+
183
+ CREATE INDEX "GradingBoundary_classId_idx" ON "GradingBoundary"("classId");
184
+ CREATE INDEX "GradingBoundary_departmentId_idx" ON "GradingBoundary"("departmentId");