@studious-lms/server 1.25.0 → 1.26.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 (50) hide show
  1. package/dist/models/marketplace.d.ts +35 -0
  2. package/dist/models/marketplace.d.ts.map +1 -1
  3. package/dist/models/marketplace.js +9 -2
  4. package/dist/models/marketplace.js.map +1 -1
  5. package/dist/models/module.d.ts +228 -0
  6. package/dist/models/module.d.ts.map +1 -0
  7. package/dist/models/module.js +69 -0
  8. package/dist/models/module.js.map +1 -0
  9. package/dist/pipelines/gradeWorksheet.d.ts.map +1 -1
  10. package/dist/pipelines/gradeWorksheet.js +4 -2
  11. package/dist/pipelines/gradeWorksheet.js.map +1 -1
  12. package/dist/routers/_app.d.ts +760 -0
  13. package/dist/routers/_app.d.ts.map +1 -1
  14. package/dist/routers/_app.js +4 -2
  15. package/dist/routers/_app.js.map +1 -1
  16. package/dist/routers/marketplace.d.ts +41 -0
  17. package/dist/routers/marketplace.d.ts.map +1 -1
  18. package/dist/routers/marketplace.js +13 -3
  19. package/dist/routers/marketplace.js.map +1 -1
  20. package/dist/routers/module.d.ts +345 -0
  21. package/dist/routers/module.d.ts.map +1 -0
  22. package/dist/routers/module.js +82 -0
  23. package/dist/routers/module.js.map +1 -0
  24. package/dist/services/assignment.d.ts.map +1 -1
  25. package/dist/services/assignment.js +8 -3
  26. package/dist/services/assignment.js.map +1 -1
  27. package/dist/services/marketplace.d.ts +36 -0
  28. package/dist/services/marketplace.d.ts.map +1 -1
  29. package/dist/services/marketplace.js +30 -3
  30. package/dist/services/marketplace.js.map +1 -1
  31. package/dist/services/module.d.ts +288 -0
  32. package/dist/services/module.d.ts.map +1 -0
  33. package/dist/services/module.js +518 -0
  34. package/dist/services/module.js.map +1 -0
  35. package/dist/services/school.d.ts.map +1 -1
  36. package/dist/services/school.js +17 -5
  37. package/dist/services/school.js.map +1 -1
  38. package/package.json +1 -1
  39. package/prisma/migrations/20260708013000_add_modules/migration.sql +100 -0
  40. package/prisma/schema.prisma +93 -0
  41. package/src/models/marketplace.ts +16 -0
  42. package/src/models/module.ts +77 -0
  43. package/src/pipelines/gradeWorksheet.ts +6 -0
  44. package/src/routers/_app.ts +2 -0
  45. package/src/routers/marketplace.ts +16 -0
  46. package/src/routers/module.ts +118 -0
  47. package/src/services/assignment.ts +12 -1
  48. package/src/services/marketplace.ts +39 -0
  49. package/src/services/module.ts +683 -0
  50. package/src/services/school.ts +15 -3
@@ -2,7 +2,7 @@
2
2
  * School service - school admin workflow, memberships, and invites.
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]="7675f5a8-bfcb-53db-b66d-cdd4c8755f46")}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]="c3d38743-6297-594a-9bde-bf049584e6b4")}catch(e){}}();
6
6
  import { SessionType } from "@prisma/client";
7
7
  import { TRPCError } from "@trpc/server";
8
8
  import { hash } from "bcryptjs";
@@ -465,6 +465,7 @@ export async function getStudentTimeline(userId, input) {
465
465
  where: {
466
466
  userId: input.studentId,
467
467
  startTime: range,
468
+ OR: [{ classId: null }, { class: { schoolId: input.schoolId } }],
468
469
  },
469
470
  select: {
470
471
  id: true,
@@ -481,6 +482,7 @@ export async function getStudentTimeline(userId, input) {
481
482
  prisma.assignment.findMany({
482
483
  where: {
483
484
  class: {
485
+ schoolId: input.schoolId,
484
486
  students: { some: { id: input.studentId } },
485
487
  },
486
488
  template: false,
@@ -626,6 +628,7 @@ export async function getMemberTimeline(userId, input) {
626
628
  where: {
627
629
  userId: input.memberId,
628
630
  startTime: range,
631
+ OR: [{ classId: null }, { class: { schoolId: input.schoolId } }],
629
632
  },
630
633
  select: {
631
634
  id: true,
@@ -641,7 +644,10 @@ export async function getMemberTimeline(userId, input) {
641
644
  }),
642
645
  prisma.assignment.findMany({
643
646
  where: {
644
- class: { students: { some: { id: input.memberId } } },
647
+ class: {
648
+ schoolId: input.schoolId,
649
+ students: { some: { id: input.memberId } },
650
+ },
645
651
  template: false,
646
652
  dueDate: range,
647
653
  },
@@ -729,8 +735,14 @@ export async function getMemberTimeline(userId, input) {
729
735
  prisma.event.findMany({
730
736
  where: {
731
737
  OR: [
732
- { userId: input.memberId },
733
- { class: { teachers: { some: { id: input.memberId } } } },
738
+ { userId: input.memberId, classId: null },
739
+ { userId: input.memberId, class: { schoolId: input.schoolId } },
740
+ {
741
+ class: {
742
+ schoolId: input.schoolId,
743
+ teachers: { some: { id: input.memberId } },
744
+ },
745
+ },
734
746
  ],
735
747
  startTime: range,
736
748
  },
@@ -909,4 +921,4 @@ export async function acceptInvite(userId, token) {
909
921
  return { membership };
910
922
  }
911
923
  //# sourceMappingURL=school.js.map
912
- //# debugId=7675f5a8-bfcb-53db-b66d-cdd4c8755f46
924
+ //# debugId=c3d38743-6297-594a-9bde-bf049584e6b4
@@ -1 +1 @@
1
- {"version":3,"file":"school.js","sources":["services/school.ts"],"sourceRoot":"/","sourcesContent":["/**\n * School service - school admin workflow, memberships, and invites.\n */\nimport { SchoolMembershipRole, SessionType } from \"@prisma/client\";\nimport { TRPCError } from \"@trpc/server\";\nimport { hash } from \"bcryptjs\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { env } from \"../lib/config/env.js\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { sendMail } from \"../utils/email.js\";\nimport { generateUniqueUsername } from \"../utils/generateUsername.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n createSession,\n createUser,\n findUserByEmail,\n findUserById,\n findUserByUsername,\n} from \"../models/auth.js\";\nimport { upsertUserProfile } from \"../models/user.js\";\nimport {\n acceptSchoolInvite,\n countActiveAdmins,\n createSchoolInvite,\n createSchoolWithAdmin,\n deleteSchoolClassRecord,\n findActiveSchoolAdminMembership,\n findPendingInviteByToken,\n findSchoolClass,\n findSchoolMembership,\n getSchoolById,\n getSchoolMemberDetail,\n getSchoolOverview,\n listActiveSchoolMemberships,\n listMemberClasses,\n listRecentSchoolMembers,\n listSchoolClasses,\n listSchoolInvites,\n listSchoolMembers,\n listUserSchoolMemberships,\n removeSchoolMembershipPreservingContent,\n revokeSchoolInvite,\n updateSchoolClassMembers,\n updateSchoolMembershipRole,\n updateSchoolRecord,\n upsertSchoolMembership,\n} from \"../models/school.js\";\n\nasync function requireSchoolAdmin(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 perform this action\",\n });\n }\n return membership;\n}\n\nasync function requireSchoolMember(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 are not a member of this school\",\n });\n }\n return membership;\n}\n\nexport async function getCurrentSchool(userId: string, schoolId?: string) {\n const memberships = await listUserSchoolMemberships(userId);\n const activeMembership = schoolId\n ? memberships.find((membership) => membership.schoolId === schoolId)\n : memberships[0];\n\n const activeSchool = activeMembership?.school\n ? {\n id: activeMembership.school.id,\n name: activeMembership.school.name,\n description: activeMembership.school.description ?? null,\n subdomain: activeMembership.school.subdomain ?? null,\n logoId: activeMembership.school.logoId ?? null,\n // The path is the GCS object key — the frontend resolves it to a\n // signed URL through trpc.file.getSignedUrl when needed.\n logoPath: activeMembership.school.logo?.path ?? null,\n logoType: activeMembership.school.logo?.type ?? null,\n letterheadFileId: activeMembership.school.letterheadFileId ?? null,\n letterheadPath: activeMembership.school.letterhead?.path ?? null,\n letterheadType: activeMembership.school.letterhead?.type ?? null,\n }\n : null;\n\n return {\n activeSchool,\n activeRole: activeMembership?.role ?? null,\n memberships,\n };\n}\n\nexport async function createSchoolRecord(\n userId: string,\n input: {\n name: string;\n description?: string;\n subdomain?: string;\n logoId?: string;\n }\n) {\n const school = await createSchoolWithAdmin({\n userId,\n name: input.name,\n subdomain: input.subdomain,\n logoId: input.logoId,\n });\n\n if (input.description) {\n await updateSchoolRecord(school.id, { description: input.description });\n }\n\n return { school };\n}\n\nexport async function updateSchoolDetails(\n userId: string,\n input: {\n schoolId: string;\n name?: string;\n description?: string | null;\n subdomain?: string | null;\n logoId?: string | null;\n letterheadFileId?: string | null;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const brandingFileIds = [input.logoId, input.letterheadFileId].filter(\n (id): id is string => typeof id === \"string\"\n );\n if (brandingFileIds.length) {\n const accessible = await prisma.file.findMany({\n where: {\n id: { in: brandingFileIds },\n OR: [\n { userId },\n { folder: { schoolStorageId: input.schoolId } },\n ],\n },\n select: { id: true },\n });\n const accessibleIds = new Set(accessible.map((f) => f.id));\n if (brandingFileIds.some((id) => !accessibleIds.has(id))) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"File does not belong to this school\",\n });\n }\n }\n const updated = await updateSchoolRecord(input.schoolId, {\n name: input.name,\n description: input.description,\n subdomain: input.subdomain,\n logoId: input.logoId,\n letterheadFileId: input.letterheadFileId,\n });\n return { school: updated };\n}\n\nexport async function getAdminOverview(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n const [school, recentMembers] = await Promise.all([\n getSchoolOverview(schoolId),\n listRecentSchoolMembers(schoolId),\n ]);\n if (!school) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"School not found\" });\n }\n\n const roleCounts = school.memberships.reduce(\n (counts, membership) => {\n counts[membership.role] += 1;\n return counts;\n },\n {\n ADMIN: 0,\n TEACHER: 0,\n STUDENT: 0,\n ACCOUNTANT: 0,\n PARENT: 0,\n } satisfies Record<SchoolMembershipRole, number>\n );\n\n return {\n school: {\n id: school.id,\n name: school.name,\n subdomain: school.subdomain,\n counts: {\n classes: school._count.classes,\n members: school._count.memberships,\n pendingInvites: school._count.invites,\n ...roleCounts,\n },\n recentClasses: school.classes,\n recentInvites: school.invites,\n recentMembers,\n },\n };\n}\n\nexport async function listClasses(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { classes: await listSchoolClasses(schoolId) };\n}\n\nexport async function createSchoolClass(\n userId: string,\n input: {\n schoolId: string;\n name: string;\n section: string;\n subject: string;\n color?: string;\n symbol?: string | null;\n departmentId?: string;\n teachers?: string[];\n students?: string[];\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\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\n const createdClass = await prisma.class.create({\n data: {\n name: input.name,\n section: input.section,\n subject: input.subject,\n color: input.color,\n symbol: input.symbol,\n schoolId: input.schoolId,\n departmentId: input.departmentId,\n teachers: input.teachers?.length\n ? { connect: input.teachers.map((id) => ({ id })) }\n : undefined,\n students: input.students?.length\n ? { connect: input.students.map((id) => ({ id })) }\n : undefined,\n },\n include: { teachers: true, students: true },\n });\n\n return { class: createdClass };\n}\n\nexport async function listMembers(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { members: await listSchoolMembers(schoolId) };\n}\n\nexport async function addMember(\n userId: string,\n input: { schoolId: string; memberUserId: string; role: SchoolMembershipRole }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const membership = await upsertSchoolMembership({\n schoolId: input.schoolId,\n userId: input.memberUserId,\n role: input.role,\n });\n return { membership };\n}\n\nexport async function updateMemberRole(\n userId: string,\n input: { schoolId: string; memberUserId: string; role: SchoolMembershipRole }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const current = await findSchoolMembership(input.schoolId, input.memberUserId);\n if (!current) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Member not found\" });\n }\n\n if (current.role === \"ADMIN\" && input.role !== \"ADMIN\") {\n const adminCount = await countActiveAdmins(input.schoolId);\n if (adminCount <= 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"A school must have at least one active admin\",\n });\n }\n }\n\n const membership = await updateSchoolMembershipRole(\n input.schoolId,\n input.memberUserId,\n input.role\n );\n return { membership };\n}\n\nexport async function getMemberDetail(\n userId: string,\n input: { schoolId: string; memberUserId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const membership = await getSchoolMemberDetail(\n input.schoolId,\n input.memberUserId\n );\n if (!membership) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Member not found\" });\n }\n\n const [teachingClasses, enrolledClasses] = await listMemberClasses(\n input.schoolId,\n input.memberUserId\n );\n\n const toClassSummary = (cls: (typeof teachingClasses)[number]) => ({\n id: cls.id,\n name: cls.name,\n section: cls.section,\n subject: cls.subject,\n color: cls.color,\n teacherCount: cls._count.teachers,\n studentCount: cls._count.students,\n });\n\n return {\n membership,\n teachingClasses: teachingClasses.map(toClassSummary),\n enrolledClasses: enrolledClasses.map(toClassSummary),\n };\n}\n\nexport async function bulkUpdateMemberRoles(\n userId: string,\n input: {\n schoolId: string;\n memberUserIds: string[];\n role: SchoolMembershipRole;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const memberships = await listActiveSchoolMemberships(\n input.schoolId,\n input.memberUserIds\n );\n if (memberships.length === 0) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"No members found\" });\n }\n\n if (input.role !== \"ADMIN\") {\n const demotedAdmins = memberships.filter((m) => m.role === \"ADMIN\").length;\n if (demotedAdmins > 0) {\n const adminCount = await countActiveAdmins(input.schoolId);\n if (adminCount - demotedAdmins < 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"A school must have at least one active admin\",\n });\n }\n }\n }\n\n await prisma.schoolMembership.updateMany({\n where: {\n schoolId: input.schoolId,\n userId: { in: memberships.map((m) => m.userId) },\n status: \"ACTIVE\",\n },\n data: { role: input.role },\n });\n return { updatedCount: memberships.length };\n}\n\nexport async function bulkRemoveMembers(\n userId: string,\n input: { schoolId: string; memberUserIds: string[] }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const targetIds = input.memberUserIds.filter((id) => id !== userId);\n const memberships = await listActiveSchoolMemberships(\n input.schoolId,\n targetIds\n );\n if (memberships.length === 0) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"No members found\" });\n }\n\n const removedAdmins = memberships.filter((m) => m.role === \"ADMIN\").length;\n if (removedAdmins > 0) {\n const adminCount = await countActiveAdmins(input.schoolId);\n if (adminCount - removedAdmins < 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"A school must have at least one active admin\",\n });\n }\n }\n\n for (const membership of memberships) {\n await removeSchoolMembershipPreservingContent(\n input.schoolId,\n membership.userId\n );\n }\n return { removedCount: memberships.length };\n}\n\nexport async function deleteSchoolClass(\n userId: string,\n input: { schoolId: string; classId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const cls = await findSchoolClass(input.schoolId, input.classId);\n if (!cls) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Class not found\" });\n }\n await deleteSchoolClassRecord(input.schoolId, input.classId);\n return { deletedClass: { id: input.classId } };\n}\n\nexport async function updateClassMembers(\n userId: string,\n input: {\n schoolId: string;\n classId: string;\n addTeacherIds?: string[];\n removeTeacherIds?: string[];\n addStudentIds?: string[];\n removeStudentIds?: string[];\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const cls = await findSchoolClass(input.schoolId, input.classId);\n if (!cls) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Class not found\" });\n }\n\n const addTeacherIds = input.addTeacherIds ?? [];\n const addStudentIds = input.addStudentIds ?? [];\n const addedIds = [...addTeacherIds, ...addStudentIds];\n if (addedIds.length > 0) {\n const memberships = await listActiveSchoolMemberships(\n input.schoolId,\n addedIds\n );\n const activeIds = new Set(memberships.map((m) => m.userId));\n if (addedIds.some((id) => !activeIds.has(id))) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"All added users must be active members of this school\",\n });\n }\n }\n\n const updated = await updateSchoolClassMembers(input.classId, {\n addTeacherIds,\n removeTeacherIds: input.removeTeacherIds ?? [],\n addStudentIds,\n removeStudentIds: input.removeStudentIds ?? [],\n });\n return { class: updated };\n}\n\nexport async function removeMember(\n userId: string,\n input: { schoolId: string; memberUserId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const current = await findSchoolMembership(input.schoolId, input.memberUserId);\n if (!current) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Member not found\" });\n }\n\n if (current.role === \"ADMIN\" && current.status === \"ACTIVE\") {\n const adminCount = await countActiveAdmins(input.schoolId);\n if (adminCount <= 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"A school must have at least one active admin\",\n });\n }\n }\n\n await removeSchoolMembershipPreservingContent(input.schoolId, input.memberUserId);\n return { success: true };\n}\n\nexport async function listInvites(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { invites: await listSchoolInvites(schoolId) };\n}\n\n/**\n * Issue a direct-upload URL for a school-level asset (e.g. logo). The file\n * is created unattached and is owned by the requester until they associate\n * it via school.create or school.update.\n */\nexport async function getSchoolAssetUploadUrl(\n userId: string,\n input: { fileName: string; fileType: string; fileSize: number }\n) {\n const { createDirectUploadFiles } = await import(\"../lib/fileUpload.js\");\n const [uploadFile] = await createDirectUploadFiles(\n [\n {\n name: input.fileName,\n type: input.fileType,\n size: input.fileSize,\n },\n ],\n userId\n );\n return uploadFile;\n}\n\nexport async function confirmSchoolAssetUpload(\n userId: string,\n fileId: string,\n uploadSuccess: boolean\n) {\n const { confirmDirectUpload } = await import(\"../lib/fileUpload.js\");\n await confirmDirectUpload(fileId, uploadSuccess);\n return { success: true };\n}\n\n/**\n * Lightweight ID-only listing used to mask external user names in the UI.\n * Any active institution member can fetch this.\n */\nexport async function listMemberIds(userId: string, schoolId: string) {\n await requireSchoolMember(schoolId, userId);\n const rows = await prisma.schoolMembership.findMany({\n where: { schoolId, status: \"ACTIVE\" },\n select: { userId: true },\n });\n return rows.map((r) => r.userId);\n}\n\n/** Search active institution members by username, displayName, or email. */\nexport async function searchMembers(\n userId: string,\n schoolId: string,\n query: string,\n limit = 10,\n role?: SchoolMembershipRole\n) {\n await requireSchoolMember(schoolId, userId);\n const trimmed = query.trim();\n if (!trimmed) return [];\n return prisma.user.findMany({\n where: {\n id: { not: userId },\n schoolMemberships: {\n some: {\n schoolId,\n status: \"ACTIVE\",\n ...(role ? { role } : {}),\n },\n },\n OR: [\n { username: { contains: trimmed, mode: \"insensitive\" } },\n { email: { contains: trimmed, mode: \"insensitive\" } },\n {\n profile: {\n displayName: { contains: trimmed, mode: \"insensitive\" },\n },\n },\n ],\n },\n take: limit,\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n schoolMemberships: {\n where: { schoolId, status: \"ACTIVE\" },\n select: { role: true },\n },\n },\n orderBy: { username: \"asc\" },\n });\n}\n\n/**\n * Combined student timeline: calendar events + assignments + attendance.\n * Visible to school admins (any student) and to teachers who share at least\n * one class with the student.\n */\nexport async function getStudentTimeline(\n userId: string,\n input: {\n schoolId: string;\n studentId: string;\n from?: Date;\n to?: Date;\n }\n) {\n const isAdmin = await findActiveSchoolAdminMembership(\n input.schoolId,\n userId\n );\n\n // Permission: admin OR shares a class.\n if (!isAdmin) {\n const sharedClass = await prisma.class.findFirst({\n where: {\n schoolId: input.schoolId,\n teachers: { some: { id: userId } },\n students: { some: { id: input.studentId } },\n },\n select: { id: true },\n });\n if (!sharedClass) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You don't share a class with this student\",\n });\n }\n }\n\n // Make sure student is in the institution.\n const studentMembership = await prisma.schoolMembership.findFirst({\n where: { schoolId: input.schoolId, userId: input.studentId, status: \"ACTIVE\" },\n select: { role: true, user: { select: { id: true, username: true, profile: { select: { displayName: true, profilePicture: true } } } } },\n });\n if (!studentMembership) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Student is not in this institution\",\n });\n }\n\n // Default to the last 12 months when no range is given, to bound reads.\n const defaultFrom = new Date();\n defaultFrom.setFullYear(defaultFrom.getFullYear() - 1);\n const range = {\n gte: input.from ?? defaultFrom,\n ...(input.to ? { lte: input.to } : {}),\n };\n const [events, assignments, attendance] = await Promise.all([\n prisma.event.findMany({\n where: {\n userId: input.studentId,\n startTime: range,\n },\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n class: { select: { id: true, name: true, color: true } },\n },\n orderBy: { startTime: \"asc\" },\n }),\n prisma.assignment.findMany({\n where: {\n class: {\n students: { some: { id: input.studentId } },\n },\n template: false,\n dueDate: range,\n },\n select: {\n id: true,\n title: true,\n dueDate: true,\n type: true,\n graded: true,\n maxGrade: true,\n weight: true,\n class: {\n select: {\n id: true,\n name: true,\n section: true,\n subject: true,\n color: true,\n },\n },\n submissions: {\n where: { studentId: input.studentId },\n select: {\n id: true,\n submitted: true,\n submittedAt: true,\n returned: true,\n gradeReceived: true,\n },\n },\n },\n orderBy: { dueDate: \"asc\" },\n }),\n prisma.attendanceRecord.findMany({\n where: {\n studentId: input.studentId,\n attendance: {\n class: { schoolId: input.schoolId },\n date: range,\n },\n },\n select: {\n id: true,\n status: true,\n note: true,\n excusedByExcusalId: true,\n attendance: {\n select: {\n id: true,\n date: true,\n class: { select: { id: true, name: true, color: true } },\n },\n },\n excusedByExcusal: { select: { id: true, reason: true } },\n },\n orderBy: { attendance: { date: \"asc\" } },\n }),\n ]);\n\n const attendanceShaped = attendance.map((record) => ({\n id: record.attendance.id,\n recordId: record.id,\n date: record.attendance.date,\n class: record.attendance.class,\n status: record.status,\n note: record.note,\n lockedFromExcusal: Boolean(record.excusedByExcusalId),\n reason: record.excusedByExcusal?.reason ?? null,\n }));\n\n return {\n student: studentMembership.user,\n events,\n assignments,\n attendance: attendanceShaped,\n };\n}\n\n/**\n * Role-aware overview used by `/view/[userId]`.\n *\n * - For STUDENT members it returns the same timeline as `getStudentTimeline`\n * (events, assignments, attendance) so teachers/admins can audit progress.\n * - For TEACHER/ADMIN members it returns their teaching agenda: every event in\n * a class they teach plus their personal events, alongside the classes they\n * run with enrolment counts.\n *\n * Permissions:\n * - School admins can view anyone in the institution.\n * - A teacher can view a STUDENT they share a class with.\n * - A teacher/admin can always view their own overview.\n */\nexport async function getMemberTimeline(\n userId: string,\n input: {\n schoolId: string;\n memberId: string;\n from?: Date;\n to?: Date;\n }\n) {\n const callerIsAdmin = Boolean(\n await findActiveSchoolAdminMembership(input.schoolId, userId)\n );\n\n const membership = await prisma.schoolMembership.findFirst({\n where: {\n schoolId: input.schoolId,\n userId: input.memberId,\n status: \"ACTIVE\",\n },\n select: {\n role: true,\n user: {\n select: {\n id: true,\n username: true,\n profile: { select: { displayName: true, profilePicture: true } },\n },\n },\n },\n });\n if (!membership) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"This person is not in this institution\",\n });\n }\n\n // Default to the last 12 months when no range is given, to bound reads.\n const defaultFrom = new Date();\n defaultFrom.setFullYear(defaultFrom.getFullYear() - 1);\n const range = {\n gte: input.from ?? defaultFrom,\n ...(input.to ? { lte: input.to } : {}),\n };\n\n if (membership.role === \"STUDENT\") {\n if (!callerIsAdmin) {\n const sharedClass = await prisma.class.findFirst({\n where: {\n schoolId: input.schoolId,\n teachers: { some: { id: userId } },\n students: { some: { id: input.memberId } },\n },\n select: { id: true },\n });\n if (!sharedClass) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You don't share a class with this student\",\n });\n }\n }\n\n const [events, assignments, attendance] = await Promise.all([\n prisma.event.findMany({\n where: {\n userId: input.memberId,\n startTime: range,\n },\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n class: { select: { id: true, name: true, color: true } },\n },\n orderBy: { startTime: \"asc\" },\n }),\n prisma.assignment.findMany({\n where: {\n class: { students: { some: { id: input.memberId } } },\n template: false,\n dueDate: range,\n },\n select: {\n id: true,\n title: true,\n dueDate: true,\n type: true,\n graded: true,\n maxGrade: true,\n weight: true,\n class: {\n select: {\n id: true,\n name: true,\n section: true,\n subject: true,\n color: true,\n },\n },\n submissions: {\n where: { studentId: input.memberId },\n select: {\n id: true,\n submitted: true,\n submittedAt: true,\n returned: true,\n gradeReceived: true,\n },\n },\n },\n orderBy: { dueDate: \"asc\" },\n }),\n prisma.attendanceRecord.findMany({\n where: {\n studentId: input.memberId,\n attendance: {\n class: { schoolId: input.schoolId },\n date: range,\n },\n },\n select: {\n id: true,\n status: true,\n note: true,\n excusedByExcusalId: true,\n attendance: {\n select: {\n id: true,\n date: true,\n class: { select: { id: true, name: true, color: true } },\n },\n },\n excusedByExcusal: { select: { id: true, reason: true } },\n },\n orderBy: { attendance: { date: \"asc\" } },\n }),\n ]);\n\n const attendanceShaped = attendance.map((record) => ({\n id: record.attendance.id,\n recordId: record.id,\n date: record.attendance.date,\n class: record.attendance.class,\n status: record.status,\n note: record.note,\n lockedFromExcusal: Boolean(record.excusedByExcusalId),\n reason: record.excusedByExcusal?.reason ?? null,\n }));\n\n return {\n role: \"STUDENT\" as const,\n member: membership.user,\n events,\n assignments,\n attendance: attendanceShaped,\n };\n }\n\n // TEACHER or ADMIN: only admins (or the member themselves) may view.\n if (!callerIsAdmin && userId !== input.memberId) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can view this member\",\n });\n }\n\n const [events, classes] = await Promise.all([\n prisma.event.findMany({\n where: {\n OR: [\n { userId: input.memberId },\n { class: { teachers: { some: { id: input.memberId } } } },\n ],\n startTime: range,\n },\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n class: { select: { id: true, name: true, color: true } },\n },\n orderBy: { startTime: \"asc\" },\n }),\n prisma.class.findMany({\n where: {\n schoolId: input.schoolId,\n teachers: { some: { id: input.memberId } },\n },\n select: {\n id: true,\n name: true,\n section: true,\n subject: true,\n color: true,\n _count: { select: { students: true } },\n },\n orderBy: { name: \"asc\" },\n }),\n ]);\n\n return {\n role: membership.role as \"TEACHER\" | \"ADMIN\",\n member: membership.user,\n events,\n classes: classes.map((c) => ({\n id: c.id,\n name: c.name,\n section: c.section,\n subject: c.subject,\n color: c.color,\n studentCount: c._count.students,\n })),\n };\n}\n\nexport async function createInvite(\n userId: string,\n input: {\n schoolId: string;\n email: string;\n role: SchoolMembershipRole;\n /** Optional display name set by the inviting admin. If omitted the user\n * picks their own when they complete the password reset flow. */\n displayName?: string;\n /** Optional username; if omitted we generate a friendly random one. */\n username?: string;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n // The institution invite flow is \"new account only\": if the email is\n // already in use we reject. This keeps the join experience simple — every\n // new institution member always lands on a password reset link.\n const existingUser = await findUserByEmail(input.email);\n if (existingUser) {\n throw new TRPCError({\n code: \"CONFLICT\",\n message:\n \"An account with this email already exists. Ask them to log in and you can add them via search.\",\n });\n }\n\n let username: string;\n if (input.username) {\n const taken = await findUserByUsername(input.username);\n if (taken) {\n throw new TRPCError({\n code: \"CONFLICT\",\n message: \"Username already taken\",\n });\n }\n username = input.username;\n } else {\n username = await generateUniqueUsername(async (candidate) => {\n const existing = await findUserByUsername(candidate);\n return Boolean(existing);\n });\n }\n\n const placeholderPassword = await hash(uuidv4(), 10);\n const user = await createUser({\n username,\n email: input.email,\n password: placeholderPassword,\n verified: true,\n });\n const createdUser = { id: user.id, username: user.username };\n\n if (input.displayName) {\n await upsertUserProfile(user.id, { displayName: input.displayName });\n }\n\n const resetSession = await createSession({\n id: uuidv4(),\n type: SessionType.PASSWORD_RESET,\n userId: user.id,\n expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 14),\n });\n const passwordResetToken = resetSession.id;\n\n const token = uuidv4();\n const invite = await createSchoolInvite({\n schoolId: input.schoolId,\n invitedById: userId,\n email: input.email,\n role: input.role,\n token,\n expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 14),\n });\n\n await acceptSchoolInvite(invite.id, createdUser.id);\n\n const passwordResetUrl = `${env.NEXT_PUBLIC_APP_URL}/reset-password/${passwordResetToken}`;\n const emailLines = [\n `You've been added to ${invite.school.name} on Studious.`,\n \"\",\n `We created an account for you with the username \"${createdUser.username}\".`,\n input.displayName\n ? `Your name is set to \"${input.displayName}\" — you can change it after signing in.`\n : `You can set your name once you sign in for the first time.`,\n \"\",\n `Set your password to get started: ${passwordResetUrl}`,\n ];\n\n try {\n await sendMail({\n from: \"hello@studious.sh\",\n to: input.email,\n subject: `Join ${invite.school.name} on Studious`,\n text: emailLines.join(\"\\n\"),\n });\n } catch (err) {\n logger.error(\"Failed to send school invite email\", {\n schoolId: input.schoolId,\n email: input.email,\n err,\n });\n }\n\n return {\n invite,\n createdUser,\n passwordResetUrl,\n };\n}\n\nexport async function revokeInvite(\n userId: string,\n input: { schoolId: string; inviteId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n return { invite: await revokeSchoolInvite(input.inviteId, input.schoolId) };\n}\n\nexport async function getInvite(token: string) {\n const invite = await findPendingInviteByToken(token);\n if (!invite || invite.status !== \"PENDING\") {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invite not found\" });\n }\n if (invite.expiresAt < new Date()) {\n throw new TRPCError({ code: \"UNAUTHORIZED\", message: \"Invite expired\" });\n }\n return {\n invite: {\n id: invite.id,\n email: invite.email,\n role: invite.role,\n school: invite.school,\n expiresAt: invite.expiresAt,\n },\n };\n}\n\nexport async function acceptInvite(userId: string, token: string) {\n const invite = await findPendingInviteByToken(token);\n if (!invite || invite.status !== \"PENDING\") {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invite not found\" });\n }\n if (invite.expiresAt < new Date()) {\n throw new TRPCError({ code: \"UNAUTHORIZED\", message: \"Invite expired\" });\n }\n\n const user = await findUserById(userId);\n if (!user) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"User not found\" });\n }\n if (user.email.toLowerCase() !== invite.email.toLowerCase()) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"This invite was sent to a different account\",\n });\n }\n\n const membership = await acceptSchoolInvite(invite.id, userId);\n return { membership };\n}\n"],"names":[],"mappings":"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","debug_id":"7675f5a8-bfcb-53db-b66d-cdd4c8755f46"}
1
+ {"version":3,"file":"school.js","sources":["services/school.ts"],"sourceRoot":"/","sourcesContent":["/**\n * School service - school admin workflow, memberships, and invites.\n */\nimport { SchoolMembershipRole, SessionType } from \"@prisma/client\";\nimport { TRPCError } from \"@trpc/server\";\nimport { hash } from \"bcryptjs\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { env } from \"../lib/config/env.js\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { sendMail } from \"../utils/email.js\";\nimport { generateUniqueUsername } from \"../utils/generateUsername.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n createSession,\n createUser,\n findUserByEmail,\n findUserById,\n findUserByUsername,\n} from \"../models/auth.js\";\nimport { upsertUserProfile } from \"../models/user.js\";\nimport {\n acceptSchoolInvite,\n countActiveAdmins,\n createSchoolInvite,\n createSchoolWithAdmin,\n deleteSchoolClassRecord,\n findActiveSchoolAdminMembership,\n findPendingInviteByToken,\n findSchoolClass,\n findSchoolMembership,\n getSchoolById,\n getSchoolMemberDetail,\n getSchoolOverview,\n listActiveSchoolMemberships,\n listMemberClasses,\n listRecentSchoolMembers,\n listSchoolClasses,\n listSchoolInvites,\n listSchoolMembers,\n listUserSchoolMemberships,\n removeSchoolMembershipPreservingContent,\n revokeSchoolInvite,\n updateSchoolClassMembers,\n updateSchoolMembershipRole,\n updateSchoolRecord,\n upsertSchoolMembership,\n} from \"../models/school.js\";\n\nasync function requireSchoolAdmin(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 perform this action\",\n });\n }\n return membership;\n}\n\nasync function requireSchoolMember(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 are not a member of this school\",\n });\n }\n return membership;\n}\n\nexport async function getCurrentSchool(userId: string, schoolId?: string) {\n const memberships = await listUserSchoolMemberships(userId);\n const activeMembership = schoolId\n ? memberships.find((membership) => membership.schoolId === schoolId)\n : memberships[0];\n\n const activeSchool = activeMembership?.school\n ? {\n id: activeMembership.school.id,\n name: activeMembership.school.name,\n description: activeMembership.school.description ?? null,\n subdomain: activeMembership.school.subdomain ?? null,\n logoId: activeMembership.school.logoId ?? null,\n // The path is the GCS object key — the frontend resolves it to a\n // signed URL through trpc.file.getSignedUrl when needed.\n logoPath: activeMembership.school.logo?.path ?? null,\n logoType: activeMembership.school.logo?.type ?? null,\n letterheadFileId: activeMembership.school.letterheadFileId ?? null,\n letterheadPath: activeMembership.school.letterhead?.path ?? null,\n letterheadType: activeMembership.school.letterhead?.type ?? null,\n }\n : null;\n\n return {\n activeSchool,\n activeRole: activeMembership?.role ?? null,\n memberships,\n };\n}\n\nexport async function createSchoolRecord(\n userId: string,\n input: {\n name: string;\n description?: string;\n subdomain?: string;\n logoId?: string;\n }\n) {\n const school = await createSchoolWithAdmin({\n userId,\n name: input.name,\n subdomain: input.subdomain,\n logoId: input.logoId,\n });\n\n if (input.description) {\n await updateSchoolRecord(school.id, { description: input.description });\n }\n\n return { school };\n}\n\nexport async function updateSchoolDetails(\n userId: string,\n input: {\n schoolId: string;\n name?: string;\n description?: string | null;\n subdomain?: string | null;\n logoId?: string | null;\n letterheadFileId?: string | null;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const brandingFileIds = [input.logoId, input.letterheadFileId].filter(\n (id): id is string => typeof id === \"string\"\n );\n if (brandingFileIds.length) {\n const accessible = await prisma.file.findMany({\n where: {\n id: { in: brandingFileIds },\n OR: [\n { userId },\n { folder: { schoolStorageId: input.schoolId } },\n ],\n },\n select: { id: true },\n });\n const accessibleIds = new Set(accessible.map((f) => f.id));\n if (brandingFileIds.some((id) => !accessibleIds.has(id))) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"File does not belong to this school\",\n });\n }\n }\n const updated = await updateSchoolRecord(input.schoolId, {\n name: input.name,\n description: input.description,\n subdomain: input.subdomain,\n logoId: input.logoId,\n letterheadFileId: input.letterheadFileId,\n });\n return { school: updated };\n}\n\nexport async function getAdminOverview(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n const [school, recentMembers] = await Promise.all([\n getSchoolOverview(schoolId),\n listRecentSchoolMembers(schoolId),\n ]);\n if (!school) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"School not found\" });\n }\n\n const roleCounts = school.memberships.reduce(\n (counts, membership) => {\n counts[membership.role] += 1;\n return counts;\n },\n {\n ADMIN: 0,\n TEACHER: 0,\n STUDENT: 0,\n ACCOUNTANT: 0,\n PARENT: 0,\n } satisfies Record<SchoolMembershipRole, number>\n );\n\n return {\n school: {\n id: school.id,\n name: school.name,\n subdomain: school.subdomain,\n counts: {\n classes: school._count.classes,\n members: school._count.memberships,\n pendingInvites: school._count.invites,\n ...roleCounts,\n },\n recentClasses: school.classes,\n recentInvites: school.invites,\n recentMembers,\n },\n };\n}\n\nexport async function listClasses(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { classes: await listSchoolClasses(schoolId) };\n}\n\nexport async function createSchoolClass(\n userId: string,\n input: {\n schoolId: string;\n name: string;\n section: string;\n subject: string;\n color?: string;\n symbol?: string | null;\n departmentId?: string;\n teachers?: string[];\n students?: string[];\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\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\n const createdClass = await prisma.class.create({\n data: {\n name: input.name,\n section: input.section,\n subject: input.subject,\n color: input.color,\n symbol: input.symbol,\n schoolId: input.schoolId,\n departmentId: input.departmentId,\n teachers: input.teachers?.length\n ? { connect: input.teachers.map((id) => ({ id })) }\n : undefined,\n students: input.students?.length\n ? { connect: input.students.map((id) => ({ id })) }\n : undefined,\n },\n include: { teachers: true, students: true },\n });\n\n return { class: createdClass };\n}\n\nexport async function listMembers(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { members: await listSchoolMembers(schoolId) };\n}\n\nexport async function addMember(\n userId: string,\n input: { schoolId: string; memberUserId: string; role: SchoolMembershipRole }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const membership = await upsertSchoolMembership({\n schoolId: input.schoolId,\n userId: input.memberUserId,\n role: input.role,\n });\n return { membership };\n}\n\nexport async function updateMemberRole(\n userId: string,\n input: { schoolId: string; memberUserId: string; role: SchoolMembershipRole }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const current = await findSchoolMembership(input.schoolId, input.memberUserId);\n if (!current) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Member not found\" });\n }\n\n if (current.role === \"ADMIN\" && input.role !== \"ADMIN\") {\n const adminCount = await countActiveAdmins(input.schoolId);\n if (adminCount <= 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"A school must have at least one active admin\",\n });\n }\n }\n\n const membership = await updateSchoolMembershipRole(\n input.schoolId,\n input.memberUserId,\n input.role\n );\n return { membership };\n}\n\nexport async function getMemberDetail(\n userId: string,\n input: { schoolId: string; memberUserId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const membership = await getSchoolMemberDetail(\n input.schoolId,\n input.memberUserId\n );\n if (!membership) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Member not found\" });\n }\n\n const [teachingClasses, enrolledClasses] = await listMemberClasses(\n input.schoolId,\n input.memberUserId\n );\n\n const toClassSummary = (cls: (typeof teachingClasses)[number]) => ({\n id: cls.id,\n name: cls.name,\n section: cls.section,\n subject: cls.subject,\n color: cls.color,\n teacherCount: cls._count.teachers,\n studentCount: cls._count.students,\n });\n\n return {\n membership,\n teachingClasses: teachingClasses.map(toClassSummary),\n enrolledClasses: enrolledClasses.map(toClassSummary),\n };\n}\n\nexport async function bulkUpdateMemberRoles(\n userId: string,\n input: {\n schoolId: string;\n memberUserIds: string[];\n role: SchoolMembershipRole;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const memberships = await listActiveSchoolMemberships(\n input.schoolId,\n input.memberUserIds\n );\n if (memberships.length === 0) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"No members found\" });\n }\n\n if (input.role !== \"ADMIN\") {\n const demotedAdmins = memberships.filter((m) => m.role === \"ADMIN\").length;\n if (demotedAdmins > 0) {\n const adminCount = await countActiveAdmins(input.schoolId);\n if (adminCount - demotedAdmins < 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"A school must have at least one active admin\",\n });\n }\n }\n }\n\n await prisma.schoolMembership.updateMany({\n where: {\n schoolId: input.schoolId,\n userId: { in: memberships.map((m) => m.userId) },\n status: \"ACTIVE\",\n },\n data: { role: input.role },\n });\n return { updatedCount: memberships.length };\n}\n\nexport async function bulkRemoveMembers(\n userId: string,\n input: { schoolId: string; memberUserIds: string[] }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const targetIds = input.memberUserIds.filter((id) => id !== userId);\n const memberships = await listActiveSchoolMemberships(\n input.schoolId,\n targetIds\n );\n if (memberships.length === 0) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"No members found\" });\n }\n\n const removedAdmins = memberships.filter((m) => m.role === \"ADMIN\").length;\n if (removedAdmins > 0) {\n const adminCount = await countActiveAdmins(input.schoolId);\n if (adminCount - removedAdmins < 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"A school must have at least one active admin\",\n });\n }\n }\n\n for (const membership of memberships) {\n await removeSchoolMembershipPreservingContent(\n input.schoolId,\n membership.userId\n );\n }\n return { removedCount: memberships.length };\n}\n\nexport async function deleteSchoolClass(\n userId: string,\n input: { schoolId: string; classId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const cls = await findSchoolClass(input.schoolId, input.classId);\n if (!cls) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Class not found\" });\n }\n await deleteSchoolClassRecord(input.schoolId, input.classId);\n return { deletedClass: { id: input.classId } };\n}\n\nexport async function updateClassMembers(\n userId: string,\n input: {\n schoolId: string;\n classId: string;\n addTeacherIds?: string[];\n removeTeacherIds?: string[];\n addStudentIds?: string[];\n removeStudentIds?: string[];\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const cls = await findSchoolClass(input.schoolId, input.classId);\n if (!cls) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Class not found\" });\n }\n\n const addTeacherIds = input.addTeacherIds ?? [];\n const addStudentIds = input.addStudentIds ?? [];\n const addedIds = [...addTeacherIds, ...addStudentIds];\n if (addedIds.length > 0) {\n const memberships = await listActiveSchoolMemberships(\n input.schoolId,\n addedIds\n );\n const activeIds = new Set(memberships.map((m) => m.userId));\n if (addedIds.some((id) => !activeIds.has(id))) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"All added users must be active members of this school\",\n });\n }\n }\n\n const updated = await updateSchoolClassMembers(input.classId, {\n addTeacherIds,\n removeTeacherIds: input.removeTeacherIds ?? [],\n addStudentIds,\n removeStudentIds: input.removeStudentIds ?? [],\n });\n return { class: updated };\n}\n\nexport async function removeMember(\n userId: string,\n input: { schoolId: string; memberUserId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const current = await findSchoolMembership(input.schoolId, input.memberUserId);\n if (!current) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Member not found\" });\n }\n\n if (current.role === \"ADMIN\" && current.status === \"ACTIVE\") {\n const adminCount = await countActiveAdmins(input.schoolId);\n if (adminCount <= 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"A school must have at least one active admin\",\n });\n }\n }\n\n await removeSchoolMembershipPreservingContent(input.schoolId, input.memberUserId);\n return { success: true };\n}\n\nexport async function listInvites(userId: string, schoolId: string) {\n await requireSchoolAdmin(schoolId, userId);\n return { invites: await listSchoolInvites(schoolId) };\n}\n\n/**\n * Issue a direct-upload URL for a school-level asset (e.g. logo). The file\n * is created unattached and is owned by the requester until they associate\n * it via school.create or school.update.\n */\nexport async function getSchoolAssetUploadUrl(\n userId: string,\n input: { fileName: string; fileType: string; fileSize: number }\n) {\n const { createDirectUploadFiles } = await import(\"../lib/fileUpload.js\");\n const [uploadFile] = await createDirectUploadFiles(\n [\n {\n name: input.fileName,\n type: input.fileType,\n size: input.fileSize,\n },\n ],\n userId\n );\n return uploadFile;\n}\n\nexport async function confirmSchoolAssetUpload(\n userId: string,\n fileId: string,\n uploadSuccess: boolean\n) {\n const { confirmDirectUpload } = await import(\"../lib/fileUpload.js\");\n await confirmDirectUpload(fileId, uploadSuccess);\n return { success: true };\n}\n\n/**\n * Lightweight ID-only listing used to mask external user names in the UI.\n * Any active institution member can fetch this.\n */\nexport async function listMemberIds(userId: string, schoolId: string) {\n await requireSchoolMember(schoolId, userId);\n const rows = await prisma.schoolMembership.findMany({\n where: { schoolId, status: \"ACTIVE\" },\n select: { userId: true },\n });\n return rows.map((r) => r.userId);\n}\n\n/** Search active institution members by username, displayName, or email. */\nexport async function searchMembers(\n userId: string,\n schoolId: string,\n query: string,\n limit = 10,\n role?: SchoolMembershipRole\n) {\n await requireSchoolMember(schoolId, userId);\n const trimmed = query.trim();\n if (!trimmed) return [];\n return prisma.user.findMany({\n where: {\n id: { not: userId },\n schoolMemberships: {\n some: {\n schoolId,\n status: \"ACTIVE\",\n ...(role ? { role } : {}),\n },\n },\n OR: [\n { username: { contains: trimmed, mode: \"insensitive\" } },\n { email: { contains: trimmed, mode: \"insensitive\" } },\n {\n profile: {\n displayName: { contains: trimmed, mode: \"insensitive\" },\n },\n },\n ],\n },\n take: limit,\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n schoolMemberships: {\n where: { schoolId, status: \"ACTIVE\" },\n select: { role: true },\n },\n },\n orderBy: { username: \"asc\" },\n });\n}\n\n/**\n * Combined student timeline: calendar events + assignments + attendance.\n * Visible to school admins (any student) and to teachers who share at least\n * one class with the student.\n */\nexport async function getStudentTimeline(\n userId: string,\n input: {\n schoolId: string;\n studentId: string;\n from?: Date;\n to?: Date;\n }\n) {\n const isAdmin = await findActiveSchoolAdminMembership(\n input.schoolId,\n userId\n );\n\n // Permission: admin OR shares a class.\n if (!isAdmin) {\n const sharedClass = await prisma.class.findFirst({\n where: {\n schoolId: input.schoolId,\n teachers: { some: { id: userId } },\n students: { some: { id: input.studentId } },\n },\n select: { id: true },\n });\n if (!sharedClass) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You don't share a class with this student\",\n });\n }\n }\n\n // Make sure student is in the institution.\n const studentMembership = await prisma.schoolMembership.findFirst({\n where: { schoolId: input.schoolId, userId: input.studentId, status: \"ACTIVE\" },\n select: { role: true, user: { select: { id: true, username: true, profile: { select: { displayName: true, profilePicture: true } } } } },\n });\n if (!studentMembership) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Student is not in this institution\",\n });\n }\n\n // Default to the last 12 months when no range is given, to bound reads.\n const defaultFrom = new Date();\n defaultFrom.setFullYear(defaultFrom.getFullYear() - 1);\n const range = {\n gte: input.from ?? defaultFrom,\n ...(input.to ? { lte: input.to } : {}),\n };\n const [events, assignments, attendance] = await Promise.all([\n prisma.event.findMany({\n where: {\n userId: input.studentId,\n startTime: range,\n OR: [{ classId: null }, { class: { schoolId: input.schoolId } }],\n },\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n class: { select: { id: true, name: true, color: true } },\n },\n orderBy: { startTime: \"asc\" },\n }),\n prisma.assignment.findMany({\n where: {\n class: {\n schoolId: input.schoolId,\n students: { some: { id: input.studentId } },\n },\n template: false,\n dueDate: range,\n },\n select: {\n id: true,\n title: true,\n dueDate: true,\n type: true,\n graded: true,\n maxGrade: true,\n weight: true,\n class: {\n select: {\n id: true,\n name: true,\n section: true,\n subject: true,\n color: true,\n },\n },\n submissions: {\n where: { studentId: input.studentId },\n select: {\n id: true,\n submitted: true,\n submittedAt: true,\n returned: true,\n gradeReceived: true,\n },\n },\n },\n orderBy: { dueDate: \"asc\" },\n }),\n prisma.attendanceRecord.findMany({\n where: {\n studentId: input.studentId,\n attendance: {\n class: { schoolId: input.schoolId },\n date: range,\n },\n },\n select: {\n id: true,\n status: true,\n note: true,\n excusedByExcusalId: true,\n attendance: {\n select: {\n id: true,\n date: true,\n class: { select: { id: true, name: true, color: true } },\n },\n },\n excusedByExcusal: { select: { id: true, reason: true } },\n },\n orderBy: { attendance: { date: \"asc\" } },\n }),\n ]);\n\n const attendanceShaped = attendance.map((record) => ({\n id: record.attendance.id,\n recordId: record.id,\n date: record.attendance.date,\n class: record.attendance.class,\n status: record.status,\n note: record.note,\n lockedFromExcusal: Boolean(record.excusedByExcusalId),\n reason: record.excusedByExcusal?.reason ?? null,\n }));\n\n return {\n student: studentMembership.user,\n events,\n assignments,\n attendance: attendanceShaped,\n };\n}\n\n/**\n * Role-aware overview used by `/view/[userId]`.\n *\n * - For STUDENT members it returns the same timeline as `getStudentTimeline`\n * (events, assignments, attendance) so teachers/admins can audit progress.\n * - For TEACHER/ADMIN members it returns their teaching agenda: every event in\n * a class they teach plus their personal events, alongside the classes they\n * run with enrolment counts.\n *\n * Permissions:\n * - School admins can view anyone in the institution.\n * - A teacher can view a STUDENT they share a class with.\n * - A teacher/admin can always view their own overview.\n */\nexport async function getMemberTimeline(\n userId: string,\n input: {\n schoolId: string;\n memberId: string;\n from?: Date;\n to?: Date;\n }\n) {\n const callerIsAdmin = Boolean(\n await findActiveSchoolAdminMembership(input.schoolId, userId)\n );\n\n const membership = await prisma.schoolMembership.findFirst({\n where: {\n schoolId: input.schoolId,\n userId: input.memberId,\n status: \"ACTIVE\",\n },\n select: {\n role: true,\n user: {\n select: {\n id: true,\n username: true,\n profile: { select: { displayName: true, profilePicture: true } },\n },\n },\n },\n });\n if (!membership) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"This person is not in this institution\",\n });\n }\n\n // Default to the last 12 months when no range is given, to bound reads.\n const defaultFrom = new Date();\n defaultFrom.setFullYear(defaultFrom.getFullYear() - 1);\n const range = {\n gte: input.from ?? defaultFrom,\n ...(input.to ? { lte: input.to } : {}),\n };\n\n if (membership.role === \"STUDENT\") {\n if (!callerIsAdmin) {\n const sharedClass = await prisma.class.findFirst({\n where: {\n schoolId: input.schoolId,\n teachers: { some: { id: userId } },\n students: { some: { id: input.memberId } },\n },\n select: { id: true },\n });\n if (!sharedClass) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You don't share a class with this student\",\n });\n }\n }\n\n const [events, assignments, attendance] = await Promise.all([\n prisma.event.findMany({\n where: {\n userId: input.memberId,\n startTime: range,\n OR: [{ classId: null }, { class: { schoolId: input.schoolId } }],\n },\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n class: { select: { id: true, name: true, color: true } },\n },\n orderBy: { startTime: \"asc\" },\n }),\n prisma.assignment.findMany({\n where: {\n class: {\n schoolId: input.schoolId,\n students: { some: { id: input.memberId } },\n },\n template: false,\n dueDate: range,\n },\n select: {\n id: true,\n title: true,\n dueDate: true,\n type: true,\n graded: true,\n maxGrade: true,\n weight: true,\n class: {\n select: {\n id: true,\n name: true,\n section: true,\n subject: true,\n color: true,\n },\n },\n submissions: {\n where: { studentId: input.memberId },\n select: {\n id: true,\n submitted: true,\n submittedAt: true,\n returned: true,\n gradeReceived: true,\n },\n },\n },\n orderBy: { dueDate: \"asc\" },\n }),\n prisma.attendanceRecord.findMany({\n where: {\n studentId: input.memberId,\n attendance: {\n class: { schoolId: input.schoolId },\n date: range,\n },\n },\n select: {\n id: true,\n status: true,\n note: true,\n excusedByExcusalId: true,\n attendance: {\n select: {\n id: true,\n date: true,\n class: { select: { id: true, name: true, color: true } },\n },\n },\n excusedByExcusal: { select: { id: true, reason: true } },\n },\n orderBy: { attendance: { date: \"asc\" } },\n }),\n ]);\n\n const attendanceShaped = attendance.map((record) => ({\n id: record.attendance.id,\n recordId: record.id,\n date: record.attendance.date,\n class: record.attendance.class,\n status: record.status,\n note: record.note,\n lockedFromExcusal: Boolean(record.excusedByExcusalId),\n reason: record.excusedByExcusal?.reason ?? null,\n }));\n\n return {\n role: \"STUDENT\" as const,\n member: membership.user,\n events,\n assignments,\n attendance: attendanceShaped,\n };\n }\n\n // TEACHER or ADMIN: only admins (or the member themselves) may view.\n if (!callerIsAdmin && userId !== input.memberId) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can view this member\",\n });\n }\n\n const [events, classes] = await Promise.all([\n prisma.event.findMany({\n where: {\n OR: [\n { userId: input.memberId, classId: null },\n { userId: input.memberId, class: { schoolId: input.schoolId } },\n {\n class: {\n schoolId: input.schoolId,\n teachers: { some: { id: input.memberId } },\n },\n },\n ],\n startTime: range,\n },\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n class: { select: { id: true, name: true, color: true } },\n },\n orderBy: { startTime: \"asc\" },\n }),\n prisma.class.findMany({\n where: {\n schoolId: input.schoolId,\n teachers: { some: { id: input.memberId } },\n },\n select: {\n id: true,\n name: true,\n section: true,\n subject: true,\n color: true,\n _count: { select: { students: true } },\n },\n orderBy: { name: \"asc\" },\n }),\n ]);\n\n return {\n role: membership.role as \"TEACHER\" | \"ADMIN\",\n member: membership.user,\n events,\n classes: classes.map((c) => ({\n id: c.id,\n name: c.name,\n section: c.section,\n subject: c.subject,\n color: c.color,\n studentCount: c._count.students,\n })),\n };\n}\n\nexport async function createInvite(\n userId: string,\n input: {\n schoolId: string;\n email: string;\n role: SchoolMembershipRole;\n /** Optional display name set by the inviting admin. If omitted the user\n * picks their own when they complete the password reset flow. */\n displayName?: string;\n /** Optional username; if omitted we generate a friendly random one. */\n username?: string;\n }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n // The institution invite flow is \"new account only\": if the email is\n // already in use we reject. This keeps the join experience simple — every\n // new institution member always lands on a password reset link.\n const existingUser = await findUserByEmail(input.email);\n if (existingUser) {\n throw new TRPCError({\n code: \"CONFLICT\",\n message:\n \"An account with this email already exists. Ask them to log in and you can add them via search.\",\n });\n }\n\n let username: string;\n if (input.username) {\n const taken = await findUserByUsername(input.username);\n if (taken) {\n throw new TRPCError({\n code: \"CONFLICT\",\n message: \"Username already taken\",\n });\n }\n username = input.username;\n } else {\n username = await generateUniqueUsername(async (candidate) => {\n const existing = await findUserByUsername(candidate);\n return Boolean(existing);\n });\n }\n\n const placeholderPassword = await hash(uuidv4(), 10);\n const user = await createUser({\n username,\n email: input.email,\n password: placeholderPassword,\n verified: true,\n });\n const createdUser = { id: user.id, username: user.username };\n\n if (input.displayName) {\n await upsertUserProfile(user.id, { displayName: input.displayName });\n }\n\n const resetSession = await createSession({\n id: uuidv4(),\n type: SessionType.PASSWORD_RESET,\n userId: user.id,\n expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 14),\n });\n const passwordResetToken = resetSession.id;\n\n const token = uuidv4();\n const invite = await createSchoolInvite({\n schoolId: input.schoolId,\n invitedById: userId,\n email: input.email,\n role: input.role,\n token,\n expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 14),\n });\n\n await acceptSchoolInvite(invite.id, createdUser.id);\n\n const passwordResetUrl = `${env.NEXT_PUBLIC_APP_URL}/reset-password/${passwordResetToken}`;\n const emailLines = [\n `You've been added to ${invite.school.name} on Studious.`,\n \"\",\n `We created an account for you with the username \"${createdUser.username}\".`,\n input.displayName\n ? `Your name is set to \"${input.displayName}\" — you can change it after signing in.`\n : `You can set your name once you sign in for the first time.`,\n \"\",\n `Set your password to get started: ${passwordResetUrl}`,\n ];\n\n try {\n await sendMail({\n from: \"hello@studious.sh\",\n to: input.email,\n subject: `Join ${invite.school.name} on Studious`,\n text: emailLines.join(\"\\n\"),\n });\n } catch (err) {\n logger.error(\"Failed to send school invite email\", {\n schoolId: input.schoolId,\n email: input.email,\n err,\n });\n }\n\n return {\n invite,\n createdUser,\n passwordResetUrl,\n };\n}\n\nexport async function revokeInvite(\n userId: string,\n input: { schoolId: string; inviteId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n return { invite: await revokeSchoolInvite(input.inviteId, input.schoolId) };\n}\n\nexport async function getInvite(token: string) {\n const invite = await findPendingInviteByToken(token);\n if (!invite || invite.status !== \"PENDING\") {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invite not found\" });\n }\n if (invite.expiresAt < new Date()) {\n throw new TRPCError({ code: \"UNAUTHORIZED\", message: \"Invite expired\" });\n }\n return {\n invite: {\n id: invite.id,\n email: invite.email,\n role: invite.role,\n school: invite.school,\n expiresAt: invite.expiresAt,\n },\n };\n}\n\nexport async function acceptInvite(userId: string, token: string) {\n const invite = await findPendingInviteByToken(token);\n if (!invite || invite.status !== \"PENDING\") {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Invite not found\" });\n }\n if (invite.expiresAt < new Date()) {\n throw new TRPCError({ code: \"UNAUTHORIZED\", message: \"Invite expired\" });\n }\n\n const user = await findUserById(userId);\n if (!user) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"User not found\" });\n }\n if (user.email.toLowerCase() !== invite.email.toLowerCase()) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"This invite was sent to a different account\",\n });\n }\n\n const membership = await acceptSchoolInvite(invite.id, userId);\n return { membership };\n}\n"],"names":[],"mappings":"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","debug_id":"c3d38743-6297-594a-9bde-bf049584e6b4"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studious-lms/server",
3
- "version": "1.25.0",
3
+ "version": "1.26.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,100 @@
1
+ -- CreateEnum
2
+ CREATE TYPE "CourseModuleItemType" AS ENUM ('ASSIGNMENT', 'WORKSHEET', 'FILE', 'ANNOUNCEMENT', 'DISCUSSION', 'EXTERNAL_URL', 'SUB_HEADER');
3
+
4
+ -- CreateEnum
5
+ CREATE TYPE "ModuleItemRequirementType" AS ENUM ('VIEW', 'SUBMIT', 'SCORE_AT_LEAST');
6
+
7
+ -- CreateEnum
8
+ CREATE TYPE "ModuleItemProgressStatus" AS ENUM ('INCOMPLETE', 'COMPLETE');
9
+
10
+ -- CreateTable
11
+ CREATE TABLE "Module" (
12
+ "id" TEXT NOT NULL,
13
+ "classId" TEXT NOT NULL,
14
+ "title" TEXT NOT NULL,
15
+ "position" INTEGER NOT NULL,
16
+ "unlockAt" TIMESTAMP(3),
17
+ "requireSequential" BOOLEAN NOT NULL DEFAULT false,
18
+ "published" BOOLEAN NOT NULL DEFAULT false,
19
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
20
+ "updatedAt" TIMESTAMP(3) NOT NULL,
21
+
22
+ CONSTRAINT "Module_pkey" PRIMARY KEY ("id")
23
+ );
24
+
25
+ -- CreateTable
26
+ CREATE TABLE "ModulePrerequisite" (
27
+ "id" TEXT NOT NULL,
28
+ "moduleId" TEXT NOT NULL,
29
+ "prerequisiteId" TEXT NOT NULL,
30
+
31
+ CONSTRAINT "ModulePrerequisite_pkey" PRIMARY KEY ("id")
32
+ );
33
+
34
+ -- CreateTable
35
+ CREATE TABLE "CourseModuleItem" (
36
+ "id" TEXT NOT NULL,
37
+ "moduleId" TEXT NOT NULL,
38
+ "position" INTEGER NOT NULL,
39
+ "indent" INTEGER NOT NULL DEFAULT 0,
40
+ "itemType" "CourseModuleItemType" NOT NULL,
41
+ "itemId" TEXT,
42
+ "externalUrl" TEXT,
43
+ "title" TEXT,
44
+ "requirementType" "ModuleItemRequirementType",
45
+ "requiredScore" DOUBLE PRECISION,
46
+
47
+ CONSTRAINT "CourseModuleItem_pkey" PRIMARY KEY ("id")
48
+ );
49
+
50
+ -- CreateTable
51
+ CREATE TABLE "ModuleItemProgress" (
52
+ "id" TEXT NOT NULL,
53
+ "moduleItemId" TEXT NOT NULL,
54
+ "studentId" TEXT NOT NULL,
55
+ "status" "ModuleItemProgressStatus" NOT NULL DEFAULT 'INCOMPLETE',
56
+ "completedAt" TIMESTAMP(3),
57
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
58
+ "updatedAt" TIMESTAMP(3) NOT NULL,
59
+
60
+ CONSTRAINT "ModuleItemProgress_pkey" PRIMARY KEY ("id")
61
+ );
62
+
63
+ -- CreateIndex
64
+ CREATE INDEX "Module_classId_position_idx" ON "Module"("classId", "position");
65
+
66
+ -- CreateIndex
67
+ CREATE INDEX "ModulePrerequisite_prerequisiteId_idx" ON "ModulePrerequisite"("prerequisiteId");
68
+
69
+ -- CreateIndex
70
+ CREATE UNIQUE INDEX "ModulePrerequisite_moduleId_prerequisiteId_key" ON "ModulePrerequisite"("moduleId", "prerequisiteId");
71
+
72
+ -- CreateIndex
73
+ CREATE INDEX "CourseModuleItem_moduleId_position_idx" ON "CourseModuleItem"("moduleId", "position");
74
+
75
+ -- CreateIndex
76
+ CREATE INDEX "CourseModuleItem_itemType_itemId_idx" ON "CourseModuleItem"("itemType", "itemId");
77
+
78
+ -- CreateIndex
79
+ CREATE INDEX "ModuleItemProgress_studentId_idx" ON "ModuleItemProgress"("studentId");
80
+
81
+ -- CreateIndex
82
+ CREATE UNIQUE INDEX "ModuleItemProgress_moduleItemId_studentId_key" ON "ModuleItemProgress"("moduleItemId", "studentId");
83
+
84
+ -- AddForeignKey
85
+ ALTER TABLE "Module" ADD CONSTRAINT "Module_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE CASCADE ON UPDATE CASCADE;
86
+
87
+ -- AddForeignKey
88
+ ALTER TABLE "ModulePrerequisite" ADD CONSTRAINT "ModulePrerequisite_moduleId_fkey" FOREIGN KEY ("moduleId") REFERENCES "Module"("id") ON DELETE CASCADE ON UPDATE CASCADE;
89
+
90
+ -- AddForeignKey
91
+ ALTER TABLE "ModulePrerequisite" ADD CONSTRAINT "ModulePrerequisite_prerequisiteId_fkey" FOREIGN KEY ("prerequisiteId") REFERENCES "Module"("id") ON DELETE CASCADE ON UPDATE CASCADE;
92
+
93
+ -- AddForeignKey
94
+ ALTER TABLE "CourseModuleItem" ADD CONSTRAINT "CourseModuleItem_moduleId_fkey" FOREIGN KEY ("moduleId") REFERENCES "Module"("id") ON DELETE CASCADE ON UPDATE CASCADE;
95
+
96
+ -- AddForeignKey
97
+ ALTER TABLE "ModuleItemProgress" ADD CONSTRAINT "ModuleItemProgress_moduleItemId_fkey" FOREIGN KEY ("moduleItemId") REFERENCES "CourseModuleItem"("id") ON DELETE CASCADE ON UPDATE CASCADE;
98
+
99
+ -- AddForeignKey
100
+ ALTER TABLE "ModuleItemProgress" ADD CONSTRAINT "ModuleItemProgress_studentId_fkey" FOREIGN KEY ("studentId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -328,6 +328,7 @@ model User {
328
328
  discussions Discussion[]
329
329
  discussionReplies DiscussionReply[]
330
330
  discussionReads DiscussionRead[]
331
+ moduleItemProgress ModuleItemProgress[]
331
332
  customGradeEntries CustomGradeEntry[] @relation("UserCustomGradeEntries")
332
333
  fileAnnotations FileAnnotation[] @relation("AuthoredFileAnnotations")
333
334
  marketplaceListings MarketplaceListing[] @relation("MarketplaceListingAuthor")
@@ -428,6 +429,8 @@ model Class {
428
429
  studentsCanCreateDiscussions Boolean @default(true)
429
430
  studentsCanReply Boolean @default(true)
430
431
 
432
+ modules Module[]
433
+
431
434
  /// Teacher-controlled ClassSidebar visibility. Keys match nav hrefs
432
435
  /// without leading slash (e.g. "assignments", "quizzes"). Null = all defaults on.
433
436
  sidebarFeatures Json?
@@ -1478,6 +1481,96 @@ model Permission {
1478
1481
  @@index([schoolId])
1479
1482
  }
1480
1483
 
1484
+ enum CourseModuleItemType {
1485
+ ASSIGNMENT
1486
+ WORKSHEET
1487
+ FILE
1488
+ ANNOUNCEMENT
1489
+ DISCUSSION
1490
+ EXTERNAL_URL
1491
+ SUB_HEADER
1492
+ }
1493
+
1494
+ enum ModuleItemRequirementType {
1495
+ VIEW
1496
+ SUBMIT
1497
+ SCORE_AT_LEAST
1498
+ }
1499
+
1500
+ enum ModuleItemProgressStatus {
1501
+ INCOMPLETE
1502
+ COMPLETE
1503
+ }
1504
+
1505
+ /// Canvas-style course module: an ordered group of content items with
1506
+ /// optional prerequisites, unlock date and sequential progression.
1507
+ model Module {
1508
+ id String @id @default(uuid())
1509
+ classId String
1510
+ class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
1511
+ title String
1512
+ position Int
1513
+ unlockAt DateTime?
1514
+ requireSequential Boolean @default(false)
1515
+ published Boolean @default(false)
1516
+ createdAt DateTime @default(now())
1517
+ updatedAt DateTime @updatedAt
1518
+
1519
+ items CourseModuleItem[]
1520
+ prerequisites ModulePrerequisite[] @relation("ModulePrerequisites")
1521
+ requiredBy ModulePrerequisite[] @relation("ModuleRequiredBy")
1522
+
1523
+ @@index([classId, position])
1524
+ }
1525
+
1526
+ model ModulePrerequisite {
1527
+ id String @id @default(uuid())
1528
+ moduleId String
1529
+ module Module @relation("ModulePrerequisites", fields: [moduleId], references: [id], onDelete: Cascade)
1530
+ prerequisiteId String
1531
+ prerequisite Module @relation("ModuleRequiredBy", fields: [prerequisiteId], references: [id], onDelete: Cascade)
1532
+
1533
+ @@unique([moduleId, prerequisiteId])
1534
+ @@index([prerequisiteId])
1535
+ }
1536
+
1537
+ model CourseModuleItem {
1538
+ id String @id @default(uuid())
1539
+ moduleId String
1540
+ module Module @relation(fields: [moduleId], references: [id], onDelete: Cascade)
1541
+ position Int
1542
+ indent Int @default(0)
1543
+ itemType CourseModuleItemType
1544
+ /// ID of the referenced assignment / worksheet / file / announcement /
1545
+ /// discussion. Null for EXTERNAL_URL and SUB_HEADER items.
1546
+ itemId String?
1547
+ externalUrl String?
1548
+ /// Display title override; required for EXTERNAL_URL and SUB_HEADER.
1549
+ title String?
1550
+ requirementType ModuleItemRequirementType?
1551
+ requiredScore Float?
1552
+
1553
+ progress ModuleItemProgress[]
1554
+
1555
+ @@index([moduleId, position])
1556
+ @@index([itemType, itemId])
1557
+ }
1558
+
1559
+ model ModuleItemProgress {
1560
+ id String @id @default(uuid())
1561
+ moduleItemId String
1562
+ moduleItem CourseModuleItem @relation(fields: [moduleItemId], references: [id], onDelete: Cascade)
1563
+ studentId String
1564
+ student User @relation(fields: [studentId], references: [id], onDelete: Cascade)
1565
+ status ModuleItemProgressStatus @default(INCOMPLETE)
1566
+ completedAt DateTime?
1567
+ createdAt DateTime @default(now())
1568
+ updatedAt DateTime @updatedAt
1569
+
1570
+ @@unique([moduleItemId, studentId])
1571
+ @@index([studentId])
1572
+ }
1573
+
1481
1574
  // ---------------------------------------------------------------------------
1482
1575
  // A2 — Monthly student fees + manual payment ledger (Nepal pilot)
1483
1576
  // Billing period = FeeInvoice.year + FeeInvoice.month (no separate term table;
@@ -135,6 +135,22 @@ export async function searchMarketplaceListings(input: {
135
135
  return { items: rows, nextCursor };
136
136
  }
137
137
 
138
+ export async function updateMarketplaceListing(
139
+ id: string,
140
+ data: {
141
+ title?: string;
142
+ description?: string | null;
143
+ visibility?: MarketplaceVisibility;
144
+ tags?: string[];
145
+ }
146
+ ) {
147
+ return prisma.marketplaceListing.update({
148
+ where: { id },
149
+ data,
150
+ include: marketplaceListingInclude,
151
+ });
152
+ }
153
+
138
154
  export async function incrementMarketplaceReportCount(id: string) {
139
155
  return prisma.marketplaceListing.update({
140
156
  where: { id },