@studious-lms/server 1.27.0 → 1.28.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 (106) hide show
  1. package/dist/index.d.ts.map +1 -1
  2. package/dist/index.js +31 -4
  3. package/dist/index.js.map +1 -1
  4. package/dist/instrument.js +9 -4
  5. package/dist/instrument.js.map +1 -1
  6. package/dist/lib/fileUpload.d.ts +15 -0
  7. package/dist/lib/fileUpload.d.ts.map +1 -1
  8. package/dist/lib/fileUpload.js +43 -2
  9. package/dist/lib/fileUpload.js.map +1 -1
  10. package/dist/pipelines/aiLabChatContract.d.ts +2 -2
  11. package/dist/pipelines/generateVisualization.d.ts +33 -0
  12. package/dist/pipelines/generateVisualization.d.ts.map +1 -0
  13. package/dist/pipelines/generateVisualization.js +79 -0
  14. package/dist/pipelines/generateVisualization.js.map +1 -0
  15. package/dist/routers/_app.d.ts +891 -53
  16. package/dist/routers/_app.d.ts.map +1 -1
  17. package/dist/routers/_app.js +4 -2
  18. package/dist/routers/_app.js.map +1 -1
  19. package/dist/routers/admin.d.ts +297 -0
  20. package/dist/routers/admin.d.ts.map +1 -1
  21. package/dist/routers/admin.js +43 -2
  22. package/dist/routers/admin.js.map +1 -1
  23. package/dist/routers/class.d.ts.map +1 -1
  24. package/dist/routers/class.js +16 -3
  25. package/dist/routers/class.js.map +1 -1
  26. package/dist/routers/module.d.ts +1 -1
  27. package/dist/routers/visualization.d.ts +124 -0
  28. package/dist/routers/visualization.d.ts.map +1 -0
  29. package/dist/routers/visualization.js +41 -0
  30. package/dist/routers/visualization.js.map +1 -0
  31. package/dist/services/adminClass.d.ts +153 -0
  32. package/dist/services/adminClass.d.ts.map +1 -0
  33. package/dist/services/adminClass.js +196 -0
  34. package/dist/services/adminClass.js.map +1 -0
  35. package/dist/services/adminInstitution.d.ts +2 -0
  36. package/dist/services/adminInstitution.d.ts.map +1 -1
  37. package/dist/services/adminInstitution.js +11 -4
  38. package/dist/services/adminInstitution.js.map +1 -1
  39. package/dist/services/adminMetrics.d.ts +8 -0
  40. package/dist/services/adminMetrics.d.ts.map +1 -1
  41. package/dist/services/adminMetrics.js +30 -3
  42. package/dist/services/adminMetrics.js.map +1 -1
  43. package/dist/services/adminSpam.d.ts +76 -0
  44. package/dist/services/adminSpam.d.ts.map +1 -0
  45. package/dist/services/adminSpam.js +163 -0
  46. package/dist/services/adminSpam.js.map +1 -0
  47. package/dist/services/adminSql.d.ts +36 -0
  48. package/dist/services/adminSql.d.ts.map +1 -0
  49. package/dist/services/adminSql.js +172 -0
  50. package/dist/services/adminSql.js.map +1 -0
  51. package/dist/services/adminTelemetry.d.ts +56 -0
  52. package/dist/services/adminTelemetry.d.ts.map +1 -0
  53. package/dist/services/adminTelemetry.js +147 -0
  54. package/dist/services/adminTelemetry.js.map +1 -0
  55. package/dist/services/adminUser.d.ts +45 -0
  56. package/dist/services/adminUser.d.ts.map +1 -1
  57. package/dist/services/adminUser.js +48 -11
  58. package/dist/services/adminUser.js.map +1 -1
  59. package/dist/services/auth.d.ts.map +1 -1
  60. package/dist/services/auth.js +10 -4
  61. package/dist/services/auth.js.map +1 -1
  62. package/dist/services/fees.d.ts.map +1 -1
  63. package/dist/services/fees.js +7 -3
  64. package/dist/services/fees.js.map +1 -1
  65. package/dist/services/module.d.ts.map +1 -1
  66. package/dist/services/module.js +23 -4
  67. package/dist/services/module.js.map +1 -1
  68. package/dist/services/visualization.d.ts +72 -0
  69. package/dist/services/visualization.d.ts.map +1 -0
  70. package/dist/services/visualization.js +122 -0
  71. package/dist/services/visualization.js.map +1 -0
  72. package/dist/utils/sentryTrpc.d.ts +3 -0
  73. package/dist/utils/sentryTrpc.d.ts.map +1 -0
  74. package/dist/utils/sentryTrpc.js +26 -0
  75. package/dist/utils/sentryTrpc.js.map +1 -0
  76. package/package.json +1 -1
  77. package/prisma/migrations/20261025120000_add_visualizations/migration.sql +27 -0
  78. package/prisma/schema.prisma +24 -0
  79. package/src/index.ts +30 -4
  80. package/src/instrument.ts +8 -2
  81. package/src/lib/fileUpload.ts +49 -0
  82. package/src/pipelines/generateVisualization.ts +107 -0
  83. package/src/routers/_app.ts +2 -0
  84. package/src/routers/admin.ts +72 -0
  85. package/src/routers/class.ts +14 -1
  86. package/src/routers/visualization.ts +60 -0
  87. package/src/services/adminClass.ts +222 -0
  88. package/src/services/adminInstitution.ts +9 -2
  89. package/src/services/adminMetrics.ts +35 -0
  90. package/src/services/adminSpam.ts +224 -0
  91. package/src/services/adminSql.ts +214 -0
  92. package/src/services/adminTelemetry.ts +194 -0
  93. package/src/services/adminUser.ts +61 -9
  94. package/src/services/auth.ts +8 -2
  95. package/src/services/fees.ts +5 -1
  96. package/src/services/module.ts +29 -2
  97. package/src/services/visualization.ts +147 -0
  98. package/src/utils/sentryTrpc.ts +25 -0
  99. package/tests/unit/lib/fileUploadSession.test.ts +67 -0
  100. package/tests/unit/services/adminClass.test.ts +102 -0
  101. package/tests/unit/services/adminSpam.test.ts +108 -0
  102. package/tests/unit/services/adminSql.test.ts +56 -0
  103. package/tests/unit/services/adminTelemetry.test.ts +47 -0
  104. package/tests/unit/services/adminUser.test.ts +2 -0
  105. package/tests/unit/services/visualization.test.ts +130 -0
  106. package/tests/unit/utils/sentryTrpc.test.ts +15 -0
@@ -7,7 +7,7 @@
7
7
  * sequential progression.
8
8
  */
9
9
 
10
- !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]="86e40dd6-85f3-59e2-afd9-e0da189f9288")}catch(e){}}();
10
+ !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]="69f3db7b-9e94-5f6e-9e8b-f196705cf116")}catch(e){}}();
11
11
  import { TRPCError } from "@trpc/server";
12
12
  import { CourseModuleItemType as ModuleItemType, ModuleItemRequirementType, ModuleItemProgressStatus, } from "@prisma/client";
13
13
  import { prisma } from "../lib/prisma.js";
@@ -134,6 +134,7 @@ const CONTENT_TYPES = [
134
134
  ModuleItemType.FILE,
135
135
  ModuleItemType.ANNOUNCEMENT,
136
136
  ModuleItemType.DISCUSSION,
137
+ ModuleItemType.VISUALIZATION,
137
138
  ];
138
139
  const SUBMITTABLE_TYPES = [
139
140
  ModuleItemType.ASSIGNMENT,
@@ -173,7 +174,9 @@ async function validateItemInput(classId, input) {
173
174
  ? await prisma.announcement.findFirst({ where: { id: itemId, classId } })
174
175
  : itemType === ModuleItemType.DISCUSSION
175
176
  ? await prisma.discussion.findFirst({ where: { id: itemId, classId } })
176
- : await prisma.file.findUnique({ where: { id: itemId } });
177
+ : itemType === ModuleItemType.VISUALIZATION
178
+ ? await prisma.visualization.findFirst({ where: { id: itemId, classId } })
179
+ : await prisma.file.findUnique({ where: { id: itemId } });
177
180
  if (!exists) {
178
181
  throw new TRPCError({
179
182
  code: "NOT_FOUND",
@@ -309,10 +312,26 @@ function isModuleComplete(module, completedItemIds) {
309
312
  * completion/accessibility and per-module progress percentages.
310
313
  */
311
314
  export async function getStudentModulesState(classId, studentId) {
312
- const [modules, progress] = await Promise.all([
315
+ const [allModules, progress] = await Promise.all([
313
316
  findModulesByClassId(classId, true),
314
317
  findStudentProgressForClass(classId, studentId),
315
318
  ]);
319
+ // Hide visualisations the teacher hasn't published yet.
320
+ const visualizationIds = allModules
321
+ .flatMap((m) => m.items)
322
+ .filter((i) => i.itemType === ModuleItemType.VISUALIZATION && i.itemId)
323
+ .map((i) => i.itemId);
324
+ const publishedVisualizationIds = new Set(visualizationIds.length
325
+ ? (await prisma.visualization.findMany({
326
+ where: { id: { in: visualizationIds }, classId, published: true },
327
+ select: { id: true },
328
+ })).map((v) => v.id)
329
+ : []);
330
+ const modules = allModules.map((m) => ({
331
+ ...m,
332
+ items: m.items.filter((i) => i.itemType !== ModuleItemType.VISUALIZATION ||
333
+ (!!i.itemId && publishedVisualizationIds.has(i.itemId))),
334
+ }));
316
335
  const completedItemIds = new Set(progress
317
336
  .filter((p) => p.status === ModuleItemProgressStatus.COMPLETE)
318
337
  .map((p) => p.moduleItemId));
@@ -515,4 +534,4 @@ export async function syncWorksheetModuleProgress(studentId, worksheetId) {
515
534
  }
516
535
  }
517
536
  //# sourceMappingURL=module.js.map
518
- //# debugId=86e40dd6-85f3-59e2-afd9-e0da189f9288
537
+ //# debugId=69f3db7b-9e94-5f6e-9e8b-f196705cf116
@@ -1 +1 @@
1
- {"version":3,"file":"module.js","sources":["services/module.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Module service – Canvas-style modules (\"pathways\") for classes.\n *\n * Modules are ordered groups of content items (assignments, worksheets,\n * files, announcements, discussions, external URLs, sub-headers) with\n * completion requirements, prerequisites, unlock dates and optional\n * sequential progression.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n CourseModuleItemType as ModuleItemType,\n ModuleItemRequirementType,\n ModuleItemProgressStatus,\n Prisma,\n} from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n findClassWithTeacher,\n findModulesByClassId,\n findModuleByClassAndId,\n findModuleItemInClass,\n findStudentProgressForClass,\n upsertItemProgress,\n moduleInclude,\n} from \"../models/module.js\";\n\nasync function assertTeacher(userId: string, classId: string) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Class not found or you are not a teacher\",\n });\n }\n return classData;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Module CRUD */\n/* -------------------------------------------------------------------------- */\n\nexport async function listModulesRecord(userId: string, classId: string) {\n await assertTeacher(userId, classId);\n return findModulesByClassId(classId);\n}\n\nexport async function createModuleRecord(\n userId: string,\n input: { classId: string; title: string; unlockAt?: Date | null; requireSequential?: boolean }\n) {\n await assertTeacher(userId, input.classId);\n const last = await prisma.module.findFirst({\n where: { classId: input.classId },\n orderBy: { position: \"desc\" },\n select: { position: true },\n });\n return prisma.module.create({\n data: {\n classId: input.classId,\n title: input.title,\n position: (last?.position ?? 0) + 1,\n unlockAt: input.unlockAt ?? null,\n requireSequential: input.requireSequential ?? false,\n },\n include: moduleInclude,\n });\n}\n\nexport async function updateModuleRecord(\n userId: string,\n input: {\n id: string;\n classId: string;\n title?: string;\n unlockAt?: Date | null;\n requireSequential?: boolean;\n published?: boolean;\n prerequisiteIds?: string[];\n }\n) {\n await assertTeacher(userId, input.classId);\n const module = await findModuleByClassAndId(input.id, input.classId);\n if (!module) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module not found\" });\n }\n\n if (input.prerequisiteIds) {\n const prereqs = await prisma.module.findMany({\n where: { id: { in: input.prerequisiteIds }, classId: input.classId },\n select: { id: true, position: true },\n });\n if (prereqs.length !== input.prerequisiteIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Prerequisite module not found in this class\",\n });\n }\n // Like Canvas, only earlier modules can be prerequisites (prevents cycles).\n if (prereqs.some((p) => p.id === input.id || p.position >= module.position)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Prerequisites must be modules positioned before this one\",\n });\n }\n }\n\n return prisma.$transaction(async (tx) => {\n if (input.prerequisiteIds) {\n await tx.modulePrerequisite.deleteMany({ where: { moduleId: input.id } });\n if (input.prerequisiteIds.length) {\n await tx.modulePrerequisite.createMany({\n data: input.prerequisiteIds.map((prerequisiteId) => ({\n moduleId: input.id,\n prerequisiteId,\n })),\n });\n }\n }\n return tx.module.update({\n where: { id: input.id },\n data: {\n ...(input.title !== undefined && { title: input.title }),\n ...(input.unlockAt !== undefined && { unlockAt: input.unlockAt }),\n ...(input.requireSequential !== undefined && {\n requireSequential: input.requireSequential,\n }),\n ...(input.published !== undefined && { published: input.published }),\n },\n include: moduleInclude,\n });\n });\n}\n\nexport async function deleteModuleRecord(\n userId: string,\n input: { id: string; classId: string }\n) {\n await assertTeacher(userId, input.classId);\n const module = await findModuleByClassAndId(input.id, input.classId);\n if (!module) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module not found\" });\n }\n await prisma.module.delete({ where: { id: input.id } });\n return { id: input.id };\n}\n\nexport async function reorderModulesRecord(\n userId: string,\n input: { classId: string; orderedIds: string[] }\n) {\n await assertTeacher(userId, input.classId);\n const modules = await prisma.module.findMany({\n where: { classId: input.classId },\n select: { id: true },\n });\n const classIds = new Set(modules.map((m) => m.id));\n if (\n input.orderedIds.length !== classIds.size ||\n input.orderedIds.some((id) => !classIds.has(id))\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"orderedIds must contain every module of the class exactly once\",\n });\n }\n await prisma.$transaction(\n input.orderedIds.map((id, index) =>\n prisma.module.update({ where: { id }, data: { position: index + 1 } })\n )\n );\n return findModulesByClassId(input.classId);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Module items */\n/* -------------------------------------------------------------------------- */\n\nconst CONTENT_TYPES: ModuleItemType[] = [\n ModuleItemType.ASSIGNMENT,\n ModuleItemType.WORKSHEET,\n ModuleItemType.FILE,\n ModuleItemType.ANNOUNCEMENT,\n ModuleItemType.DISCUSSION,\n];\n\nconst SUBMITTABLE_TYPES: ModuleItemType[] = [\n ModuleItemType.ASSIGNMENT,\n ModuleItemType.WORKSHEET,\n];\n\nasync function validateItemInput(\n classId: string,\n input: {\n itemType: ModuleItemType;\n itemId?: string | null;\n externalUrl?: string | null;\n title?: string | null;\n requirementType?: ModuleItemRequirementType | null;\n requiredScore?: number | null;\n }\n) {\n const { itemType, itemId, externalUrl, title, requirementType } = input;\n\n if (itemType === ModuleItemType.SUB_HEADER) {\n if (!title) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Sub-header requires a title\" });\n }\n if (requirementType) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Sub-headers cannot have completion requirements\",\n });\n }\n return;\n }\n\n if (itemType === ModuleItemType.EXTERNAL_URL) {\n if (!externalUrl || !title) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"External URL items require a URL and a title\",\n });\n }\n } else if (CONTENT_TYPES.includes(itemType)) {\n if (!itemId) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"itemId is required\" });\n }\n const exists =\n itemType === ModuleItemType.ASSIGNMENT\n ? await prisma.assignment.findFirst({ where: { id: itemId, classId } })\n : itemType === ModuleItemType.WORKSHEET\n ? await prisma.worksheet.findFirst({ where: { id: itemId, classId } })\n : itemType === ModuleItemType.ANNOUNCEMENT\n ? await prisma.announcement.findFirst({ where: { id: itemId, classId } })\n : itemType === ModuleItemType.DISCUSSION\n ? await prisma.discussion.findFirst({ where: { id: itemId, classId } })\n : await prisma.file.findUnique({ where: { id: itemId } });\n if (!exists) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Referenced content not found in this class\",\n });\n }\n }\n\n if (\n (requirementType === ModuleItemRequirementType.SUBMIT ||\n requirementType === ModuleItemRequirementType.SCORE_AT_LEAST) &&\n !SUBMITTABLE_TYPES.includes(itemType)\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Submit/score requirements only apply to assignments and worksheets\",\n });\n }\n if (\n requirementType === ModuleItemRequirementType.SCORE_AT_LEAST &&\n (input.requiredScore == null || input.requiredScore < 0)\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"requiredScore is required for score requirements\",\n });\n }\n}\n\nexport async function createModuleItemRecord(\n userId: string,\n input: {\n classId: string;\n moduleId: string;\n itemType: ModuleItemType;\n itemId?: string;\n externalUrl?: string;\n title?: string;\n indent?: number;\n requirementType?: ModuleItemRequirementType;\n requiredScore?: number;\n }\n) {\n await assertTeacher(userId, input.classId);\n const module = await findModuleByClassAndId(input.moduleId, input.classId);\n if (!module) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module not found\" });\n }\n await validateItemInput(input.classId, input);\n\n const last = await prisma.courseModuleItem.findFirst({\n where: { moduleId: input.moduleId },\n orderBy: { position: \"desc\" },\n select: { position: true },\n });\n\n return prisma.courseModuleItem.create({\n data: {\n moduleId: input.moduleId,\n position: (last?.position ?? 0) + 1,\n indent: input.indent ?? 0,\n itemType: input.itemType,\n itemId: input.itemId ?? null,\n externalUrl: input.externalUrl ?? null,\n title: input.title ?? null,\n requirementType: input.requirementType ?? null,\n requiredScore:\n input.requirementType === ModuleItemRequirementType.SCORE_AT_LEAST\n ? input.requiredScore\n : null,\n },\n });\n}\n\nexport async function updateModuleItemRecord(\n userId: string,\n input: {\n classId: string;\n id: string;\n title?: string | null;\n externalUrl?: string;\n indent?: number;\n requirementType?: ModuleItemRequirementType | null;\n requiredScore?: number | null;\n }\n) {\n await assertTeacher(userId, input.classId);\n const item = await findModuleItemInClass(input.id, input.classId);\n if (!item) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n\n const requirementType =\n input.requirementType !== undefined ? input.requirementType : item.requirementType;\n const requiredScore =\n input.requiredScore !== undefined ? input.requiredScore : item.requiredScore;\n\n await validateItemInput(input.classId, {\n itemType: item.itemType,\n itemId: item.itemId,\n externalUrl: input.externalUrl !== undefined ? input.externalUrl : item.externalUrl,\n title: input.title !== undefined ? input.title : item.title,\n requirementType,\n requiredScore,\n });\n\n return prisma.courseModuleItem.update({\n where: { id: input.id },\n data: {\n ...(input.title !== undefined && { title: input.title }),\n ...(input.externalUrl !== undefined && { externalUrl: input.externalUrl }),\n ...(input.indent !== undefined && { indent: input.indent }),\n ...(input.requirementType !== undefined && {\n requirementType: input.requirementType,\n }),\n requiredScore:\n requirementType === ModuleItemRequirementType.SCORE_AT_LEAST\n ? requiredScore\n : null,\n },\n });\n}\n\nexport async function deleteModuleItemRecord(\n userId: string,\n input: { classId: string; id: string }\n) {\n await assertTeacher(userId, input.classId);\n const item = await findModuleItemInClass(input.id, input.classId);\n if (!item) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n await prisma.courseModuleItem.delete({ where: { id: input.id } });\n return { id: input.id };\n}\n\n/**\n * Reorder items, supporting drag-and-drop across modules. `items` is the full\n * new ordering: for every affected module, its items in display order.\n */\nexport async function reorderModuleItemsRecord(\n userId: string,\n input: { classId: string; items: { id: string; moduleId: string }[] }\n) {\n await assertTeacher(userId, input.classId);\n\n const itemIds = input.items.map((i) => i.id);\n const moduleIds = [...new Set(input.items.map((i) => i.moduleId))];\n\n const [dbItems, dbModules] = await Promise.all([\n prisma.courseModuleItem.findMany({\n where: { id: { in: itemIds }, module: { classId: input.classId } },\n select: { id: true },\n }),\n prisma.module.findMany({\n where: { id: { in: moduleIds }, classId: input.classId },\n select: { id: true },\n }),\n ]);\n if (dbItems.length !== itemIds.length || dbModules.length !== moduleIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Item or module not found in this class\",\n });\n }\n\n const positionByModule = new Map<string, number>();\n await prisma.$transaction(\n input.items.map((item) => {\n const next = (positionByModule.get(item.moduleId) ?? 0) + 1;\n positionByModule.set(item.moduleId, next);\n return prisma.courseModuleItem.update({\n where: { id: item.id },\n data: { moduleId: item.moduleId, position: next },\n });\n })\n );\n return findModulesByClassId(input.classId);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Student state & progress */\n/* -------------------------------------------------------------------------- */\n\ntype ModuleWithItems = Prisma.ModuleGetPayload<{\n include: typeof moduleInclude;\n}>;\n\nfunction isModuleComplete(\n module: ModuleWithItems,\n completedItemIds: Set<string>\n) {\n const required = module.items.filter((i) => i.requirementType);\n return required.every((i) => completedItemIds.has(i.id));\n}\n\n/**\n * Compute the full module state for a student: lock status, per-item\n * completion/accessibility and per-module progress percentages.\n */\nexport async function getStudentModulesState(classId: string, studentId: string) {\n const [modules, progress] = await Promise.all([\n findModulesByClassId(classId, true),\n findStudentProgressForClass(classId, studentId),\n ]);\n\n const completedItemIds = new Set(\n progress\n .filter((p) => p.status === ModuleItemProgressStatus.COMPLETE)\n .map((p) => p.moduleItemId)\n );\n\n // Students open worksheets through the assignment they are attached to, so\n // resolve each worksheet item to its containing assignment for navigation.\n const worksheetIds = [\n ...new Set(\n modules\n .flatMap((m) => m.items)\n .filter((i) => i.itemType === ModuleItemType.WORKSHEET && i.itemId)\n .map((i) => i.itemId as string)\n ),\n ];\n const worksheets = worksheetIds.length\n ? await prisma.worksheet.findMany({\n where: { id: { in: worksheetIds } },\n select: { id: true, assignments: { select: { id: true }, take: 1 } },\n })\n : [];\n const assignmentIdByWorksheetId = new Map(\n worksheets.map((w) => [w.id, w.assignments[0]?.id ?? null])\n );\n\n const completeModuleIds = new Set<string>();\n for (const module of modules) {\n if (isModuleComplete(module, completedItemIds)) {\n completeModuleIds.add(module.id);\n }\n }\n\n const now = new Date();\n let continueItemId: string | null = null;\n let continueModuleId: string | null = null;\n\n const result = modules.map((module) => {\n const publishedPrereqIds = module.prerequisites\n .map((p) => p.prerequisiteId)\n .filter((id) => modules.some((m) => m.id === id));\n const lockedByPrerequisite = publishedPrereqIds.some(\n (id) => !completeModuleIds.has(id)\n );\n const lockedByDate = !!module.unlockAt && module.unlockAt > now;\n const locked = lockedByPrerequisite || lockedByDate;\n\n const required = module.items.filter((i) => i.requirementType);\n const completedRequired = required.filter((i) => completedItemIds.has(i.id));\n const percentComplete = required.length\n ? Math.round((completedRequired.length / required.length) * 100)\n : completeModuleIds.has(module.id)\n ? 100\n : 0;\n\n // With sequential progression, items after the first incomplete required\n // item are not yet accessible.\n let sequentialBlocked = false;\n const items = module.items.map((item) => {\n const completed = completedItemIds.has(item.id);\n const accessible =\n !locked && (!module.requireSequential || !sequentialBlocked);\n if (\n module.requireSequential &&\n item.requirementType &&\n !completed &&\n !sequentialBlocked\n ) {\n sequentialBlocked = true;\n }\n if (\n !continueItemId &&\n !locked &&\n accessible &&\n item.requirementType &&\n !completed\n ) {\n continueItemId = item.id;\n continueModuleId = module.id;\n }\n return {\n ...item,\n completed,\n accessible,\n worksheetAssignmentId:\n item.itemType === ModuleItemType.WORKSHEET && item.itemId\n ? (assignmentIdByWorksheetId.get(item.itemId) ?? null)\n : null,\n };\n });\n\n return {\n ...module,\n items,\n locked,\n lockedByPrerequisite,\n lockedByDate,\n completed: completeModuleIds.has(module.id),\n requiredCount: required.length,\n completedRequiredCount: completedRequired.length,\n percentComplete,\n };\n });\n\n return {\n modules: result,\n continueItemId,\n continueModuleId,\n };\n}\n\n/**\n * Mark a module item as viewed by a student. Completes VIEW requirements;\n * for other requirement types this only records that a progress row exists.\n */\nexport async function markItemViewedRecord(\n studentId: string,\n input: { classId: string; itemId: string }\n) {\n const item = await findModuleItemInClass(input.itemId, input.classId);\n if (!item || !item.module.published) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n\n const state = await getStudentModulesState(input.classId, studentId);\n const moduleState = state.modules.find((m) => m.id === item.moduleId);\n const itemState = moduleState?.items.find((i) => i.id === item.id);\n if (!moduleState || !itemState || moduleState.locked || !itemState.accessible) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"This module item is locked\",\n });\n }\n\n if (item.requirementType === ModuleItemRequirementType.VIEW) {\n return upsertItemProgress(item.id, studentId, \"COMPLETE\");\n }\n return upsertItemProgress(item.id, studentId, \"INCOMPLETE\");\n}\n\n/* -------------------------------------------------------------------------- */\n/* Automatic completion hooks */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Update module progress for a student's assignment after a submission event\n * (submitted or returned/graded). Safe to call from any flow; never throws.\n */\nexport async function syncAssignmentModuleProgress(\n studentId: string,\n assignmentId: string\n) {\n try {\n const items = await prisma.courseModuleItem.findMany({\n where: {\n itemType: ModuleItemType.ASSIGNMENT,\n itemId: assignmentId,\n requirementType: {\n in: [\n ModuleItemRequirementType.SUBMIT,\n ModuleItemRequirementType.SCORE_AT_LEAST,\n ],\n },\n },\n });\n if (!items.length) return;\n\n const submission = await prisma.submission.findFirst({\n where: { assignmentId, studentId },\n select: { submitted: true, returned: true, gradeReceived: true },\n });\n if (!submission) return;\n\n for (const item of items) {\n const complete =\n item.requirementType === ModuleItemRequirementType.SUBMIT\n ? !!submission.submitted\n : !!submission.returned &&\n submission.gradeReceived != null &&\n submission.gradeReceived >= (item.requiredScore ?? 0);\n if (complete) {\n await upsertItemProgress(item.id, studentId, \"COMPLETE\");\n }\n }\n } catch (error) {\n logger.error(\"Failed to sync assignment module progress\", {\n error,\n studentId,\n assignmentId,\n });\n }\n}\n\n/**\n * Update module progress for a student's worksheet after grading completes.\n * SUBMIT requirements complete immediately; SCORE_AT_LEAST compares the sum\n * of earned points across the worksheet response. Never throws.\n */\nexport async function syncWorksheetModuleProgress(\n studentId: string,\n worksheetId: string\n) {\n try {\n const items = await prisma.courseModuleItem.findMany({\n where: {\n itemType: ModuleItemType.WORKSHEET,\n itemId: worksheetId,\n requirementType: {\n in: [\n ModuleItemRequirementType.SUBMIT,\n ModuleItemRequirementType.SCORE_AT_LEAST,\n ],\n },\n },\n });\n if (!items.length) return;\n\n const earned = await prisma.studentQuestionProgress.aggregate({\n where: { studentId, question: { worksheetId } },\n _sum: { points: true },\n });\n const totalPoints = earned._sum.points ?? 0;\n\n for (const item of items) {\n const complete =\n item.requirementType === ModuleItemRequirementType.SUBMIT ||\n totalPoints >= (item.requiredScore ?? 0);\n if (complete) {\n await upsertItemProgress(item.id, studentId, \"COMPLETE\");\n }\n }\n } catch (error) {\n logger.error(\"Failed to sync worksheet module progress\", {\n error,\n studentId,\n worksheetId,\n });\n }\n}\n"],"names":[],"mappings":"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","debug_id":"86e40dd6-85f3-59e2-afd9-e0da189f9288"}
1
+ {"version":3,"file":"module.js","sources":["services/module.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Module service – Canvas-style modules (\"pathways\") for classes.\n *\n * Modules are ordered groups of content items (assignments, worksheets,\n * files, announcements, discussions, external URLs, sub-headers) with\n * completion requirements, prerequisites, unlock dates and optional\n * sequential progression.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n CourseModuleItemType as ModuleItemType,\n ModuleItemRequirementType,\n ModuleItemProgressStatus,\n Prisma,\n} from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n findClassWithTeacher,\n findModulesByClassId,\n findModuleByClassAndId,\n findModuleItemInClass,\n findStudentProgressForClass,\n upsertItemProgress,\n moduleInclude,\n} from \"../models/module.js\";\n\nasync function assertTeacher(userId: string, classId: string) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Class not found or you are not a teacher\",\n });\n }\n return classData;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Module CRUD */\n/* -------------------------------------------------------------------------- */\n\nexport async function listModulesRecord(userId: string, classId: string) {\n await assertTeacher(userId, classId);\n return findModulesByClassId(classId);\n}\n\nexport async function createModuleRecord(\n userId: string,\n input: { classId: string; title: string; unlockAt?: Date | null; requireSequential?: boolean }\n) {\n await assertTeacher(userId, input.classId);\n const last = await prisma.module.findFirst({\n where: { classId: input.classId },\n orderBy: { position: \"desc\" },\n select: { position: true },\n });\n return prisma.module.create({\n data: {\n classId: input.classId,\n title: input.title,\n position: (last?.position ?? 0) + 1,\n unlockAt: input.unlockAt ?? null,\n requireSequential: input.requireSequential ?? false,\n },\n include: moduleInclude,\n });\n}\n\nexport async function updateModuleRecord(\n userId: string,\n input: {\n id: string;\n classId: string;\n title?: string;\n unlockAt?: Date | null;\n requireSequential?: boolean;\n published?: boolean;\n prerequisiteIds?: string[];\n }\n) {\n await assertTeacher(userId, input.classId);\n const module = await findModuleByClassAndId(input.id, input.classId);\n if (!module) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module not found\" });\n }\n\n if (input.prerequisiteIds) {\n const prereqs = await prisma.module.findMany({\n where: { id: { in: input.prerequisiteIds }, classId: input.classId },\n select: { id: true, position: true },\n });\n if (prereqs.length !== input.prerequisiteIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Prerequisite module not found in this class\",\n });\n }\n // Like Canvas, only earlier modules can be prerequisites (prevents cycles).\n if (prereqs.some((p) => p.id === input.id || p.position >= module.position)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Prerequisites must be modules positioned before this one\",\n });\n }\n }\n\n return prisma.$transaction(async (tx) => {\n if (input.prerequisiteIds) {\n await tx.modulePrerequisite.deleteMany({ where: { moduleId: input.id } });\n if (input.prerequisiteIds.length) {\n await tx.modulePrerequisite.createMany({\n data: input.prerequisiteIds.map((prerequisiteId) => ({\n moduleId: input.id,\n prerequisiteId,\n })),\n });\n }\n }\n return tx.module.update({\n where: { id: input.id },\n data: {\n ...(input.title !== undefined && { title: input.title }),\n ...(input.unlockAt !== undefined && { unlockAt: input.unlockAt }),\n ...(input.requireSequential !== undefined && {\n requireSequential: input.requireSequential,\n }),\n ...(input.published !== undefined && { published: input.published }),\n },\n include: moduleInclude,\n });\n });\n}\n\nexport async function deleteModuleRecord(\n userId: string,\n input: { id: string; classId: string }\n) {\n await assertTeacher(userId, input.classId);\n const module = await findModuleByClassAndId(input.id, input.classId);\n if (!module) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module not found\" });\n }\n await prisma.module.delete({ where: { id: input.id } });\n return { id: input.id };\n}\n\nexport async function reorderModulesRecord(\n userId: string,\n input: { classId: string; orderedIds: string[] }\n) {\n await assertTeacher(userId, input.classId);\n const modules = await prisma.module.findMany({\n where: { classId: input.classId },\n select: { id: true },\n });\n const classIds = new Set(modules.map((m) => m.id));\n if (\n input.orderedIds.length !== classIds.size ||\n input.orderedIds.some((id) => !classIds.has(id))\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"orderedIds must contain every module of the class exactly once\",\n });\n }\n await prisma.$transaction(\n input.orderedIds.map((id, index) =>\n prisma.module.update({ where: { id }, data: { position: index + 1 } })\n )\n );\n return findModulesByClassId(input.classId);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Module items */\n/* -------------------------------------------------------------------------- */\n\nconst CONTENT_TYPES: ModuleItemType[] = [\n ModuleItemType.ASSIGNMENT,\n ModuleItemType.WORKSHEET,\n ModuleItemType.FILE,\n ModuleItemType.ANNOUNCEMENT,\n ModuleItemType.DISCUSSION,\n ModuleItemType.VISUALIZATION,\n];\n\nconst SUBMITTABLE_TYPES: ModuleItemType[] = [\n ModuleItemType.ASSIGNMENT,\n ModuleItemType.WORKSHEET,\n];\n\nasync function validateItemInput(\n classId: string,\n input: {\n itemType: ModuleItemType;\n itemId?: string | null;\n externalUrl?: string | null;\n title?: string | null;\n requirementType?: ModuleItemRequirementType | null;\n requiredScore?: number | null;\n }\n) {\n const { itemType, itemId, externalUrl, title, requirementType } = input;\n\n if (itemType === ModuleItemType.SUB_HEADER) {\n if (!title) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Sub-header requires a title\" });\n }\n if (requirementType) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Sub-headers cannot have completion requirements\",\n });\n }\n return;\n }\n\n if (itemType === ModuleItemType.EXTERNAL_URL) {\n if (!externalUrl || !title) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"External URL items require a URL and a title\",\n });\n }\n } else if (CONTENT_TYPES.includes(itemType)) {\n if (!itemId) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"itemId is required\" });\n }\n const exists =\n itemType === ModuleItemType.ASSIGNMENT\n ? await prisma.assignment.findFirst({ where: { id: itemId, classId } })\n : itemType === ModuleItemType.WORKSHEET\n ? await prisma.worksheet.findFirst({ where: { id: itemId, classId } })\n : itemType === ModuleItemType.ANNOUNCEMENT\n ? await prisma.announcement.findFirst({ where: { id: itemId, classId } })\n : itemType === ModuleItemType.DISCUSSION\n ? await prisma.discussion.findFirst({ where: { id: itemId, classId } })\n : itemType === ModuleItemType.VISUALIZATION\n ? await prisma.visualization.findFirst({ where: { id: itemId, classId } })\n : await prisma.file.findUnique({ where: { id: itemId } });\n if (!exists) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Referenced content not found in this class\",\n });\n }\n }\n\n if (\n (requirementType === ModuleItemRequirementType.SUBMIT ||\n requirementType === ModuleItemRequirementType.SCORE_AT_LEAST) &&\n !SUBMITTABLE_TYPES.includes(itemType)\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Submit/score requirements only apply to assignments and worksheets\",\n });\n }\n if (\n requirementType === ModuleItemRequirementType.SCORE_AT_LEAST &&\n (input.requiredScore == null || input.requiredScore < 0)\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"requiredScore is required for score requirements\",\n });\n }\n}\n\nexport async function createModuleItemRecord(\n userId: string,\n input: {\n classId: string;\n moduleId: string;\n itemType: ModuleItemType;\n itemId?: string;\n externalUrl?: string;\n title?: string;\n indent?: number;\n requirementType?: ModuleItemRequirementType;\n requiredScore?: number;\n }\n) {\n await assertTeacher(userId, input.classId);\n const module = await findModuleByClassAndId(input.moduleId, input.classId);\n if (!module) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module not found\" });\n }\n await validateItemInput(input.classId, input);\n\n const last = await prisma.courseModuleItem.findFirst({\n where: { moduleId: input.moduleId },\n orderBy: { position: \"desc\" },\n select: { position: true },\n });\n\n return prisma.courseModuleItem.create({\n data: {\n moduleId: input.moduleId,\n position: (last?.position ?? 0) + 1,\n indent: input.indent ?? 0,\n itemType: input.itemType,\n itemId: input.itemId ?? null,\n externalUrl: input.externalUrl ?? null,\n title: input.title ?? null,\n requirementType: input.requirementType ?? null,\n requiredScore:\n input.requirementType === ModuleItemRequirementType.SCORE_AT_LEAST\n ? input.requiredScore\n : null,\n },\n });\n}\n\nexport async function updateModuleItemRecord(\n userId: string,\n input: {\n classId: string;\n id: string;\n title?: string | null;\n externalUrl?: string;\n indent?: number;\n requirementType?: ModuleItemRequirementType | null;\n requiredScore?: number | null;\n }\n) {\n await assertTeacher(userId, input.classId);\n const item = await findModuleItemInClass(input.id, input.classId);\n if (!item) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n\n const requirementType =\n input.requirementType !== undefined ? input.requirementType : item.requirementType;\n const requiredScore =\n input.requiredScore !== undefined ? input.requiredScore : item.requiredScore;\n\n await validateItemInput(input.classId, {\n itemType: item.itemType,\n itemId: item.itemId,\n externalUrl: input.externalUrl !== undefined ? input.externalUrl : item.externalUrl,\n title: input.title !== undefined ? input.title : item.title,\n requirementType,\n requiredScore,\n });\n\n return prisma.courseModuleItem.update({\n where: { id: input.id },\n data: {\n ...(input.title !== undefined && { title: input.title }),\n ...(input.externalUrl !== undefined && { externalUrl: input.externalUrl }),\n ...(input.indent !== undefined && { indent: input.indent }),\n ...(input.requirementType !== undefined && {\n requirementType: input.requirementType,\n }),\n requiredScore:\n requirementType === ModuleItemRequirementType.SCORE_AT_LEAST\n ? requiredScore\n : null,\n },\n });\n}\n\nexport async function deleteModuleItemRecord(\n userId: string,\n input: { classId: string; id: string }\n) {\n await assertTeacher(userId, input.classId);\n const item = await findModuleItemInClass(input.id, input.classId);\n if (!item) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n await prisma.courseModuleItem.delete({ where: { id: input.id } });\n return { id: input.id };\n}\n\n/**\n * Reorder items, supporting drag-and-drop across modules. `items` is the full\n * new ordering: for every affected module, its items in display order.\n */\nexport async function reorderModuleItemsRecord(\n userId: string,\n input: { classId: string; items: { id: string; moduleId: string }[] }\n) {\n await assertTeacher(userId, input.classId);\n\n const itemIds = input.items.map((i) => i.id);\n const moduleIds = [...new Set(input.items.map((i) => i.moduleId))];\n\n const [dbItems, dbModules] = await Promise.all([\n prisma.courseModuleItem.findMany({\n where: { id: { in: itemIds }, module: { classId: input.classId } },\n select: { id: true },\n }),\n prisma.module.findMany({\n where: { id: { in: moduleIds }, classId: input.classId },\n select: { id: true },\n }),\n ]);\n if (dbItems.length !== itemIds.length || dbModules.length !== moduleIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Item or module not found in this class\",\n });\n }\n\n const positionByModule = new Map<string, number>();\n await prisma.$transaction(\n input.items.map((item) => {\n const next = (positionByModule.get(item.moduleId) ?? 0) + 1;\n positionByModule.set(item.moduleId, next);\n return prisma.courseModuleItem.update({\n where: { id: item.id },\n data: { moduleId: item.moduleId, position: next },\n });\n })\n );\n return findModulesByClassId(input.classId);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Student state & progress */\n/* -------------------------------------------------------------------------- */\n\ntype ModuleWithItems = Prisma.ModuleGetPayload<{\n include: typeof moduleInclude;\n}>;\n\nfunction isModuleComplete(\n module: ModuleWithItems,\n completedItemIds: Set<string>\n) {\n const required = module.items.filter((i) => i.requirementType);\n return required.every((i) => completedItemIds.has(i.id));\n}\n\n/**\n * Compute the full module state for a student: lock status, per-item\n * completion/accessibility and per-module progress percentages.\n */\nexport async function getStudentModulesState(classId: string, studentId: string) {\n const [allModules, progress] = await Promise.all([\n findModulesByClassId(classId, true),\n findStudentProgressForClass(classId, studentId),\n ]);\n\n // Hide visualisations the teacher hasn't published yet.\n const visualizationIds = allModules\n .flatMap((m) => m.items)\n .filter((i) => i.itemType === ModuleItemType.VISUALIZATION && i.itemId)\n .map((i) => i.itemId as string);\n const publishedVisualizationIds = new Set(\n visualizationIds.length\n ? (\n await prisma.visualization.findMany({\n where: { id: { in: visualizationIds }, classId, published: true },\n select: { id: true },\n })\n ).map((v) => v.id)\n : []\n );\n const modules = allModules.map((m) => ({\n ...m,\n items: m.items.filter(\n (i) =>\n i.itemType !== ModuleItemType.VISUALIZATION ||\n (!!i.itemId && publishedVisualizationIds.has(i.itemId))\n ),\n }));\n\n const completedItemIds = new Set(\n progress\n .filter((p) => p.status === ModuleItemProgressStatus.COMPLETE)\n .map((p) => p.moduleItemId)\n );\n\n // Students open worksheets through the assignment they are attached to, so\n // resolve each worksheet item to its containing assignment for navigation.\n const worksheetIds = [\n ...new Set(\n modules\n .flatMap((m) => m.items)\n .filter((i) => i.itemType === ModuleItemType.WORKSHEET && i.itemId)\n .map((i) => i.itemId as string)\n ),\n ];\n const worksheets = worksheetIds.length\n ? await prisma.worksheet.findMany({\n where: { id: { in: worksheetIds } },\n select: { id: true, assignments: { select: { id: true }, take: 1 } },\n })\n : [];\n const assignmentIdByWorksheetId = new Map(\n worksheets.map((w) => [w.id, w.assignments[0]?.id ?? null])\n );\n\n const completeModuleIds = new Set<string>();\n for (const module of modules) {\n if (isModuleComplete(module, completedItemIds)) {\n completeModuleIds.add(module.id);\n }\n }\n\n const now = new Date();\n let continueItemId: string | null = null;\n let continueModuleId: string | null = null;\n\n const result = modules.map((module) => {\n const publishedPrereqIds = module.prerequisites\n .map((p) => p.prerequisiteId)\n .filter((id) => modules.some((m) => m.id === id));\n const lockedByPrerequisite = publishedPrereqIds.some(\n (id) => !completeModuleIds.has(id)\n );\n const lockedByDate = !!module.unlockAt && module.unlockAt > now;\n const locked = lockedByPrerequisite || lockedByDate;\n\n const required = module.items.filter((i) => i.requirementType);\n const completedRequired = required.filter((i) => completedItemIds.has(i.id));\n const percentComplete = required.length\n ? Math.round((completedRequired.length / required.length) * 100)\n : completeModuleIds.has(module.id)\n ? 100\n : 0;\n\n // With sequential progression, items after the first incomplete required\n // item are not yet accessible.\n let sequentialBlocked = false;\n const items = module.items.map((item) => {\n const completed = completedItemIds.has(item.id);\n const accessible =\n !locked && (!module.requireSequential || !sequentialBlocked);\n if (\n module.requireSequential &&\n item.requirementType &&\n !completed &&\n !sequentialBlocked\n ) {\n sequentialBlocked = true;\n }\n if (\n !continueItemId &&\n !locked &&\n accessible &&\n item.requirementType &&\n !completed\n ) {\n continueItemId = item.id;\n continueModuleId = module.id;\n }\n return {\n ...item,\n completed,\n accessible,\n worksheetAssignmentId:\n item.itemType === ModuleItemType.WORKSHEET && item.itemId\n ? (assignmentIdByWorksheetId.get(item.itemId) ?? null)\n : null,\n };\n });\n\n return {\n ...module,\n items,\n locked,\n lockedByPrerequisite,\n lockedByDate,\n completed: completeModuleIds.has(module.id),\n requiredCount: required.length,\n completedRequiredCount: completedRequired.length,\n percentComplete,\n };\n });\n\n return {\n modules: result,\n continueItemId,\n continueModuleId,\n };\n}\n\n/**\n * Mark a module item as viewed by a student. Completes VIEW requirements;\n * for other requirement types this only records that a progress row exists.\n */\nexport async function markItemViewedRecord(\n studentId: string,\n input: { classId: string; itemId: string }\n) {\n const item = await findModuleItemInClass(input.itemId, input.classId);\n if (!item || !item.module.published) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n\n const state = await getStudentModulesState(input.classId, studentId);\n const moduleState = state.modules.find((m) => m.id === item.moduleId);\n const itemState = moduleState?.items.find((i) => i.id === item.id);\n if (!moduleState || !itemState || moduleState.locked || !itemState.accessible) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"This module item is locked\",\n });\n }\n\n if (item.requirementType === ModuleItemRequirementType.VIEW) {\n return upsertItemProgress(item.id, studentId, \"COMPLETE\");\n }\n return upsertItemProgress(item.id, studentId, \"INCOMPLETE\");\n}\n\n/* -------------------------------------------------------------------------- */\n/* Automatic completion hooks */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Update module progress for a student's assignment after a submission event\n * (submitted or returned/graded). Safe to call from any flow; never throws.\n */\nexport async function syncAssignmentModuleProgress(\n studentId: string,\n assignmentId: string\n) {\n try {\n const items = await prisma.courseModuleItem.findMany({\n where: {\n itemType: ModuleItemType.ASSIGNMENT,\n itemId: assignmentId,\n requirementType: {\n in: [\n ModuleItemRequirementType.SUBMIT,\n ModuleItemRequirementType.SCORE_AT_LEAST,\n ],\n },\n },\n });\n if (!items.length) return;\n\n const submission = await prisma.submission.findFirst({\n where: { assignmentId, studentId },\n select: { submitted: true, returned: true, gradeReceived: true },\n });\n if (!submission) return;\n\n for (const item of items) {\n const complete =\n item.requirementType === ModuleItemRequirementType.SUBMIT\n ? !!submission.submitted\n : !!submission.returned &&\n submission.gradeReceived != null &&\n submission.gradeReceived >= (item.requiredScore ?? 0);\n if (complete) {\n await upsertItemProgress(item.id, studentId, \"COMPLETE\");\n }\n }\n } catch (error) {\n logger.error(\"Failed to sync assignment module progress\", {\n error,\n studentId,\n assignmentId,\n });\n }\n}\n\n/**\n * Update module progress for a student's worksheet after grading completes.\n * SUBMIT requirements complete immediately; SCORE_AT_LEAST compares the sum\n * of earned points across the worksheet response. Never throws.\n */\nexport async function syncWorksheetModuleProgress(\n studentId: string,\n worksheetId: string\n) {\n try {\n const items = await prisma.courseModuleItem.findMany({\n where: {\n itemType: ModuleItemType.WORKSHEET,\n itemId: worksheetId,\n requirementType: {\n in: [\n ModuleItemRequirementType.SUBMIT,\n ModuleItemRequirementType.SCORE_AT_LEAST,\n ],\n },\n },\n });\n if (!items.length) return;\n\n const earned = await prisma.studentQuestionProgress.aggregate({\n where: { studentId, question: { worksheetId } },\n _sum: { points: true },\n });\n const totalPoints = earned._sum.points ?? 0;\n\n for (const item of items) {\n const complete =\n item.requirementType === ModuleItemRequirementType.SUBMIT ||\n totalPoints >= (item.requiredScore ?? 0);\n if (complete) {\n await upsertItemProgress(item.id, studentId, \"COMPLETE\");\n }\n }\n } catch (error) {\n logger.error(\"Failed to sync worksheet module progress\", {\n error,\n studentId,\n worksheetId,\n });\n }\n}\n"],"names":[],"mappings":"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","debug_id":"69f3db7b-9e94-5f6e-9e8b-f196705cf116"}
@@ -0,0 +1,72 @@
1
+ /** Teachers see every visualisation in the class; students only published ones. */
2
+ export declare function listVisualizations(userId: string, classId: string): Promise<{
3
+ id: string;
4
+ createdAt: Date;
5
+ updatedAt: Date;
6
+ classId: string;
7
+ title: string;
8
+ prompt: string | null;
9
+ published: boolean;
10
+ }[]>;
11
+ export declare function getVisualization(userId: string, classId: string, id: string): Promise<{
12
+ id: string;
13
+ createdAt: Date;
14
+ updatedAt: Date;
15
+ classId: string;
16
+ title: string;
17
+ prompt: string | null;
18
+ published: boolean;
19
+ html: string;
20
+ }>;
21
+ export declare function createVisualization(userId: string, input: {
22
+ classId: string;
23
+ prompt: string;
24
+ title?: string;
25
+ }): Promise<{
26
+ id: string;
27
+ createdAt: Date;
28
+ updatedAt: Date;
29
+ classId: string;
30
+ title: string;
31
+ prompt: string | null;
32
+ published: boolean;
33
+ html: string;
34
+ }>;
35
+ export declare function reviseVisualizationRecord(userId: string, input: {
36
+ classId: string;
37
+ id: string;
38
+ instruction: string;
39
+ }): Promise<{
40
+ id: string;
41
+ createdAt: Date;
42
+ updatedAt: Date;
43
+ classId: string;
44
+ title: string;
45
+ prompt: string | null;
46
+ published: boolean;
47
+ html: string;
48
+ }>;
49
+ export declare function updateVisualization(input: {
50
+ classId: string;
51
+ id: string;
52
+ title?: string;
53
+ html?: string;
54
+ published?: boolean;
55
+ }): Promise<{
56
+ id: string;
57
+ createdAt: Date;
58
+ updatedAt: Date;
59
+ classId: string;
60
+ title: string;
61
+ prompt: string | null;
62
+ published: boolean;
63
+ html: string;
64
+ }>;
65
+ /** Deletes the visualisation and any module items that pointed at it. */
66
+ export declare function deleteVisualization(input: {
67
+ classId: string;
68
+ id: string;
69
+ }): Promise<{
70
+ id: string;
71
+ }>;
72
+ //# sourceMappingURL=visualization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visualization.d.ts","sourceRoot":"/","sources":["services/visualization.ts"],"names":[],"mappings":"AA+CA,mFAAmF;AACnF,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;KAOvE;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;;;;;;;;GAUjF;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAmB3D;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAkB5D;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;;;;;;;;;GAcA;AAED,yEAAyE;AACzE,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE;;GAS/E"}
@@ -0,0 +1,122 @@
1
+
2
+ !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]="ce0610d2-b722-5212-95c5-af7baafc7cb6")}catch(e){}}();
3
+ import { TRPCError } from "@trpc/server";
4
+ import { prisma } from "../lib/prisma.js";
5
+ import { isTeacherInClass } from "../models/class.js";
6
+ import { generateVisualization, MAX_VISUALIZATION_HTML_LENGTH, reviseVisualization, } from "../pipelines/generateVisualization.js";
7
+ const summarySelect = {
8
+ id: true,
9
+ classId: true,
10
+ title: true,
11
+ prompt: true,
12
+ published: true,
13
+ createdAt: true,
14
+ updatedAt: true,
15
+ };
16
+ const detailSelect = { ...summarySelect, html: true };
17
+ async function getClassContext(classId) {
18
+ return prisma.class.findUnique({
19
+ where: { id: classId },
20
+ select: { name: true, subject: true, schoolId: true },
21
+ });
22
+ }
23
+ async function findTeacherVisualization(classId, id) {
24
+ const viz = await prisma.visualization.findFirst({
25
+ where: { id, classId },
26
+ select: detailSelect,
27
+ });
28
+ if (!viz) {
29
+ throw new TRPCError({ code: "NOT_FOUND", message: "Visualisation not found" });
30
+ }
31
+ return viz;
32
+ }
33
+ function aiError(error) {
34
+ throw new TRPCError({
35
+ code: "INTERNAL_SERVER_ERROR",
36
+ message: "Newton couldn't build that visualisation. Try rephrasing it.",
37
+ cause: error,
38
+ });
39
+ }
40
+ /** Teachers see every visualisation in the class; students only published ones. */
41
+ export async function listVisualizations(userId, classId) {
42
+ const isTeacher = !!(await isTeacherInClass(classId, userId));
43
+ return prisma.visualization.findMany({
44
+ where: { classId, ...(isTeacher ? {} : { published: true }) },
45
+ select: summarySelect,
46
+ orderBy: { updatedAt: "desc" },
47
+ });
48
+ }
49
+ export async function getVisualization(userId, classId, id) {
50
+ const isTeacher = !!(await isTeacherInClass(classId, userId));
51
+ const viz = await prisma.visualization.findFirst({
52
+ where: { id, classId, ...(isTeacher ? {} : { published: true }) },
53
+ select: detailSelect,
54
+ });
55
+ if (!viz) {
56
+ throw new TRPCError({ code: "NOT_FOUND", message: "Visualisation not found" });
57
+ }
58
+ return viz;
59
+ }
60
+ export async function createVisualization(userId, input) {
61
+ const cls = await getClassContext(input.classId);
62
+ const generated = await generateVisualization(input.prompt, {
63
+ className: cls?.name,
64
+ subject: cls?.subject,
65
+ attribution: { userId, classId: input.classId, schoolId: cls?.schoolId },
66
+ }).catch(aiError);
67
+ return prisma.visualization.create({
68
+ data: {
69
+ classId: input.classId,
70
+ createdById: userId,
71
+ title: input.title?.trim() || generated.title,
72
+ prompt: input.prompt,
73
+ html: generated.html,
74
+ },
75
+ select: detailSelect,
76
+ });
77
+ }
78
+ export async function reviseVisualizationRecord(userId, input) {
79
+ const current = await findTeacherVisualization(input.classId, input.id);
80
+ const cls = await getClassContext(input.classId);
81
+ const revised = await reviseVisualization(current, input.instruction, {
82
+ className: cls?.name,
83
+ subject: cls?.subject,
84
+ attribution: { userId, classId: input.classId, schoolId: cls?.schoolId },
85
+ }).catch(aiError);
86
+ return prisma.visualization.update({
87
+ where: { id: current.id },
88
+ data: {
89
+ html: revised.html,
90
+ prompt: [current.prompt, input.instruction].filter(Boolean).join("\n\n"),
91
+ },
92
+ select: detailSelect,
93
+ });
94
+ }
95
+ export async function updateVisualization(input) {
96
+ const current = await findTeacherVisualization(input.classId, input.id);
97
+ if (input.html !== undefined && input.html.length > MAX_VISUALIZATION_HTML_LENGTH) {
98
+ throw new TRPCError({ code: "BAD_REQUEST", message: "Visualisation is too large" });
99
+ }
100
+ return prisma.visualization.update({
101
+ where: { id: current.id },
102
+ data: {
103
+ ...(input.title !== undefined ? { title: input.title } : {}),
104
+ ...(input.html !== undefined ? { html: input.html } : {}),
105
+ ...(input.published !== undefined ? { published: input.published } : {}),
106
+ },
107
+ select: detailSelect,
108
+ });
109
+ }
110
+ /** Deletes the visualisation and any module items that pointed at it. */
111
+ export async function deleteVisualization(input) {
112
+ const current = await findTeacherVisualization(input.classId, input.id);
113
+ await prisma.$transaction([
114
+ prisma.courseModuleItem.deleteMany({
115
+ where: { itemType: "VISUALIZATION", itemId: current.id },
116
+ }),
117
+ prisma.visualization.delete({ where: { id: current.id } }),
118
+ ]);
119
+ return { id: current.id };
120
+ }
121
+ //# sourceMappingURL=visualization.js.map
122
+ //# debugId=ce0610d2-b722-5212-95c5-af7baafc7cb6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visualization.js","sources":["services/visualization.ts"],"sourceRoot":"/","sourcesContent":["import { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { isTeacherInClass } from \"../models/class.js\";\nimport {\n generateVisualization,\n MAX_VISUALIZATION_HTML_LENGTH,\n reviseVisualization,\n} from \"../pipelines/generateVisualization.js\";\n\nconst summarySelect = {\n id: true,\n classId: true,\n title: true,\n prompt: true,\n published: true,\n createdAt: true,\n updatedAt: true,\n} as const;\n\nconst detailSelect = { ...summarySelect, html: true } as const;\n\nasync function getClassContext(classId: string) {\n return prisma.class.findUnique({\n where: { id: classId },\n select: { name: true, subject: true, schoolId: true },\n });\n}\n\nasync function findTeacherVisualization(classId: string, id: string) {\n const viz = await prisma.visualization.findFirst({\n where: { id, classId },\n select: detailSelect,\n });\n if (!viz) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Visualisation not found\" });\n }\n return viz;\n}\n\nfunction aiError(error: unknown): never {\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Newton couldn't build that visualisation. Try rephrasing it.\",\n cause: error,\n });\n}\n\n/** Teachers see every visualisation in the class; students only published ones. */\nexport async function listVisualizations(userId: string, classId: string) {\n const isTeacher = !!(await isTeacherInClass(classId, userId));\n return prisma.visualization.findMany({\n where: { classId, ...(isTeacher ? {} : { published: true }) },\n select: summarySelect,\n orderBy: { updatedAt: \"desc\" },\n });\n}\n\nexport async function getVisualization(userId: string, classId: string, id: string) {\n const isTeacher = !!(await isTeacherInClass(classId, userId));\n const viz = await prisma.visualization.findFirst({\n where: { id, classId, ...(isTeacher ? {} : { published: true }) },\n select: detailSelect,\n });\n if (!viz) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Visualisation not found\" });\n }\n return viz;\n}\n\nexport async function createVisualization(\n userId: string,\n input: { classId: string; prompt: string; title?: string },\n) {\n const cls = await getClassContext(input.classId);\n const generated = await generateVisualization(input.prompt, {\n className: cls?.name,\n subject: cls?.subject,\n attribution: { userId, classId: input.classId, schoolId: cls?.schoolId },\n }).catch(aiError);\n\n return prisma.visualization.create({\n data: {\n classId: input.classId,\n createdById: userId,\n title: input.title?.trim() || generated.title,\n prompt: input.prompt,\n html: generated.html,\n },\n select: detailSelect,\n });\n}\n\nexport async function reviseVisualizationRecord(\n userId: string,\n input: { classId: string; id: string; instruction: string },\n) {\n const current = await findTeacherVisualization(input.classId, input.id);\n const cls = await getClassContext(input.classId);\n const revised = await reviseVisualization(current, input.instruction, {\n className: cls?.name,\n subject: cls?.subject,\n attribution: { userId, classId: input.classId, schoolId: cls?.schoolId },\n }).catch(aiError);\n\n return prisma.visualization.update({\n where: { id: current.id },\n data: {\n html: revised.html,\n prompt: [current.prompt, input.instruction].filter(Boolean).join(\"\\n\\n\"),\n },\n select: detailSelect,\n });\n}\n\nexport async function updateVisualization(input: {\n classId: string;\n id: string;\n title?: string;\n html?: string;\n published?: boolean;\n}) {\n const current = await findTeacherVisualization(input.classId, input.id);\n if (input.html !== undefined && input.html.length > MAX_VISUALIZATION_HTML_LENGTH) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Visualisation is too large\" });\n }\n return prisma.visualization.update({\n where: { id: current.id },\n data: {\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.html !== undefined ? { html: input.html } : {}),\n ...(input.published !== undefined ? { published: input.published } : {}),\n },\n select: detailSelect,\n });\n}\n\n/** Deletes the visualisation and any module items that pointed at it. */\nexport async function deleteVisualization(input: { classId: string; id: string }) {\n const current = await findTeacherVisualization(input.classId, input.id);\n await prisma.$transaction([\n prisma.courseModuleItem.deleteMany({\n where: { itemType: \"VISUALIZATION\", itemId: current.id },\n }),\n prisma.visualization.delete({ where: { id: current.id } }),\n ]);\n return { id: current.id };\n}\n"],"names":[],"mappings":"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","debug_id":"ce0610d2-b722-5212-95c5-af7baafc7cb6"}
@@ -0,0 +1,3 @@
1
+ import type { TRPCError } from '@trpc/server';
2
+ export declare function isReportableTrpcError(error: Pick<TRPCError, 'code'>): boolean;
3
+ //# sourceMappingURL=sentryTrpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentryTrpc.d.ts","sourceRoot":"/","sources":["utils/sentryTrpc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAsB9C,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,OAAO,CAE7E"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Error codes that mean "the caller did something wrong" — noise in Sentry.
3
+ * Everything else (server faults, unhandled Prisma/AI failures) is reported.
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]="450e7279-31f8-530d-b245-0d62551d7c22")}catch(e){}}();
7
+ const EXPECTED_CODES = new Set([
8
+ 'BAD_REQUEST',
9
+ 'PARSE_ERROR',
10
+ 'UNAUTHORIZED',
11
+ 'FORBIDDEN',
12
+ 'NOT_FOUND',
13
+ 'CONFLICT',
14
+ 'PRECONDITION_FAILED',
15
+ 'PAYLOAD_TOO_LARGE',
16
+ 'UNPROCESSABLE_CONTENT',
17
+ 'TOO_MANY_REQUESTS',
18
+ 'CLIENT_CLOSED_REQUEST',
19
+ 'METHOD_NOT_SUPPORTED',
20
+ 'UNSUPPORTED_MEDIA_TYPE',
21
+ ]);
22
+ export function isReportableTrpcError(error) {
23
+ return !EXPECTED_CODES.has(error.code);
24
+ }
25
+ //# sourceMappingURL=sentryTrpc.js.map
26
+ //# debugId=450e7279-31f8-530d-b245-0d62551d7c22
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentryTrpc.js","sources":["utils/sentryTrpc.ts"],"sourceRoot":"/","sourcesContent":["import type { TRPCError } from '@trpc/server';\n\n/**\n * Error codes that mean \"the caller did something wrong\" — noise in Sentry.\n * Everything else (server faults, unhandled Prisma/AI failures) is reported.\n */\nconst EXPECTED_CODES = new Set([\n 'BAD_REQUEST',\n 'PARSE_ERROR',\n 'UNAUTHORIZED',\n 'FORBIDDEN',\n 'NOT_FOUND',\n 'CONFLICT',\n 'PRECONDITION_FAILED',\n 'PAYLOAD_TOO_LARGE',\n 'UNPROCESSABLE_CONTENT',\n 'TOO_MANY_REQUESTS',\n 'CLIENT_CLOSED_REQUEST',\n 'METHOD_NOT_SUPPORTED',\n 'UNSUPPORTED_MEDIA_TYPE',\n]);\n\nexport function isReportableTrpcError(error: Pick<TRPCError, 'code'>): boolean {\n return !EXPECTED_CODES.has(error.code);\n}\n"],"names":[],"mappings":"AAEA;;;GAGG;;;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,aAAa;IACb,aAAa;IACb,cAAc;IACd,WAAW;IACX,WAAW;IACX,UAAU;IACV,qBAAqB;IACrB,mBAAmB;IACnB,uBAAuB;IACvB,mBAAmB;IACnB,uBAAuB;IACvB,sBAAsB;IACtB,wBAAwB;CACzB,CAAC,CAAC;AAEH,MAAM,UAAU,qBAAqB,CAAC,KAA8B;IAClE,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC","debug_id":"450e7279-31f8-530d-b245-0d62551d7c22"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studious-lms/server",
3
- "version": "1.27.0",
3
+ "version": "1.28.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,27 @@
1
+ -- AlterEnum
2
+ ALTER TYPE "CourseModuleItemType" ADD VALUE 'VISUALIZATION';
3
+
4
+ -- CreateTable
5
+ CREATE TABLE "Visualization" (
6
+ "id" TEXT NOT NULL,
7
+ "classId" TEXT NOT NULL,
8
+ "createdById" TEXT,
9
+ "title" TEXT NOT NULL,
10
+ "prompt" TEXT,
11
+ "html" TEXT NOT NULL,
12
+ "published" BOOLEAN NOT NULL DEFAULT false,
13
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
14
+ "updatedAt" TIMESTAMP(3) NOT NULL,
15
+
16
+ CONSTRAINT "Visualization_pkey" PRIMARY KEY ("id")
17
+ );
18
+
19
+ -- CreateIndex
20
+ CREATE INDEX "Visualization_classId_idx" ON "Visualization"("classId");
21
+
22
+ -- AddForeignKey
23
+ ALTER TABLE "Visualization" ADD CONSTRAINT "Visualization_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE CASCADE ON UPDATE CASCADE;
24
+
25
+ -- AddForeignKey
26
+ ALTER TABLE "Visualization" ADD CONSTRAINT "Visualization_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
27
+
@@ -328,6 +328,7 @@ model User {
328
328
  discussions Discussion[]
329
329
  discussionReplies DiscussionReply[]
330
330
  discussionReads DiscussionRead[]
331
+ visualizations Visualization[]
331
332
  moduleItemProgress ModuleItemProgress[]
332
333
  customGradeEntries CustomGradeEntry[] @relation("UserCustomGradeEntries")
333
334
  fileAnnotations FileAnnotation[] @relation("AuthoredFileAnnotations")
@@ -430,6 +431,7 @@ model Class {
430
431
  studentsCanReply Boolean @default(true)
431
432
 
432
433
  modules Module[]
434
+ visualizations Visualization[]
433
435
 
434
436
  /// Teacher-controlled ClassSidebar visibility. Keys match nav hrefs
435
437
  /// without leading slash (e.g. "assignments", "quizzes"). Null = all defaults on.
@@ -1497,6 +1499,7 @@ enum CourseModuleItemType {
1497
1499
  DISCUSSION
1498
1500
  EXTERNAL_URL
1499
1501
  SUB_HEADER
1502
+ VISUALIZATION
1500
1503
  }
1501
1504
 
1502
1505
  enum ModuleItemRequirementType {
@@ -1685,3 +1688,24 @@ model FeePayment {
1685
1688
  @@index([schoolId])
1686
1689
  @@index([paidAt])
1687
1690
  }
1691
+
1692
+ /// Teacher-authored interactive visualisation (a sandboxed HTML/JS document,
1693
+ /// usually drafted by Newton) that can be attached to modules for students.
1694
+ model Visualization {
1695
+ id String @id @default(uuid())
1696
+ classId String
1697
+ class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
1698
+ createdById String?
1699
+ createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
1700
+ title String
1701
+ /// The teacher's request the current version was generated from.
1702
+ prompt String?
1703
+ /// Self-contained HTML document rendered in a sandboxed iframe.
1704
+ html String
1705
+ /// Students can only open published visualisations.
1706
+ published Boolean @default(false)
1707
+ createdAt DateTime @default(now())
1708
+ updatedAt DateTime @updatedAt
1709
+
1710
+ @@index([classId])
1711
+ }