@studious-lms/server 1.2.45 → 1.2.47

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 (241) hide show
  1. package/.env.example +45 -0
  2. package/.env.test.example +37 -0
  3. package/README.md +34 -7
  4. package/coverage/base.css +224 -0
  5. package/coverage/block-navigation.js +87 -0
  6. package/coverage/clover.xml +12110 -0
  7. package/coverage/coverage-final.json +44 -0
  8. package/coverage/favicon.png +0 -0
  9. package/coverage/index.html +221 -0
  10. package/coverage/prettify.css +1 -0
  11. package/coverage/prettify.js +2 -0
  12. package/coverage/server/index.html +116 -0
  13. package/coverage/server/src/exportType.ts.html +109 -0
  14. package/coverage/server/src/index.html +161 -0
  15. package/coverage/server/src/index.ts.html +1702 -0
  16. package/coverage/server/src/instrument.ts.html +130 -0
  17. package/coverage/server/src/lib/config/env.ts.html +448 -0
  18. package/coverage/server/src/lib/config/index.html +116 -0
  19. package/coverage/server/src/lib/fileUpload.ts.html +1138 -0
  20. package/coverage/server/src/lib/googleCloudStorage.ts.html +334 -0
  21. package/coverage/server/src/lib/index.html +206 -0
  22. package/coverage/server/src/lib/jsonConversion.ts.html +2323 -0
  23. package/coverage/server/src/lib/jsonStyles.ts.html +193 -0
  24. package/coverage/server/src/lib/notificationHandler.ts.html +193 -0
  25. package/coverage/server/src/lib/pusher.ts.html +121 -0
  26. package/coverage/server/src/lib/thumbnailGenerator.ts.html +592 -0
  27. package/coverage/server/src/middleware/auth.ts.html +646 -0
  28. package/coverage/server/src/middleware/index.html +146 -0
  29. package/coverage/server/src/middleware/logging.ts.html +244 -0
  30. package/coverage/server/src/middleware/security.ts.html +271 -0
  31. package/coverage/server/src/routers/_app.ts.html +232 -0
  32. package/coverage/server/src/routers/agenda.ts.html +319 -0
  33. package/coverage/server/src/routers/announcement.ts.html +3481 -0
  34. package/coverage/server/src/routers/assignment.ts.html +7633 -0
  35. package/coverage/server/src/routers/attendance.ts.html +1030 -0
  36. package/coverage/server/src/routers/auth.ts.html +1081 -0
  37. package/coverage/server/src/routers/class.ts.html +3535 -0
  38. package/coverage/server/src/routers/comment.ts.html +991 -0
  39. package/coverage/server/src/routers/conversation.ts.html +982 -0
  40. package/coverage/server/src/routers/event.ts.html +1609 -0
  41. package/coverage/server/src/routers/file.ts.html +1144 -0
  42. package/coverage/server/src/routers/folder.ts.html +2797 -0
  43. package/coverage/server/src/routers/index.html +386 -0
  44. package/coverage/server/src/routers/labChat.ts.html +3073 -0
  45. package/coverage/server/src/routers/marketing.ts.html +340 -0
  46. package/coverage/server/src/routers/message.ts.html +1912 -0
  47. package/coverage/server/src/routers/notifications.ts.html +364 -0
  48. package/coverage/server/src/routers/section.ts.html +1120 -0
  49. package/coverage/server/src/routers/user.ts.html +862 -0
  50. package/coverage/server/src/routers/worksheet.ts.html +1729 -0
  51. package/coverage/server/src/trpc.ts.html +397 -0
  52. package/coverage/server/src/types/index.html +116 -0
  53. package/coverage/server/src/types/trpc.ts.html +127 -0
  54. package/coverage/server/src/utils/aiUser.ts.html +280 -0
  55. package/coverage/server/src/utils/email.ts.html +121 -0
  56. package/coverage/server/src/utils/generateInviteCode.ts.html +106 -0
  57. package/coverage/server/src/utils/index.html +206 -0
  58. package/coverage/server/src/utils/inference.ts.html +709 -0
  59. package/coverage/server/src/utils/logger.ts.html +664 -0
  60. package/coverage/server/src/utils/prismaErrorHandler.ts.html +907 -0
  61. package/coverage/server/src/utils/prismaWrapper.ts.html +355 -0
  62. package/coverage/server/vitest.config.ts.html +196 -0
  63. package/coverage/sort-arrow-sprite.png +0 -0
  64. package/coverage/sorter.js +210 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +83 -52
  67. package/dist/index.js.map +1 -1
  68. package/dist/instrument.js +15 -8
  69. package/dist/instrument.js.map +1 -1
  70. package/dist/lib/config/env.d.ts +169 -0
  71. package/dist/lib/config/env.d.ts.map +1 -0
  72. package/dist/lib/config/env.js +115 -0
  73. package/dist/lib/config/env.js.map +1 -0
  74. package/dist/lib/fileUpload.d.ts.map +1 -1
  75. package/dist/lib/fileUpload.js +5 -4
  76. package/dist/lib/fileUpload.js.map +1 -1
  77. package/dist/lib/googleCloudStorage.d.ts.map +1 -1
  78. package/dist/lib/googleCloudStorage.js +7 -8
  79. package/dist/lib/googleCloudStorage.js.map +1 -1
  80. package/dist/lib/jsonConversion.d.ts.map +1 -1
  81. package/dist/lib/jsonConversion.js +14 -16
  82. package/dist/lib/jsonConversion.js.map +1 -1
  83. package/dist/lib/notificationHandler.d.ts +2 -2
  84. package/dist/lib/prisma.d.ts +2 -2
  85. package/dist/lib/prisma.d.ts.map +1 -1
  86. package/dist/lib/prisma.js +22 -3
  87. package/dist/lib/prisma.js.map +1 -1
  88. package/dist/lib/pusher.d.ts.map +1 -1
  89. package/dist/lib/pusher.js +8 -7
  90. package/dist/lib/pusher.js.map +1 -1
  91. package/dist/middleware/auth.d.ts.map +1 -1
  92. package/dist/middleware/auth.js +7 -5
  93. package/dist/middleware/auth.js.map +1 -1
  94. package/dist/middleware/security.d.ts +5 -0
  95. package/dist/middleware/security.d.ts.map +1 -0
  96. package/dist/middleware/security.js +77 -0
  97. package/dist/middleware/security.js.map +1 -0
  98. package/dist/routers/_app.d.ts +368 -108
  99. package/dist/routers/_app.d.ts.map +1 -1
  100. package/dist/routers/_app.js +4 -2
  101. package/dist/routers/_app.js.map +1 -1
  102. package/dist/routers/agenda.d.ts.map +1 -1
  103. package/dist/routers/agenda.js +12 -9
  104. package/dist/routers/agenda.js.map +1 -1
  105. package/dist/routers/announcement.d.ts +8 -0
  106. package/dist/routers/announcement.d.ts.map +1 -1
  107. package/dist/routers/announcement.js +6 -4
  108. package/dist/routers/announcement.js.map +1 -1
  109. package/dist/routers/assignment.d.ts +17 -4
  110. package/dist/routers/assignment.d.ts.map +1 -1
  111. package/dist/routers/assignment.js +51 -19
  112. package/dist/routers/assignment.js.map +1 -1
  113. package/dist/routers/attendance.d.ts +1 -0
  114. package/dist/routers/attendance.d.ts.map +1 -1
  115. package/dist/routers/attendance.js +4 -4
  116. package/dist/routers/attendance.js.map +1 -1
  117. package/dist/routers/auth.d.ts +20 -0
  118. package/dist/routers/auth.d.ts.map +1 -1
  119. package/dist/routers/auth.js +132 -15
  120. package/dist/routers/auth.js.map +1 -1
  121. package/dist/routers/class.d.ts +10 -0
  122. package/dist/routers/class.d.ts.map +1 -1
  123. package/dist/routers/class.js +49 -5
  124. package/dist/routers/class.js.map +1 -1
  125. package/dist/routers/comment.d.ts +2 -0
  126. package/dist/routers/comment.d.ts.map +1 -1
  127. package/dist/routers/conversation.d.ts +2 -0
  128. package/dist/routers/conversation.d.ts.map +1 -1
  129. package/dist/routers/conversation.js +46 -31
  130. package/dist/routers/conversation.js.map +1 -1
  131. package/dist/routers/file.d.ts.map +1 -1
  132. package/dist/routers/file.js +30 -7
  133. package/dist/routers/file.js.map +1 -1
  134. package/dist/routers/labChat.d.ts +2 -0
  135. package/dist/routers/labChat.d.ts.map +1 -1
  136. package/dist/routers/labChat.js +5 -322
  137. package/dist/routers/labChat.js.map +1 -1
  138. package/dist/routers/marketing.d.ts +1 -1
  139. package/dist/routers/message.d.ts +1 -0
  140. package/dist/routers/message.d.ts.map +1 -1
  141. package/dist/routers/message.js +3 -2
  142. package/dist/routers/message.js.map +1 -1
  143. package/dist/routers/newtonChat.d.ts +55 -0
  144. package/dist/routers/newtonChat.d.ts.map +1 -0
  145. package/dist/routers/newtonChat.js +262 -0
  146. package/dist/routers/newtonChat.js.map +1 -0
  147. package/dist/routers/notifications.d.ts +4 -4
  148. package/dist/routers/section.d.ts +19 -4
  149. package/dist/routers/section.d.ts.map +1 -1
  150. package/dist/routers/section.js +26 -8
  151. package/dist/routers/section.js.map +1 -1
  152. package/dist/routers/user.d.ts.map +1 -1
  153. package/dist/routers/user.js +5 -4
  154. package/dist/routers/user.js.map +1 -1
  155. package/dist/routers/worksheet.d.ts +44 -41
  156. package/dist/routers/worksheet.d.ts.map +1 -1
  157. package/dist/routers/worksheet.js +25 -34
  158. package/dist/routers/worksheet.js.map +1 -1
  159. package/dist/seedDatabase.d.ts +1 -1
  160. package/dist/seedDatabase.js +275 -284
  161. package/dist/seedDatabase.js.map +1 -1
  162. package/dist/server/pipelines/aiLabChat.d.ts +21 -0
  163. package/dist/server/pipelines/aiLabChat.d.ts.map +1 -0
  164. package/dist/server/pipelines/aiLabChat.js +456 -0
  165. package/dist/server/pipelines/aiLabChat.js.map +1 -0
  166. package/dist/server/pipelines/aiNewtonChat.d.ts +30 -0
  167. package/dist/server/pipelines/aiNewtonChat.d.ts.map +1 -0
  168. package/dist/server/pipelines/aiNewtonChat.js +280 -0
  169. package/dist/server/pipelines/aiNewtonChat.js.map +1 -0
  170. package/dist/server/pipelines/gradeWorksheet.d.ts +15 -0
  171. package/dist/server/pipelines/gradeWorksheet.d.ts.map +1 -0
  172. package/dist/server/pipelines/gradeWorksheet.js +139 -0
  173. package/dist/server/pipelines/gradeWorksheet.js.map +1 -0
  174. package/dist/trpc.d.ts.map +1 -1
  175. package/dist/trpc.js +2 -2
  176. package/dist/trpc.js.map +1 -1
  177. package/dist/utils/email.d.ts +9 -1
  178. package/dist/utils/email.d.ts.map +1 -1
  179. package/dist/utils/email.js +20 -5
  180. package/dist/utils/email.js.map +1 -1
  181. package/dist/utils/inference.d.ts +5 -0
  182. package/dist/utils/inference.d.ts.map +1 -1
  183. package/dist/utils/inference.js +71 -7
  184. package/dist/utils/inference.js.map +1 -1
  185. package/dist/utils/logger.d.ts.map +1 -1
  186. package/dist/utils/logger.js +3 -3
  187. package/dist/utils/logger.js.map +1 -1
  188. package/docker-compose.yml +14 -0
  189. package/package.json +13 -4
  190. package/prisma/schema.prisma +34 -5
  191. package/scripts/test-pre-push.ts +14 -0
  192. package/src/index.ts +98 -54
  193. package/src/instrument.ts +13 -6
  194. package/src/lib/config/env.ts +126 -0
  195. package/src/lib/fileUpload.ts +3 -2
  196. package/src/lib/googleCloudStorage.ts +6 -6
  197. package/src/lib/jsonConversion.ts +12 -14
  198. package/src/lib/prisma.ts +23 -2
  199. package/src/lib/pusher.ts +6 -5
  200. package/src/middleware/auth.ts +5 -3
  201. package/src/middleware/security.ts +80 -0
  202. package/src/routers/_app.ts +2 -0
  203. package/src/routers/agenda.ts +10 -7
  204. package/src/routers/announcement.ts +4 -2
  205. package/src/routers/assignment.ts +74 -41
  206. package/src/routers/attendance.ts +2 -2
  207. package/src/routers/auth.ts +143 -14
  208. package/src/routers/class.ts +52 -3
  209. package/src/routers/conversation.ts +49 -29
  210. package/src/routers/file.ts +29 -5
  211. package/src/routers/labChat.ts +3 -367
  212. package/src/routers/message.ts +1 -1
  213. package/src/routers/newtonChat.ts +299 -0
  214. package/src/routers/section.ts +26 -6
  215. package/src/routers/user.ts +3 -2
  216. package/src/routers/worksheet.ts +26 -38
  217. package/src/seedDatabase.ts +290 -283
  218. package/src/server/pipelines/aiLabChat.ts +507 -0
  219. package/src/server/pipelines/aiNewtonChat.ts +338 -0
  220. package/src/server/pipelines/gradeWorksheet.ts +151 -0
  221. package/src/trpc.ts +2 -0
  222. package/src/utils/email.ts +30 -3
  223. package/src/utils/inference.ts +85 -5
  224. package/src/utils/logger.ts +2 -1
  225. package/tests/announcement.test.ts +164 -0
  226. package/tests/assignment.test.ts +296 -0
  227. package/tests/attendance.test.ts +168 -0
  228. package/tests/auth.test.ts +33 -10
  229. package/tests/class.test.ts +34 -9
  230. package/tests/event.test.ts +228 -0
  231. package/tests/section.test.ts +216 -0
  232. package/tests/setup.ts +70 -16
  233. package/tests/user.test.ts +158 -0
  234. package/vitest.config.ts +26 -0
  235. package/API_SPECIFICATION.md +0 -1597
  236. package/BASE64_REMOVAL_SUMMARY.md +0 -164
  237. package/CHAT_API_SPEC.md +0 -579
  238. package/LAB_CHAT_API_SPEC.md +0 -518
  239. package/dist/routers/school.d.ts +0 -208
  240. package/dist/routers/school.d.ts.map +0 -1
  241. package/dist/routers/school.js +0 -483
@@ -1,1597 +0,0 @@
1
- # Easy LMS API Specification
2
-
3
- ## Overview
4
-
5
- Easy LMS is a comprehensive Learning Management System built with tRPC, Prisma, and PostgreSQL. This document provides a complete API specification for frontend developers.
6
-
7
- ### Base URL
8
- - **Development**: `http://localhost:3001/trpc`
9
- - **Production**: `https://your-domain.com/trpc`
10
-
11
- ### Authentication
12
- - **Method**: Bearer Token Authentication
13
- - **Header**: `Authorization: Bearer <token>`
14
- - **Session Management**: Token-based sessions with expiration
15
-
16
- ---
17
-
18
- ## 🔐 Authentication Endpoints
19
-
20
- ### `auth.register`
21
- **Type**: Mutation
22
- **Access**: Public
23
- **Description**: Register a new user account
24
-
25
- **Input**:
26
- ```typescript
27
- {
28
- username: string; // min 3 characters
29
- email: string; // valid email format
30
- password: string; // min 6 characters
31
- confirmPassword: string;
32
- }
33
- ```
34
-
35
- **Output**:
36
- ```typescript
37
- {
38
- user: {
39
- id: string;
40
- username: string;
41
- };
42
- }
43
- ```
44
-
45
- ### `auth.login`
46
- **Type**: Mutation
47
- **Access**: Public
48
- **Description**: Login with username and password
49
-
50
- **Input**:
51
- ```typescript
52
- {
53
- username: string;
54
- password: string;
55
- }
56
- ```
57
-
58
- **Output**:
59
- ```typescript
60
- {
61
- token: string;
62
- user: {
63
- id: string;
64
- username: string;
65
- };
66
- verified?: boolean;
67
- }
68
- ```
69
-
70
- ### `auth.logout`
71
- **Type**: Mutation
72
- **Access**: Public
73
- **Description**: Logout and invalidate session
74
-
75
- **Output**:
76
- ```typescript
77
- {
78
- success: boolean;
79
- }
80
- ```
81
-
82
- ### `auth.check`
83
- **Type**: Query
84
- **Access**: Protected
85
- **Description**: Verify current authentication status
86
-
87
- **Output**:
88
- ```typescript
89
- {
90
- user: {
91
- id: string;
92
- username: string;
93
- };
94
- }
95
- ```
96
-
97
- ### `auth.verify`
98
- **Type**: Mutation
99
- **Access**: Public
100
- **Description**: Verify email with token
101
-
102
- **Input**:
103
- ```typescript
104
- {
105
- token: string;
106
- }
107
- ```
108
-
109
- ### `auth.resendVerificationEmail`
110
- **Type**: Mutation
111
- **Access**: Public
112
- **Description**: Resend verification email
113
-
114
- **Input**:
115
- ```typescript
116
- {
117
- email: string;
118
- }
119
- ```
120
-
121
- ---
122
-
123
- ## 👤 User Management
124
-
125
- ### `user.getProfile`
126
- **Type**: Query
127
- **Access**: Protected
128
- **Description**: Get current user profile
129
-
130
- **Output**:
131
- ```typescript
132
- {
133
- id: string;
134
- username: string;
135
- profile: Record<string, any>;
136
- }
137
- ```
138
-
139
- ### `user.updateProfile`
140
- **Type**: Mutation
141
- **Access**: Protected
142
- **Description**: Update user profile
143
-
144
- **Input**:
145
- ```typescript
146
- {
147
- profile?: {
148
- displayName?: string;
149
- bio?: string;
150
- location?: string;
151
- website?: string;
152
- };
153
- // For custom profile picture (already uploaded to GCS)
154
- profilePicture?: {
155
- filePath: string;
156
- fileName: string;
157
- fileType: string; // image/jpeg, image/png, etc.
158
- fileSize: number;
159
- };
160
- // OR use DiceBear avatar URL
161
- dicebearAvatar?: {
162
- url: string; // DiceBear avatar URL
163
- };
164
- }
165
- ```
166
-
167
- **Note**: Profile pictures use direct upload to GCS. First get a signed upload URL using `user.getProfilePictureUploadUrl`, upload the file directly to GCS, then call this endpoint with the file path.
168
-
169
- ---
170
-
171
- ## 🏫 Class Management
172
-
173
- ### `class.getAll`
174
- **Type**: Query
175
- **Access**: Protected
176
- **Description**: Get all classes for current user
177
-
178
- **Output**:
179
- ```typescript
180
- {
181
- teacherInClass: Array<{
182
- id: string;
183
- name: string;
184
- section: string;
185
- subject: string;
186
- color?: string;
187
- dueToday: Assignment[];
188
- assignments: Assignment[];
189
- }>;
190
- studentInClass: Array<{
191
- id: string;
192
- name: string;
193
- section: string;
194
- subject: string;
195
- color?: string;
196
- dueToday: Assignment[];
197
- assignments: Assignment[];
198
- }>;
199
- }
200
- ```
201
-
202
- ### `class.get`
203
- **Type**: Query
204
- **Access**: Protected
205
- **Description**: Get specific class details
206
-
207
- **Input**:
208
- ```typescript
209
- {
210
- classId: string;
211
- }
212
- ```
213
-
214
- **Output**:
215
- ```typescript
216
- {
217
- class: {
218
- id: string;
219
- name: string;
220
- subject: string;
221
- section: string;
222
- color?: string;
223
- teachers: Array<{
224
- id: string;
225
- username: string;
226
- }>;
227
- students: Array<{
228
- id: string;
229
- username: string;
230
- }>;
231
- announcements: Array<{
232
- id: string;
233
- remarks: string;
234
- createdAt: Date;
235
- teacher: {
236
- id: string;
237
- username: string;
238
- };
239
- }>;
240
- assignments: Assignment[];
241
- sections: Section[];
242
- };
243
- }
244
- ```
245
-
246
- ### `class.create`
247
- **Type**: Mutation
248
- **Access**: Protected
249
- **Description**: Create a new class
250
-
251
- **Input**:
252
- ```typescript
253
- {
254
- name: string;
255
- section: string;
256
- subject: string;
257
- color?: string;
258
- students?: string[];
259
- teachers?: string[];
260
- }
261
- ```
262
-
263
- ### `class.update`
264
- **Type**: Mutation
265
- **Access**: Teacher Only
266
- **Description**: Update class details
267
-
268
- **Input**:
269
- ```typescript
270
- {
271
- classId: string;
272
- name?: string;
273
- section?: string;
274
- subject?: string;
275
- }
276
- ```
277
-
278
- ### `class.delete`
279
- **Type**: Mutation
280
- **Access**: Teacher Only
281
- **Description**: Delete a class
282
-
283
- **Input**:
284
- ```typescript
285
- {
286
- classId: string;
287
- id: string;
288
- }
289
- ```
290
-
291
- ### `class.join`
292
- **Type**: Mutation
293
- **Access**: Protected
294
- **Description**: Join class with invite code
295
-
296
- **Input**:
297
- ```typescript
298
- {
299
- classCode: string;
300
- }
301
- ```
302
-
303
- ### `class.getInviteCode`
304
- **Type**: Query
305
- **Access**: Teacher Only
306
- **Description**: Get class invite code
307
-
308
- **Input**:
309
- ```typescript
310
- {
311
- classId: string;
312
- }
313
- ```
314
-
315
- **Output**:
316
- ```typescript
317
- {
318
- code: string;
319
- }
320
- ```
321
-
322
- ### `class.addStudent`
323
- **Type**: Mutation
324
- **Access**: Teacher Only
325
- **Description**: Add student to class
326
-
327
- **Input**:
328
- ```typescript
329
- {
330
- classId: string;
331
- studentId: string;
332
- }
333
- ```
334
-
335
- ### `class.changeRole`
336
- **Type**: Mutation
337
- **Access**: Teacher Only
338
- **Description**: Change user role in class
339
-
340
- **Input**:
341
- ```typescript
342
- {
343
- classId: string;
344
- userId: string;
345
- type: 'teacher' | 'student';
346
- }
347
- ```
348
-
349
- ### `class.removeMember`
350
- **Type**: Mutation
351
- **Access**: Teacher Only
352
- **Description**: Remove member from class
353
-
354
- **Input**:
355
- ```typescript
356
- {
357
- classId: string;
358
- userId: string;
359
- }
360
- ```
361
-
362
- ---
363
-
364
- ## 📝 Assignment Management
365
-
366
- ### `assignment.create`
367
- **Type**: Mutation
368
- **Access**: Protected
369
- **Description**: Create a new assignment
370
-
371
- **Input**:
372
- ```typescript
373
- {
374
- classId: string;
375
- title: string;
376
- instructions: string;
377
- dueDate: string;
378
- files?: File[];
379
- existingFileIds?: string[];
380
- maxGrade?: number;
381
- graded?: boolean;
382
- weight?: number;
383
- sectionId?: string;
384
- type?: 'HOMEWORK' | 'QUIZ' | 'TEST' | 'PROJECT' | 'ESSAY' | 'DISCUSSION' | 'PRESENTATION' | 'LAB' | 'OTHER';
385
- markSchemeId?: string;
386
- gradingBoundaryId?: string;
387
- inProgress?: boolean;
388
- }
389
- ```
390
-
391
- ### `assignment.update`
392
- **Type**: Mutation
393
- **Access**: Protected
394
- **Description**: Update assignment
395
-
396
- **Input**:
397
- ```typescript
398
- {
399
- classId: string;
400
- id: string;
401
- title?: string;
402
- instructions?: string;
403
- dueDate?: string;
404
- files?: File[];
405
- existingFileIds?: string[];
406
- removedAttachments?: string[];
407
- maxGrade?: number;
408
- graded?: boolean;
409
- weight?: number;
410
- sectionId?: string | null;
411
- type?: AssignmentType;
412
- inProgress?: boolean;
413
- }
414
- ```
415
-
416
- ### `assignment.delete`
417
- **Type**: Mutation
418
- **Access**: Protected
419
- **Description**: Delete assignment
420
-
421
- **Input**:
422
- ```typescript
423
- {
424
- id: string;
425
- classId: string;
426
- }
427
- ```
428
-
429
- ### `assignment.get`
430
- **Type**: Query
431
- **Access**: Protected
432
- **Description**: Get assignment details
433
-
434
- **Input**:
435
- ```typescript
436
- {
437
- id: string;
438
- classId: string;
439
- }
440
- ```
441
-
442
- ### `assignment.getSubmission`
443
- **Type**: Query
444
- **Access**: Class Member
445
- **Description**: Get student's submission for assignment
446
-
447
- **Input**:
448
- ```typescript
449
- {
450
- assignmentId: string;
451
- classId: string;
452
- }
453
- ```
454
-
455
- ### `assignment.getSubmissions`
456
- **Type**: Query
457
- **Access**: Teacher Only
458
- **Description**: Get all submissions for assignment
459
-
460
- **Input**:
461
- ```typescript
462
- {
463
- assignmentId: string;
464
- classId: string;
465
- }
466
- ```
467
-
468
- ### `assignment.updateSubmission`
469
- **Type**: Mutation
470
- **Access**: Class Member
471
- **Description**: Update student submission
472
-
473
- **Input**:
474
- ```typescript
475
- {
476
- assignmentId: string;
477
- classId: string;
478
- submissionId: string;
479
- submit?: boolean;
480
- newAttachments?: File[];
481
- existingFileIds?: string[];
482
- removedAttachments?: string[];
483
- }
484
- ```
485
-
486
- ### `assignment.updateSubmissionAsTeacher`
487
- **Type**: Mutation
488
- **Access**: Teacher Only
489
- **Description**: Update submission as teacher (grading)
490
-
491
- **Input**:
492
- ```typescript
493
- {
494
- assignmentId: string;
495
- classId: string;
496
- submissionId: string;
497
- return?: boolean;
498
- gradeReceived?: number | null;
499
- newAttachments?: File[];
500
- existingFileIds?: string[];
501
- removedAttachments?: string[];
502
- rubricGrades?: Array<{
503
- criteriaId: string;
504
- selectedLevelId: string;
505
- points: number;
506
- comments: string;
507
- }>;
508
- }
509
- ```
510
-
511
- ---
512
-
513
- ## 📢 Announcements
514
-
515
- ### `announcement.getAll`
516
- **Type**: Query
517
- **Access**: Class Member
518
- **Description**: Get all class announcements
519
-
520
- **Input**:
521
- ```typescript
522
- {
523
- classId: string;
524
- }
525
- ```
526
-
527
- **Output**:
528
- ```typescript
529
- {
530
- announcements: Array<{
531
- id: string;
532
- remarks: string;
533
- createdAt: Date;
534
- teacher: {
535
- id: string;
536
- username: string;
537
- };
538
- }>;
539
- }
540
- ```
541
-
542
- ### `announcement.create`
543
- **Type**: Mutation
544
- **Access**: Teacher Only
545
- **Description**: Create new announcement
546
-
547
- **Input**:
548
- ```typescript
549
- {
550
- classId: string;
551
- remarks: string;
552
- }
553
- ```
554
-
555
- ### `announcement.update`
556
- **Type**: Mutation
557
- **Access**: Protected
558
- **Description**: Update announcement
559
-
560
- **Input**:
561
- ```typescript
562
- {
563
- id: string;
564
- data: {
565
- content: string;
566
- };
567
- }
568
- ```
569
-
570
- ### `announcement.delete`
571
- **Type**: Mutation
572
- **Access**: Protected
573
- **Description**: Delete announcement
574
-
575
- **Input**:
576
- ```typescript
577
- {
578
- id: string;
579
- }
580
- ```
581
-
582
- ---
583
-
584
- ## 📁 Folder Management
585
-
586
- ### `folder.create`
587
- **Type**: Mutation
588
- **Access**: Teacher Only
589
- **Description**: Create a new folder in a class
590
-
591
- **Input**:
592
- ```typescript
593
- {
594
- classId: string;
595
- name: string;
596
- parentFolderId?: string;
597
- }
598
- ```
599
-
600
- ### `folder.get`
601
- **Type**: Query
602
- **Access**: Class Member
603
- **Description**: Get folder details and contents
604
-
605
- **Input**:
606
- ```typescript
607
- {
608
- classId: string;
609
- folderId: string;
610
- }
611
- ```
612
-
613
- ### `folder.getChildFolders`
614
- **Type**: Query
615
- **Access**: Class Member
616
- **Description**: Get child folders of a folder
617
-
618
- **Input**:
619
- ```typescript
620
- {
621
- classId: string;
622
- folderId: string;
623
- }
624
- ```
625
-
626
- ### `folder.getFolderChildren`
627
- **Type**: Query
628
- **Access**: Class Member
629
- **Description**: Get all children (files and folders) of a folder
630
-
631
- **Input**:
632
- ```typescript
633
- {
634
- classId: string;
635
- folderId: string;
636
- }
637
- ```
638
-
639
- ### `folder.getRootFolder`
640
- **Type**: Query
641
- **Access**: Class Member
642
- **Description**: Get root folder for a class
643
-
644
- **Input**:
645
- ```typescript
646
- {
647
- classId: string;
648
- }
649
- ```
650
-
651
- ### `folder.uploadFiles`
652
- **Type**: Mutation
653
- **Access**: Teacher Only
654
- **Description**: Upload files to a folder
655
-
656
- **Input**:
657
- ```typescript
658
- {
659
- classId: string;
660
- folderId: string;
661
- files: File[];
662
- }
663
- ```
664
-
665
- ### `folder.delete`
666
- **Type**: Mutation
667
- **Access**: Teacher Only
668
- **Description**: Delete a folder
669
-
670
- **Input**:
671
- ```typescript
672
- {
673
- classId: string;
674
- folderId: string;
675
- }
676
- ```
677
-
678
- ### `folder.move`
679
- **Type**: Mutation
680
- **Access**: Teacher Only
681
- **Description**: Move folder to different parent
682
-
683
- **Input**:
684
- ```typescript
685
- {
686
- classId: string;
687
- folderId: string;
688
- newParentFolderId: string;
689
- }
690
- ```
691
-
692
- ### `folder.rename`
693
- **Type**: Mutation
694
- **Access**: Teacher Only
695
- **Description**: Rename a folder
696
-
697
- **Input**:
698
- ```typescript
699
- {
700
- classId: string;
701
- folderId: string;
702
- newName: string;
703
- }
704
- ```
705
-
706
- ---
707
-
708
- ## 📁 File Management
709
-
710
- ### `file.getSignedUrl`
711
- **Type**: Mutation
712
- **Access**: Protected
713
- **Description**: Get signed URL for file download
714
-
715
- **Input**:
716
- ```typescript
717
- {
718
- fileId: string;
719
- }
720
- ```
721
-
722
- **Output**:
723
- ```typescript
724
- {
725
- url: string;
726
- }
727
- ```
728
-
729
- ### `file.move`
730
- **Type**: Mutation
731
- **Access**: Teacher Only
732
- **Description**: Move file to different folder
733
-
734
- **Input**:
735
- ```typescript
736
- {
737
- fileId: string;
738
- targetFolderId: string;
739
- classId: string;
740
- }
741
- ```
742
-
743
- ### `file.rename`
744
- **Type**: Mutation
745
- **Access**: Teacher Only
746
- **Description**: Rename file
747
-
748
- **Input**:
749
- ```typescript
750
- {
751
- fileId: string;
752
- newName: string;
753
- classId: string;
754
- }
755
- ```
756
-
757
- ### `file.delete`
758
- **Type**: Mutation
759
- **Access**: Teacher Only
760
- **Description**: Delete file
761
-
762
- **Input**:
763
- ```typescript
764
- {
765
- fileId: string;
766
- classId: string;
767
- }
768
- ```
769
-
770
- ---
771
-
772
- ## 📚 Section Management
773
-
774
- ### `section.create`
775
- **Type**: Mutation
776
- **Access**: Teacher Only
777
- **Description**: Create a new section in a class
778
-
779
- **Input**:
780
- ```typescript
781
- {
782
- classId: string;
783
- name: string;
784
- }
785
- ```
786
-
787
- **Output**:
788
- ```typescript
789
- {
790
- id: string;
791
- name: string;
792
- classId: string;
793
- }
794
- ```
795
-
796
- ### `section.update`
797
- **Type**: Mutation
798
- **Access**: Teacher Only
799
- **Description**: Update section name
800
-
801
- **Input**:
802
- ```typescript
803
- {
804
- id: string;
805
- classId: string;
806
- name: string;
807
- }
808
- ```
809
-
810
- **Output**:
811
- ```typescript
812
- {
813
- id: string;
814
- name: string;
815
- classId: string;
816
- }
817
- ```
818
-
819
- ### `section.delete`
820
- **Type**: Mutation
821
- **Access**: Teacher Only
822
- **Description**: Delete a section
823
-
824
- **Input**:
825
- ```typescript
826
- {
827
- id: string;
828
- classId: string;
829
- }
830
- ```
831
-
832
- **Output**:
833
- ```typescript
834
- {
835
- id: string;
836
- }
837
- ```
838
-
839
- ---
840
-
841
- ## 📊 Attendance Management
842
-
843
- ### `attendance.get`
844
- **Type**: Query
845
- **Access**: Class Member
846
- **Description**: Get attendance records for a class
847
-
848
- **Input**:
849
- ```typescript
850
- {
851
- classId: string;
852
- eventId?: string;
853
- }
854
- ```
855
-
856
- **Output**:
857
- ```typescript
858
- Array<{
859
- id: string;
860
- date: Date;
861
- event?: {
862
- id: string;
863
- name: string;
864
- startTime: Date;
865
- endTime: Date;
866
- location: string;
867
- color: string;
868
- };
869
- present: Array<{
870
- id: string;
871
- username: string;
872
- }>;
873
- late: Array<{
874
- id: string;
875
- username: string;
876
- }>;
877
- absent: Array<{
878
- id: string;
879
- username: string;
880
- }>;
881
- }>
882
- ```
883
-
884
- ### `attendance.update`
885
- **Type**: Mutation
886
- **Access**: Teacher Only
887
- **Description**: Update attendance for a class event
888
-
889
- **Input**:
890
- ```typescript
891
- {
892
- classId: string;
893
- eventId?: string;
894
- attendance: {
895
- present: Array<{
896
- id: string;
897
- username: string;
898
- }>;
899
- late: Array<{
900
- id: string;
901
- username: string;
902
- }>;
903
- absent: Array<{
904
- id: string;
905
- username: string;
906
- }>;
907
- };
908
- }
909
- ```
910
-
911
- **Output**:
912
- ```typescript
913
- {
914
- id: string;
915
- date: Date;
916
- event?: {
917
- id: string;
918
- name: string;
919
- startTime: Date;
920
- endTime: Date;
921
- location: string;
922
- };
923
- present: Array<{
924
- id: string;
925
- username: string;
926
- }>;
927
- late: Array<{
928
- id: string;
929
- username: string;
930
- }>;
931
- absent: Array<{
932
- id: string;
933
- username: string;
934
- }>;
935
- }
936
- ```
937
-
938
- ---
939
-
940
- ## 📅 Agenda Management
941
-
942
- ### `agenda.get`
943
- **Type**: Query
944
- **Access**: Protected
945
- **Description**: Get user's weekly agenda with personal and class events
946
-
947
- **Input**:
948
- ```typescript
949
- {
950
- weekStart: string; // ISO date string
951
- }
952
- ```
953
-
954
- **Output**:
955
- ```typescript
956
- {
957
- events: {
958
- personal: Array<{
959
- id: string;
960
- name: string;
961
- startTime: Date;
962
- endTime: Date;
963
- location?: string;
964
- color?: string;
965
- class: null;
966
- }>;
967
- class: Array<{
968
- id: string;
969
- name: string;
970
- startTime: Date;
971
- endTime: Date;
972
- location?: string;
973
- color?: string;
974
- class: {
975
- id: string;
976
- name: string;
977
- subject: string;
978
- section: string;
979
- };
980
- }>;
981
- };
982
- }
983
- ```
984
-
985
- ---
986
-
987
- ## 🔔 Notifications
988
-
989
- ### `notification.list`
990
- **Type**: Query
991
- **Access**: Protected
992
- **Description**: Get all notifications for user
993
-
994
- **Output**:
995
- ```typescript
996
- Array<{
997
- id: string;
998
- title: string;
999
- content: string;
1000
- createdAt: Date;
1001
- read: boolean;
1002
- sender?: {
1003
- username: string;
1004
- };
1005
- receiver: {
1006
- username: string;
1007
- };
1008
- }>
1009
- ```
1010
-
1011
- ### `notification.get`
1012
- **Type**: Query
1013
- **Access**: Protected
1014
- **Description**: Get specific notification
1015
-
1016
- **Input**:
1017
- ```typescript
1018
- {
1019
- id: string;
1020
- }
1021
- ```
1022
-
1023
- ### `notification.sendTo`
1024
- **Type**: Mutation
1025
- **Access**: Protected
1026
- **Description**: Send notification to user
1027
-
1028
- **Input**:
1029
- ```typescript
1030
- {
1031
- receiverId: string;
1032
- title: string;
1033
- content: string;
1034
- }
1035
- ```
1036
-
1037
- ### `notification.sendToMultiple`
1038
- **Type**: Mutation
1039
- **Access**: Protected
1040
- **Description**: Send notification to multiple users
1041
-
1042
- **Input**:
1043
- ```typescript
1044
- {
1045
- receiverIds: string[];
1046
- title: string;
1047
- content: string;
1048
- }
1049
- ```
1050
-
1051
- ### `notification.markAsRead`
1052
- **Type**: Mutation
1053
- **Access**: Protected
1054
- **Description**: Mark notification as read
1055
-
1056
- **Input**:
1057
- ```typescript
1058
- {
1059
- id: string;
1060
- }
1061
- ```
1062
-
1063
- ---
1064
-
1065
-
1066
- ## 📊 Grading & Assessment
1067
-
1068
- ### `class.getGrades`
1069
- **Type**: Query
1070
- **Access**: Class Member
1071
- **Description**: Get grades for a user
1072
-
1073
- **Input**:
1074
- ```typescript
1075
- {
1076
- classId: string;
1077
- userId: string;
1078
- }
1079
- ```
1080
-
1081
- ### `class.updateGrade`
1082
- **Type**: Mutation
1083
- **Access**: Teacher Only
1084
- **Description**: Update student grade
1085
-
1086
- **Input**:
1087
- ```typescript
1088
- {
1089
- classId: string;
1090
- assignmentId: string;
1091
- submissionId: string;
1092
- gradeReceived: number | null;
1093
- }
1094
- ```
1095
-
1096
- ### Mark Schemes
1097
-
1098
- ### `class.listMarkSchemes`
1099
- **Type**: Query
1100
- **Access**: Teacher Only
1101
-
1102
- ### `class.createMarkScheme`
1103
- **Type**: Mutation
1104
- **Access**: Teacher Only
1105
-
1106
- ### `class.updateMarkScheme`
1107
- **Type**: Mutation
1108
- **Access**: Teacher Only
1109
-
1110
- ### `class.deleteMarkScheme`
1111
- **Type**: Mutation
1112
- **Access**: Teacher Only
1113
-
1114
- ### Grading Boundaries
1115
-
1116
- ### `class.listGradingBoundaries`
1117
- **Type**: Query
1118
- **Access**: Teacher Only
1119
-
1120
- ### `class.createGradingBoundary`
1121
- **Type**: Mutation
1122
- **Access**: Teacher Only
1123
-
1124
- ### `class.updateGradingBoundary`
1125
- **Type**: Mutation
1126
- **Access**: Teacher Only
1127
-
1128
- ### `class.deleteGradingBoundary`
1129
- **Type**: Mutation
1130
- **Access**: Teacher Only
1131
-
1132
- ---
1133
-
1134
- ## 📅 Calendar & Events
1135
-
1136
- ### `class.getEvents`
1137
- **Type**: Query
1138
- **Access**: Teacher Only
1139
- **Description**: Get class events
1140
-
1141
- **Input**:
1142
- ```typescript
1143
- {
1144
- classId: string;
1145
- }
1146
- ```
1147
-
1148
- ### `assignment.attachToEvent`
1149
- **Type**: Mutation
1150
- **Access**: Teacher Only
1151
- **Description**: Attach assignment to event
1152
-
1153
- **Input**:
1154
- ```typescript
1155
- {
1156
- assignmentId: string;
1157
- eventId: string;
1158
- }
1159
- ```
1160
-
1161
- ### `assignment.detachEvent`
1162
- **Type**: Mutation
1163
- **Access**: Teacher Only
1164
- **Description**: Detach assignment from event
1165
-
1166
- **Input**:
1167
- ```typescript
1168
- {
1169
- assignmentId: string;
1170
- }
1171
- ```
1172
-
1173
- ### `assignment.getAvailableEvents`
1174
- **Type**: Query
1175
- **Access**: Teacher Only
1176
- **Description**: Get available events for assignment
1177
-
1178
- **Input**:
1179
- ```typescript
1180
- {
1181
- assignmentId: string;
1182
- }
1183
- ```
1184
-
1185
- ---
1186
-
1187
- ## 🔧 Lab Management (Draft System)
1188
-
1189
- ### `class.listLabDrafts`
1190
- **Type**: Query
1191
- **Access**: Teacher Only
1192
- **Description**: Get lab drafts
1193
-
1194
- **Input**:
1195
- ```typescript
1196
- {
1197
- classId: string;
1198
- }
1199
- ```
1200
-
1201
- ### `class.createLabDraft`
1202
- **Type**: Mutation
1203
- **Access**: Teacher Only
1204
- **Description**: Create lab draft
1205
-
1206
- ### `class.updateLabDraft`
1207
- **Type**: Mutation
1208
- **Access**: Teacher Only
1209
- **Description**: Update lab draft
1210
-
1211
- ### `class.deleteLabDraft`
1212
- **Type**: Mutation
1213
- **Access**: Teacher Only
1214
- **Description**: Delete lab draft
1215
-
1216
- ### `class.publishLabDraft`
1217
- **Type**: Mutation
1218
- **Access**: Teacher Only
1219
- **Description**: Publish lab draft as assignment
1220
-
1221
- ---
1222
-
1223
- ## 📄 Syllabus Management
1224
-
1225
- ### `class.getSyllabus`
1226
- **Type**: Query
1227
- **Access**: Class Member
1228
- **Description**: Get class syllabus
1229
-
1230
- **Input**:
1231
- ```typescript
1232
- {
1233
- classId: string;
1234
- }
1235
- ```
1236
-
1237
- **Output**:
1238
- ```typescript
1239
- {
1240
- syllabus: string;
1241
- gradingBoundaries: GradingBoundary[];
1242
- markSchemes: MarkScheme[];
1243
- }
1244
- ```
1245
-
1246
- ### `class.updateSyllabus`
1247
- **Type**: Mutation
1248
- **Access**: Teacher Only
1249
- **Description**: Update class syllabus
1250
-
1251
- **Input**:
1252
- ```typescript
1253
- {
1254
- classId: string;
1255
- contents: string;
1256
- }
1257
- ```
1258
-
1259
- ---
1260
-
1261
- ## 🗂️ File Organization
1262
-
1263
- ### `class.getFiles`
1264
- **Type**: Query
1265
- **Access**: Class Member
1266
- **Description**: Get organized files for class
1267
-
1268
- **Input**:
1269
- ```typescript
1270
- {
1271
- classId: string;
1272
- }
1273
- ```
1274
-
1275
- **Output**:
1276
- ```typescript
1277
- Array<{
1278
- id: string;
1279
- title: string;
1280
- teacher: {
1281
- id: string;
1282
- username: string;
1283
- };
1284
- teacherAttachments: File[];
1285
- students: Array<{
1286
- id: string;
1287
- username: string;
1288
- attachments: File[];
1289
- annotations: File[];
1290
- }>;
1291
- }>
1292
- ```
1293
-
1294
- ---
1295
-
1296
- ## 🌐 Real-time Features
1297
-
1298
- ### Socket.IO Events
1299
- - **Connection**: `/socket.io/`
1300
- - **Events**: Class updates, new assignments, submissions, etc.
1301
-
1302
- ---
1303
-
1304
- ## 📊 Data Models
1305
-
1306
- ### File Object (Direct Upload)
1307
- ```typescript
1308
- {
1309
- name: string;
1310
- type: string;
1311
- size: number;
1312
- // Note: No data field - files are uploaded directly to GCS
1313
- }
1314
- ```
1315
-
1316
- ### Uploaded File Object (Database)
1317
- ```typescript
1318
- {
1319
- id: string;
1320
- name: string;
1321
- url: string; // GCS file path
1322
- type: string;
1323
- size: number;
1324
- uploadStatus: 'PENDING' | 'UPLOADING' | 'COMPLETED' | 'FAILED' | 'CANCELLED';
1325
- uploadProgress?: number;
1326
- createdAt: Date;
1327
- updatedAt: Date;
1328
- }
1329
- ```
1330
-
1331
- ### Assignment Object
1332
- ```typescript
1333
- {
1334
- id: string;
1335
- title: string;
1336
- instructions: string;
1337
- dueDate: Date;
1338
- maxGrade?: number;
1339
- graded: boolean;
1340
- weight: number;
1341
- type: AssignmentType;
1342
- inProgress: boolean;
1343
- template: boolean;
1344
- attachments: File[];
1345
- submissions: Submission[];
1346
- section?: Section;
1347
- teacher: User;
1348
- class: Class;
1349
- markScheme?: MarkScheme;
1350
- gradingBoundary?: GradingBoundary;
1351
- eventAttached?: Event;
1352
- }
1353
- ```
1354
-
1355
- ### User Roles
1356
- - `STUDENT`: Can view classes, submit assignments
1357
- - `TEACHER`: Can create/manage classes, grade assignments
1358
- - `ADMIN`: System administration
1359
- - `NONE`: No specific role
1360
-
1361
- ### Assignment Types
1362
- - `HOMEWORK`
1363
- - `QUIZ`
1364
- - `TEST`
1365
- - `PROJECT`
1366
- - `ESSAY`
1367
- - `DISCUSSION`
1368
- - `PRESENTATION`
1369
- - `LAB`
1370
- - `OTHER`
1371
-
1372
- ---
1373
-
1374
- ## 🔒 Access Control
1375
-
1376
- ### Public Endpoints
1377
- - All `auth.*` endpoints
1378
-
1379
- ### Protected Endpoints
1380
- - Require valid authentication token
1381
- - User must be logged in
1382
-
1383
- ### Class Member Endpoints
1384
- - Require `classId` parameter
1385
- - User must be student or teacher in the class
1386
-
1387
- ### Teacher Only Endpoints
1388
- - User must be teacher in the specified class
1389
- - Full management capabilities
1390
-
1391
- ---
1392
-
1393
- ## ⚠️ Error Handling
1394
-
1395
- ### Common Error Codes
1396
- - `UNAUTHORIZED`: Invalid or missing authentication
1397
- - `FORBIDDEN`: Insufficient permissions
1398
- - `NOT_FOUND`: Resource doesn't exist
1399
- - `BAD_REQUEST`: Invalid input data
1400
- - `CONFLICT`: Resource already exists
1401
- - `INTERNAL_SERVER_ERROR`: Server error
1402
-
1403
- ### Error Response Format
1404
- ```typescript
1405
- {
1406
- error: {
1407
- code: string;
1408
- message: string;
1409
- data?: {
1410
- zodError?: any;
1411
- prismaError?: any;
1412
- };
1413
- };
1414
- }
1415
- ```
1416
-
1417
- ---
1418
-
1419
- ## 🚀 Usage Examples
1420
-
1421
- ### TypeScript Client Setup
1422
- ```typescript
1423
- import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
1424
- import type { AppRouter } from '@studious-lms/server';
1425
-
1426
- const trpc = createTRPCProxyClient<AppRouter>({
1427
- links: [
1428
- httpBatchLink({
1429
- url: 'http://localhost:3001/trpc',
1430
- headers() {
1431
- return {
1432
- authorization: `Bearer ${getAuthToken()}`,
1433
- };
1434
- },
1435
- }),
1436
- ],
1437
- });
1438
- ```
1439
-
1440
- ### Example API Calls
1441
- ```typescript
1442
- // Login
1443
- const loginResult = await trpc.auth.login.mutate({
1444
- username: 'john_doe',
1445
- password: 'password123'
1446
- });
1447
-
1448
- // Get classes
1449
- const classes = await trpc.class.getAll.query();
1450
-
1451
- // Create assignment
1452
- const assignment = await trpc.assignment.create.mutate({
1453
- classId: 'class-id',
1454
- title: 'Math Homework',
1455
- instructions: 'Complete problems 1-10',
1456
- dueDate: '2024-01-15T23:59:59Z',
1457
- maxGrade: 100,
1458
- graded: true
1459
- });
1460
- ```
1461
-
1462
- ---
1463
-
1464
- ## 📝 Notes for Frontend Developers
1465
-
1466
- 1. **File Uploads**: Files are uploaded directly to Google Cloud Storage (GCS) using signed URLs. See the "File Upload Flow" section below for details.
1467
- 2. **Date Handling**: All dates are ISO 8601 strings
1468
- 3. **Authentication**: Store JWT token and include in all requests
1469
- 4. **Real-time Updates**: Use Socket.IO for live updates
1470
- 5. **Error Handling**: Always handle tRPC errors appropriately
1471
- 6. **Type Safety**: Use the exported TypeScript types for full type safety
1472
-
1473
- ### 📤 File Upload Flow (Direct Upload to GCS)
1474
-
1475
- **Important**: Files are NO LONGER sent as base64 encoded strings. Instead, they are uploaded directly to Google Cloud Storage for better performance and scalability.
1476
-
1477
- #### Step-by-Step Process:
1478
-
1479
- **1. Get Signed Upload URLs**
1480
- ```typescript
1481
- // For assignment attachments
1482
- const uploadResponse = await trpc.assignment.getAssignmentUploadUrls.mutate({
1483
- assignmentId: "assignment-id",
1484
- classId: "class-id",
1485
- files: [
1486
- { name: "homework.pdf", type: "application/pdf", size: 102400 },
1487
- { name: "notes.docx", type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", size: 51200 }
1488
- ]
1489
- });
1490
-
1491
- // For submission attachments
1492
- const uploadResponse = await trpc.assignment.getSubmissionUploadUrls.mutate({
1493
- assignmentId: "assignment-id",
1494
- classId: "class-id",
1495
- files: [
1496
- { name: "solution.pdf", type: "application/pdf", size: 204800 }
1497
- ]
1498
- });
1499
-
1500
- // For folder files
1501
- const uploadResponse = await trpc.folder.getUploadUrls.mutate({
1502
- folderId: "folder-id",
1503
- classId: "class-id",
1504
- files: [
1505
- { name: "lecture.pptx", type: "application/vnd.openxmlformats-officedocument.presentationml.presentation", size: 512000 }
1506
- ]
1507
- });
1508
- ```
1509
-
1510
- **2. Upload Files Directly to GCS**
1511
- ```typescript
1512
- for (const uploadFile of uploadResponse.uploadFiles) {
1513
- const file = files.find(f => f.name === uploadFile.name);
1514
-
1515
- // Optional: Track upload progress
1516
- const xhr = new XMLHttpRequest();
1517
- xhr.upload.addEventListener('progress', async (e) => {
1518
- if (e.lengthComputable) {
1519
- const progress = (e.loaded / e.total) * 100;
1520
- await trpc.assignment.updateUploadProgress.mutate({
1521
- fileId: uploadFile.id,
1522
- progress: Math.round(progress)
1523
- });
1524
- }
1525
- });
1526
-
1527
- // Upload to GCS using signed URL
1528
- await fetch(uploadFile.uploadUrl, {
1529
- method: 'PUT',
1530
- body: file,
1531
- headers: {
1532
- 'Content-Type': file.type
1533
- }
1534
- });
1535
- }
1536
- ```
1537
-
1538
- **3. Confirm Upload Success**
1539
- ```typescript
1540
- // Confirm each file upload
1541
- for (const uploadFile of uploadResponse.uploadFiles) {
1542
- await trpc.assignment.confirmAssignmentUpload.mutate({
1543
- fileId: uploadFile.id,
1544
- uploadSuccess: true // or false if upload failed
1545
- });
1546
- }
1547
- ```
1548
-
1549
- #### Benefits of Direct Upload:
1550
- - ✅ **33% smaller payload** (no base64 encoding overhead)
1551
- - ✅ **Faster uploads** (direct to GCS, no server processing)
1552
- - ✅ **Better scalability** (server doesn't handle file data)
1553
- - ✅ **Upload progress tracking** (real-time progress updates)
1554
- - ✅ **Better error handling** (retry failed uploads individually)
1555
-
1556
- #### Available Direct Upload Endpoints:
1557
-
1558
- **Assignment Attachments:**
1559
- - `assignment.getAssignmentUploadUrls` - Get signed URLs for assignment files
1560
- - `assignment.confirmAssignmentUpload` - Confirm file upload success
1561
-
1562
- **Submission Attachments:**
1563
- - `assignment.getSubmissionUploadUrls` - Get signed URLs for submission files
1564
- - `assignment.confirmSubmissionUpload` - Confirm file upload success
1565
-
1566
- **Folder Files:**
1567
- - `folder.getUploadUrls` - Get signed URLs for folder files
1568
- - `folder.confirmUpload` - Confirm file upload success
1569
-
1570
- **Progress Tracking:**
1571
- - `assignment.updateUploadProgress` - Update upload progress for any file
1572
-
1573
- ---
1574
-
1575
- *Generated on: September 14, 2025*
1576
- *Version: 1.2.0*
1577
- *Last Updated: October 2025*
1578
-
1579
- ## 📋 Changelog
1580
-
1581
- ### Version 1.2.0 (October 2025)
1582
- - 🚀 **BREAKING CHANGE**: Migrated from base64 file uploads to direct GCS uploads
1583
- - ✅ Added comprehensive direct upload documentation with step-by-step flow
1584
- - ✅ Updated File Object data models to reflect new upload system
1585
- - ✅ Added upload status tracking (`PENDING`, `UPLOADING`, `COMPLETED`, `FAILED`, `CANCELLED`)
1586
- - ✅ Added new direct upload endpoints for assignments, submissions, and folders
1587
- - ✅ Added upload progress tracking endpoint
1588
- - ✅ Updated user profile picture upload to support both custom uploads and DiceBear avatars
1589
- - 📝 Documented all benefits of direct upload approach (33% smaller payload, faster uploads, etc.)
1590
-
1591
- ### Version 1.1.0 (September 2025)
1592
- - ✅ Added complete Folder Management endpoints (`folder.*`)
1593
- - ✅ Added Section Management endpoints (`section.*`)
1594
- - ✅ Added Attendance Management endpoints (`attendance.*`)
1595
- - ✅ Added Agenda Management endpoints (`agenda.*`)
1596
- - ❌ Removed School Management section (not implemented)
1597
- - 🔧 Improved API coverage from ~70% to ~95%